Skip to main content

docx_rs/xml_json/
mod.rs

1// Licensed under either of
2//
3// Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
4// MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
5// at your option.
6//
7// Contribution
8// Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
9// use serde::Serialize;
10use serde::Serialize;
11use std::fmt::{Display, Formatter, Write};
12use std::io::prelude::*;
13use std::io::Cursor;
14use std::str::FromStr;
15
16use crate::reader::{EventReader, Namespace, OwnedAttribute, OwnedName, XmlEvent};
17
18/// An XML Document
19#[derive(Debug, Clone)]
20pub struct XmlDocument {
21    /// Data contained within the parsed XML Document
22    pub data: Vec<XmlData>,
23}
24
25impl Display for XmlDocument {
26    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
27        for item in self.data.iter() {
28            item.fmt(f)?;
29        }
30        Ok(())
31    }
32}
33
34/// An XML Tag
35///
36/// For example:
37///
38/// ```XML
39/// <foo bar="baz">
40///     test text
41///     <sub></sub>
42/// </foo>
43/// ```
44#[derive(Debug, Clone, Serialize)]
45pub struct XmlData {
46    /// Name of the tag (i.e. "foo")
47    pub name: String,
48    /// Key-value pairs of the attributes (i.e. ("bar", "baz"))
49    pub attributes: Vec<(String, String)>,
50    /// Data (i.e. "test text")
51    pub data: Option<String>,
52    /// Sub elements (i.e. an XML element of "sub")
53    pub children: Vec<XmlData>,
54}
55
56impl XmlData {
57    /// Format the XML data as a string
58    fn format(self: &XmlData, f: &mut Formatter, _depth: usize) -> std::fmt::Result {
59        write!(f, "<{}", self.name)?;
60
61        for (key, val) in self.attributes.iter() {
62            write!(f, r#" {key}="{val}""#)?;
63        }
64
65        f.write_char('>')?;
66
67        if let Some(ref data) = self.data {
68            write!(f, "{data}")?
69        }
70
71        for child in self.children.iter() {
72            child.format(f, _depth + 1)?;
73        }
74
75        write!(f, "</{}>", self.name)
76    }
77}
78
79impl Display for XmlData {
80    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
81        self.format(f, 0)
82    }
83}
84
85/// Get the XML attributes as a string
86fn map_owned_attributes(attrs: Vec<OwnedAttribute>) -> Vec<(String, String)> {
87    attrs
88        .into_iter()
89        .map(|attr| {
90            let fmt_name = match attr.name.prefix {
91                Some(prefix) if !attr.name.local_name.is_empty() => {
92                    format!("{}:{}", prefix, attr.name.local_name)
93                }
94                Some(prefix) => prefix,
95                None => attr.name.local_name,
96            };
97            (fmt_name, attr.value)
98        })
99        .collect()
100}
101
102fn parse(
103    mut data: Vec<XmlEvent>,
104    current: Option<XmlData>,
105    mut current_vec: Vec<XmlData>,
106    trim: bool,
107    current_namespace: Namespace,
108) -> Result<(Vec<XmlData>, Vec<XmlEvent>), String> {
109    if let Some(elmt) = data.pop() {
110        match elmt {
111            XmlEvent::StartElement {
112                name,
113                attributes,
114                namespace,
115            } => {
116                let fmt_name = match name.prefix {
117                    Some(prefix) if !name.local_name.is_empty() => {
118                        format!("{}:{}", prefix, name.local_name)
119                    }
120                    Some(prefix) => prefix,
121                    None => name.local_name,
122                };
123
124                let attributes = if namespace == current_namespace {
125                    attributes
126                } else {
127                    let mut attributes = attributes;
128                    let n = namespace.clone();
129                    let ns = n
130                        .into_iter()
131                        .filter(|(_k, v)| {
132                            (!v.is_empty())
133                                && (v != "http://www.w3.org/2000/xmlns/")
134                                && (v != "http://www.w3.org/XML/1998/namespace")
135                        })
136                        .map(|(k, v)| OwnedAttribute {
137                            name: OwnedName {
138                                local_name: k.to_string(),
139                                namespace: if v.is_empty() {
140                                    None
141                                } else {
142                                    Some(v.to_string())
143                                },
144                                prefix: Some("xmlns".to_string()),
145                            },
146                            value: v.to_string(),
147                        });
148                    attributes.extend(ns);
149                    attributes
150                };
151
152                let inner = XmlData {
153                    name: fmt_name,
154                    attributes: map_owned_attributes(attributes),
155                    data: None,
156                    children: Vec::new(),
157                };
158
159                let (inner, rest) = parse(data, Some(inner), Vec::new(), trim, namespace.clone())?;
160
161                if let Some(mut crnt) = current {
162                    crnt.children.extend(inner);
163                    parse(rest, Some(crnt), current_vec, trim, namespace)
164                } else {
165                    current_vec.extend(inner);
166                    parse(rest, None, current_vec, trim, namespace)
167                }
168            }
169            XmlEvent::Characters(chr) => {
170                let chr = if trim { chr.trim().to_string() } else { chr };
171                if let Some(mut crnt) = current {
172                    crnt.data = Some(chr);
173                    parse(data, Some(crnt), current_vec, trim, current_namespace)
174                } else {
175                    Err("Invalid form of XML doc".to_string())
176                }
177            }
178            XmlEvent::EndElement { name } => {
179                let fmt_name = match &name.prefix {
180                    Some(prefix) if !name.local_name.is_empty() => {
181                        format!("{}:{}", prefix, name.local_name)
182                    }
183                    Some(prefix) => prefix.clone(),
184                    None => name.local_name.clone(),
185                };
186                if let Some(crnt) = current {
187                    if crnt.name == fmt_name {
188                        current_vec.push(crnt);
189                        Ok((current_vec, data))
190                    } else {
191                        Err(format!(
192                            "Invalid end tag: expected {}, got {}",
193                            crnt.name, name.local_name
194                        ))
195                    }
196                } else {
197                    Err(format!("Invalid end tag: {}", name.local_name))
198                }
199            }
200            _ => parse(data, current, current_vec, trim, current_namespace),
201        }
202    } else if let Some(_current) = current {
203        Err("Invalid end tag".to_string())
204    } else {
205        Ok((current_vec, Vec::new()))
206    }
207}
208
209impl XmlDocument {
210    pub fn from_reader<R>(source: R, trim: bool) -> Result<Self, ParseXmlError>
211    where
212        R: Read,
213    {
214        let parser = EventReader::new(source);
215        let mut events: Vec<XmlEvent> = parser.into_iter().map(|x| x.unwrap()).collect();
216        events.reverse();
217
218        parse(events, None, Vec::new(), trim, Namespace::empty())
219            .map(|(data, _)| XmlDocument { data })
220            .map_err(ParseXmlError)
221    }
222}
223
224/// Error when parsing XML
225#[derive(Debug, Clone, PartialEq)]
226pub struct ParseXmlError(String);
227
228impl Display for ParseXmlError {
229    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
230        write!(f, "Coult not parse string to XML: {}", self.0)
231    }
232}
233
234// Generate an XML document from a string
235impl FromStr for XmlDocument {
236    type Err = ParseXmlError;
237
238    fn from_str(s: &str) -> Result<XmlDocument, ParseXmlError> {
239        XmlDocument::from_reader(Cursor::new(s.to_string().into_bytes()), true)
240    }
241}