Skip to main content

docx_rs/reader/
xml_parser.rs

1use std::collections::VecDeque;
2use std::io::{BufReader, Read};
3
4use quick_xml::encoding::Decoder;
5use quick_xml::escape::unescape;
6use quick_xml::events::{BytesEnd, BytesRef, BytesStart, BytesText, Event};
7use quick_xml::Reader;
8use quick_xml::XmlVersion;
9
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct OwnedName {
12    pub local_name: String,
13    pub namespace: Option<String>,
14    pub prefix: Option<String>,
15}
16
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct OwnedAttribute {
19    pub name: OwnedName,
20    pub value: String,
21}
22
23#[derive(Clone, Debug, Default, PartialEq, Eq)]
24pub struct Namespace {
25    mappings: Vec<(String, String)>,
26}
27
28impl Namespace {
29    pub fn empty() -> Self {
30        Self {
31            mappings: Vec::new(),
32        }
33    }
34}
35
36impl IntoIterator for Namespace {
37    type Item = (String, String);
38    type IntoIter = std::vec::IntoIter<(String, String)>;
39
40    fn into_iter(self) -> Self::IntoIter {
41        self.mappings.into_iter()
42    }
43}
44
45#[derive(Clone, Debug, PartialEq)]
46pub enum XmlEvent {
47    StartElement {
48        name: OwnedName,
49        attributes: Vec<OwnedAttribute>,
50        namespace: Namespace,
51    },
52    EndElement {
53        name: OwnedName,
54    },
55    Characters(String),
56    Whitespace(String),
57    EndDocument,
58}
59
60pub struct EventReader<R: Read> {
61    reader: Reader<BufReader<R>>,
62    buf: Vec<u8>,
63    pending: VecDeque<XmlEvent>,
64    finished: bool,
65}
66
67impl<R: Read> EventReader<R> {
68    pub fn new(reader: R) -> Self {
69        let mut reader = Reader::from_reader(BufReader::new(reader));
70        {
71            let config = reader.config_mut();
72            config.trim_text(false);
73            config.check_end_names = true;
74            config.expand_empty_elements = false;
75        }
76        Self {
77            reader,
78            buf: Vec::new(),
79            pending: VecDeque::new(),
80            finished: false,
81        }
82    }
83
84    pub fn next_event(&mut self) -> Result<XmlEvent, quick_xml::Error> {
85        self.read_next()
86    }
87
88    fn read_next(&mut self) -> Result<XmlEvent, quick_xml::Error> {
89        if let Some(event) = self.pending.pop_front() {
90            return Ok(event);
91        }
92
93        loop {
94            self.buf.clear();
95            match self.reader.read_event_into(&mut self.buf)? {
96                Event::Start(element) => {
97                    let decoder = self.reader.decoder();
98                    let event = Self::build_start_event(element, decoder)?;
99                    return Ok(event);
100                }
101                Event::Empty(element) => {
102                    let decoder = self.reader.decoder();
103                    let event = Self::build_start_event(element, decoder)?;
104                    if let XmlEvent::StartElement { name, .. } = &event {
105                        self.pending
106                            .push_back(XmlEvent::EndElement { name: name.clone() });
107                    }
108                    return Ok(event);
109                }
110                Event::End(element) => {
111                    let name = build_name_from_end(&element)?;
112                    return Ok(XmlEvent::EndElement { name });
113                }
114                Event::Text(text) => {
115                    let text = decode_text(text)?;
116                    return self.read_text_event(text);
117                }
118                Event::GeneralRef(reference) => {
119                    let text = decode_reference(reference)?;
120                    return self.read_text_event(text);
121                }
122                Event::CData(text) => {
123                    let decoded = self.reader.decoder().decode(text.as_ref())?.into_owned();
124                    return Ok(XmlEvent::Characters(decoded));
125                }
126                Event::Eof => {
127                    self.finished = true;
128                    return Ok(XmlEvent::EndDocument);
129                }
130                Event::Decl(_) | Event::PI(_) | Event::Comment(_) | Event::DocType(_) => {
131                    // Skip non-structural events
132                }
133            }
134        }
135    }
136
137    fn read_text_event(&mut self, mut text: String) -> Result<XmlEvent, quick_xml::Error> {
138        loop {
139            self.buf.clear();
140            match self.reader.read_event_into(&mut self.buf)? {
141                Event::Text(next_text) => {
142                    text.push_str(&decode_text(next_text)?);
143                }
144                Event::GeneralRef(reference) => {
145                    text.push_str(&decode_reference(reference)?);
146                }
147                Event::Start(element) => {
148                    let decoder = self.reader.decoder();
149                    let event = Self::build_start_event(element, decoder)?;
150                    self.pending.push_back(event);
151                    break;
152                }
153                Event::Empty(element) => {
154                    let decoder = self.reader.decoder();
155                    let event = Self::build_start_event(element, decoder)?;
156                    let end_event = if let XmlEvent::StartElement { name, .. } = &event {
157                        Some(XmlEvent::EndElement { name: name.clone() })
158                    } else {
159                        None
160                    };
161                    self.pending.push_back(event);
162                    if let Some(end_event) = end_event {
163                        self.pending.push_back(end_event);
164                    }
165                    break;
166                }
167                Event::End(element) => {
168                    let name = build_name_from_end(&element)?;
169                    self.pending.push_back(XmlEvent::EndElement { name });
170                    break;
171                }
172                Event::CData(text) => {
173                    let decoded = self.reader.decoder().decode(text.as_ref())?.into_owned();
174                    self.pending.push_back(XmlEvent::Characters(decoded));
175                    break;
176                }
177                Event::Eof => {
178                    self.pending.push_back(XmlEvent::EndDocument);
179                    break;
180                }
181                Event::Decl(_) | Event::PI(_) | Event::Comment(_) | Event::DocType(_) => {
182                    break;
183                }
184            }
185        }
186
187        if text
188            .as_bytes()
189            .iter()
190            .all(|byte| matches!(byte, b' ' | b'\t' | b'\n' | b'\r'))
191        {
192            Ok(XmlEvent::Whitespace(text))
193        } else {
194            Ok(XmlEvent::Characters(text))
195        }
196    }
197
198    fn build_start_event(
199        element: BytesStart<'_>,
200        decoder: Decoder,
201    ) -> Result<XmlEvent, quick_xml::Error> {
202        let name = build_name_from_start(&element)?;
203        let attributes = build_attributes(&element, decoder)?;
204        Ok(XmlEvent::StartElement {
205            name,
206            attributes,
207            namespace: Namespace::empty(),
208        })
209    }
210}
211
212impl<R: Read> Iterator for EventReader<R> {
213    type Item = Result<XmlEvent, quick_xml::Error>;
214
215    fn next(&mut self) -> Option<Self::Item> {
216        if self.finished {
217            return None;
218        }
219        match self.read_next() {
220            Ok(XmlEvent::EndDocument) => {
221                self.finished = true;
222                Some(Ok(XmlEvent::EndDocument))
223            }
224            Ok(event) => Some(Ok(event)),
225            Err(e) => {
226                self.finished = true;
227                Some(Err(e))
228            }
229        }
230    }
231}
232
233fn build_name_from_start(element: &BytesStart<'_>) -> Result<OwnedName, quick_xml::Error> {
234    let name = element.name();
235    Ok(split_qname(name.as_ref()))
236}
237
238fn build_name_from_end(element: &BytesEnd<'_>) -> Result<OwnedName, quick_xml::Error> {
239    let name = element.name();
240    Ok(split_qname(name.as_ref()))
241}
242
243fn decode_text(text: BytesText<'_>) -> Result<String, quick_xml::Error> {
244    Ok(text.xml_content(XmlVersion::Implicit1_0)?.into_owned())
245}
246
247fn decode_reference(reference: BytesRef<'_>) -> Result<String, quick_xml::Error> {
248    if let Some(ch) = reference.resolve_char_ref()? {
249        return Ok(ch.to_string());
250    }
251    let reference = reference.xml_content(XmlVersion::Implicit1_0)?;
252    match reference.as_ref() {
253        "lt" => return Ok("<".to_owned()),
254        "gt" => return Ok(">".to_owned()),
255        "amp" => return Ok("&".to_owned()),
256        "apos" => return Ok("'".to_owned()),
257        "quot" => return Ok("\"".to_owned()),
258        _ => {}
259    }
260    let escaped = format!("&{reference};");
261    Ok(unescape(&escaped)?.into_owned())
262}
263
264fn split_qname(raw: &[u8]) -> OwnedName {
265    if let Some(idx) = raw.iter().position(|byte| *byte == b':') {
266        let prefix = String::from_utf8_lossy(&raw[..idx]).into_owned();
267        let local = String::from_utf8_lossy(&raw[idx + 1..]).into_owned();
268        OwnedName {
269            local_name: local,
270            namespace: None,
271            prefix: Some(prefix),
272        }
273    } else {
274        OwnedName {
275            local_name: String::from_utf8_lossy(raw).into_owned(),
276            namespace: None,
277            prefix: None,
278        }
279    }
280}
281
282fn build_attributes(
283    element: &BytesStart<'_>,
284    decoder: Decoder,
285) -> Result<Vec<OwnedAttribute>, quick_xml::Error> {
286    let mut raw_attributes = element.attributes();
287    let iter = raw_attributes.with_checks(false);
288    let mut attributes = Vec::with_capacity(iter.size_hint().0);
289    for attr_result in iter {
290        let attr = attr_result.map_err(quick_xml::Error::from)?;
291        let value = attr
292            .decoded_and_normalized_value(XmlVersion::Implicit1_0, decoder)?
293            .into_owned();
294        let name = split_qname(attr.key.as_ref());
295        attributes.push(OwnedAttribute { name, value });
296    }
297    Ok(attributes)
298}
299
300#[cfg(test)]
301mod tests {
302    use super::*;
303
304    #[test]
305    fn decodes_xml_entities_in_text_and_attributes() {
306        let xml = r#"<w:t w:val="A &amp; B">A &amp; B</w:t>"#;
307        let mut reader = EventReader::new(xml.as_bytes());
308
309        let start = reader.next_event().unwrap();
310        match start {
311            XmlEvent::StartElement {
312                name, attributes, ..
313            } => {
314                assert_eq!(name.prefix.as_deref(), Some("w"));
315                assert_eq!(name.local_name, "t");
316                assert_eq!(attributes[0].name.prefix.as_deref(), Some("w"));
317                assert_eq!(attributes[0].name.local_name, "val");
318                assert_eq!(attributes[0].value, "A & B");
319            }
320            event => panic!("expected start element, got {event:?}"),
321        }
322
323        assert_eq!(
324            reader.next_event().unwrap(),
325            XmlEvent::Characters("A & B".to_string())
326        );
327        assert!(matches!(
328            reader.next_event().unwrap(),
329            XmlEvent::EndElement { name } if name.local_name == "t"
330        ));
331        assert_eq!(reader.next_event().unwrap(), XmlEvent::EndDocument);
332    }
333}