Skip to main content

xml_disassembler/builders/
extract_root_attributes.rs

1//! Extract XML attributes from root element.
2
3use serde_json::{Map, Value};
4
5use crate::types::XmlElement;
6
7fn attr_value_to_string(v: &Value) -> String {
8    match v {
9        Value::String(s) => s.clone(),
10        Value::Number(n) => n.to_string(),
11        Value::Bool(b) => b.to_string(),
12        Value::Null => String::new(),
13        _ => serde_json::to_string(v).unwrap_or_default(),
14    }
15}
16
17/// Extracts XML attributes from a root element and returns them as a flat map.
18/// Handles @-prefixed keys (e.g. @xmlns, @version) and xmlns (default namespace).
19/// Converts values to strings for consistent XML output.
20pub fn extract_root_attributes(element: &XmlElement) -> XmlElement {
21    let mut attributes = Map::new();
22    if let Some(obj) = element.as_object() {
23        for (key, value) in obj {
24            let is_attr = key.starts_with('@') || key == "xmlns";
25            if is_attr {
26                let attr_key = if key == "xmlns" {
27                    "@xmlns".to_string()
28                } else {
29                    key.clone()
30                };
31                attributes.insert(attr_key, Value::String(attr_value_to_string(value)));
32            }
33        }
34    }
35    Value::Object(attributes)
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use serde_json::json;
42
43    #[test]
44    fn extracts_at_prefixed_attributes() {
45        let element = json!({
46            "@xmlns": "http://example.com",
47            "@version": "1.0",
48            "child": "ignored"
49        });
50        let attrs = extract_root_attributes(&element);
51        let obj = attrs.as_object().unwrap();
52        assert_eq!(
53            obj.get("@xmlns").and_then(|v| v.as_str()),
54            Some("http://example.com")
55        );
56        assert_eq!(obj.get("@version").and_then(|v| v.as_str()), Some("1.0"));
57        assert!(obj.get("child").is_none());
58    }
59
60    #[test]
61    fn returns_empty_for_non_object() {
62        let element = json!("string");
63        let attrs = extract_root_attributes(&element);
64        assert!(attrs.as_object().unwrap().is_empty());
65    }
66}