opcua_xml/encoding/
reader.rs1use std::{
2 io::{BufReader, Read},
3 num::{ParseFloatError, ParseIntError},
4 str::FromStr,
5};
6
7use quick_xml::events::Event;
8use thiserror::Error;
9
10#[derive(Debug, Error)]
11pub enum XmlReadError {
13 #[error("{0}")]
14 Xml(#[from] quick_xml::Error),
16 #[error("{0}")]
17 Decode(#[from] quick_xml::encoding::EncodingError),
19 #[error("Unexpected EOF")]
20 UnexpectedEof,
22 #[error("Failed to parse integer: {0}")]
23 ParseInt(#[from] ParseIntError),
25 #[error("Failed to parse float: {0}")]
26 ParseFloat(#[from] ParseFloatError),
28 #[error("Failed to parse value: {0}")]
29 Parse(String),
31}
32
33pub struct XmlStreamReader<T> {
35 reader: quick_xml::Reader<BufReader<T>>,
36 buffer: Vec<u8>,
37}
38
39impl<T: Read> XmlStreamReader<T> {
40 pub fn new(reader: T) -> Self {
42 Self {
43 reader: quick_xml::Reader::from_reader(BufReader::new(reader)),
44 buffer: Vec::new(),
45 }
46 }
47
48 pub fn next_event(&mut self) -> Result<quick_xml::events::Event<'_>, XmlReadError> {
50 self.buffer.clear();
51 Ok(self.reader.read_event_into(&mut self.buffer)?)
52 }
53
54 pub fn skip_value(&mut self) -> Result<(), XmlReadError> {
60 let mut depth = 1u32;
61 loop {
62 match self.next_event()? {
63 Event::Start(_) => depth += 1,
64 Event::End(_) => {
65 depth -= 1;
66 if depth == 0 {
67 return Ok(());
68 }
69 }
70 Event::Eof => {
71 if depth == 1 {
72 return Ok(());
73 } else {
74 return Err(XmlReadError::UnexpectedEof);
75 }
76 }
77 _ => {}
78 }
79 }
80 }
81
82 pub fn consume_as_text(&mut self) -> Result<String, XmlReadError> {
87 let mut text: Option<String> = None;
88 let mut depth = 1u32;
89 loop {
90 match self.next_event()? {
91 Event::Start(_) => depth += 1,
92 Event::End(_) => {
93 depth -= 1;
94 if depth == 0 {
95 if let Some(mut text) = text {
96 let trimmed = text.trim_ascii_end();
97 text.truncate(trimmed.len());
98 return Ok(text);
99 } else {
100 return Ok(String::new());
101 }
102 }
103 }
104 Event::Text(mut e) => {
105 if depth != 1 {
106 continue;
107 }
108 if let Some(text) = text.as_mut() {
109 text.push_str(&e.decode()?);
110 } else if e.inplace_trim_start() {
111 continue;
112 } else {
113 text = Some(e.decode()?.into_owned());
114 }
115 }
116
117 Event::Eof => {
118 if depth == 1 {
119 if let Some(mut text) = text {
120 let trimmed = text.trim_ascii_end();
121 text.truncate(trimmed.len());
122 return Ok(text);
123 } else {
124 return Ok(String::new());
125 }
126 } else {
127 return Err(XmlReadError::UnexpectedEof);
128 }
129 }
130 _ => continue,
131 }
132 }
133 }
134
135 pub fn consume_raw(&mut self) -> Result<Vec<u8>, XmlReadError> {
137 let mut out = Vec::new();
138 let mut depth = 1u32;
139 loop {
144 let evt = self.next_event()?;
145 match evt {
146 Event::Start(s) => {
147 depth += 1;
148 out.push(b'<');
149 out.extend_from_slice(&s);
150 out.push(b'>');
151 }
152 Event::End(s) => {
153 depth -= 1;
154 if depth == 0 {
155 return Ok(out);
156 }
157 out.extend_from_slice(b"</");
158 out.extend_from_slice(&s);
159 out.push(b'>');
160 }
161 Event::CData(s) => {
162 out.extend_from_slice(b"<![CDATA[");
163 out.extend_from_slice(&s);
164 out.extend_from_slice(b"]]>");
165 }
166 Event::Comment(s) => {
167 out.extend_from_slice(b"<!--");
168 out.extend_from_slice(&s);
169 out.extend_from_slice(b"-->");
170 }
171 Event::Decl(s) => {
172 out.extend_from_slice(b"<?");
173 out.extend_from_slice(&s);
174 out.extend_from_slice(b"?>");
175 }
176 Event::DocType(s) => {
177 out.extend_from_slice(b"<!DOCTYPE");
178 out.extend_from_slice(&s);
179 out.push(b'>');
180 }
181 Event::Empty(s) => {
182 out.push(b'<');
183 out.extend_from_slice(&s);
184 out.extend_from_slice(b"/>");
185 }
186 Event::PI(s) => {
187 out.extend_from_slice(b"<?");
188 out.extend_from_slice(&s);
189 out.extend_from_slice(b"?>");
190 }
191 Event::Text(s) => {
192 out.extend_from_slice(&s);
193 }
194 Event::Eof => {
195 if depth == 1 {
196 return Ok(out);
197 } else {
198 return Err(XmlReadError::UnexpectedEof);
199 }
200 }
201 Event::GeneralRef(s) => {
202 out.push(b'&');
203 out.extend_from_slice(&s);
204 out.push(b';');
205 }
206 }
207 }
208 }
209
210 pub fn consume_content<R: FromStr>(&mut self) -> Result<R, XmlReadError>
212 where
213 XmlReadError: From<<R as FromStr>::Err>,
214 {
215 let text = self.consume_as_text()?;
216 Ok(text.parse()?)
217 }
218}
219
220#[cfg(test)]
221mod test {
222 use std::io::Cursor;
223
224 use quick_xml::events::Event;
225
226 #[test]
227 fn test_xml_text_comments() {
228 let xml = r#"
229 <Foo>
230 Ho
231 <Bar>
232 Hello
233 </Bar>
234 Hello <!-- Comment --> there
235 </Foo>
236 "#;
237 let mut cursor = Cursor::new(xml.as_bytes());
238 let mut reader = super::XmlStreamReader::new(&mut cursor);
239 assert!(matches!(reader.next_event().unwrap(), Event::Text(_)));
241 assert!(matches!(reader.next_event().unwrap(), Event::Start(_)));
242 assert!(matches!(reader.next_event().unwrap(), Event::Text(_)));
243 assert!(matches!(reader.next_event().unwrap(), Event::Start(_)));
244 assert!(matches!(reader.next_event().unwrap(), Event::Text(_)));
245 assert!(matches!(reader.next_event().unwrap(), Event::End(_)));
246 assert!(matches!(reader.next_event().unwrap(), Event::Text(_)));
247 assert!(matches!(reader.next_event().unwrap(), Event::Comment(_)));
248 assert!(matches!(reader.next_event().unwrap(), Event::Text(_)));
249 assert!(matches!(reader.next_event().unwrap(), Event::End(_)));
250 assert!(matches!(reader.next_event().unwrap(), Event::Text(_)));
251 assert!(matches!(reader.next_event().unwrap(), Event::Eof));
252 assert!(matches!(reader.next_event().unwrap(), Event::Eof));
253 }
254
255 #[test]
256 fn test_consume_as_text() {
257 let xml = r#"<Foo>
258 <Bar>
259 Hello
260 </Bar>
261 Hello <!-- Comment -->there
262 </Foo>"#;
263
264 let mut cursor = Cursor::new(xml.as_bytes());
265 let mut reader = super::XmlStreamReader::new(&mut cursor);
266
267 assert!(matches!(reader.next_event().unwrap(), Event::Start(_)));
268 assert_eq!(reader.consume_as_text().unwrap(), "Hello there");
269 }
270
271 #[test]
272 fn test_consume_content() {
273 let xml = r#"<Foo>
274 12345
275 </Foo>"#;
276 let mut cursor = Cursor::new(xml.as_bytes());
277 let mut reader = super::XmlStreamReader::new(&mut cursor);
278
279 assert!(matches!(reader.next_event().unwrap(), Event::Start(_)));
280 assert_eq!(reader.consume_content::<u32>().unwrap(), 12345);
281 }
282
283 #[test]
284 fn test_consume_raw() {
285 let xml = r#"<Foo>
286<Bar>
287 Hello <!-- Comment here -->
288 More text
289</Bar>
290<Bar attr = "foo" />
291<? Mystery PI ?>
292</Foo>"#;
293 let mut cursor = Cursor::new(xml.as_bytes());
294 let mut reader = super::XmlStreamReader::new(&mut cursor);
295 assert!(matches!(reader.next_event().unwrap(), Event::Start(_)));
296 let raw = reader.consume_raw().unwrap();
297 println!("{}", String::from_utf8_lossy(&raw));
298 assert_eq!(&xml.as_bytes()[5..(xml.len() - 6)], &*raw);
299 }
300}