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 }
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 & B">A & 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}