1use alloc::borrow::{Cow, ToOwned};
10
11use rxml::{parser::EventMetrics, AttrMap, Event, Namespace, NcName, NcNameStr, XmlVersion};
12
13#[derive(Debug)]
23pub enum Item<'x> {
24 XmlDeclaration(XmlVersion),
26
27 ElementHeadStart(
29 Namespace,
31 Cow<'x, NcNameStr>,
33 ),
34
35 Attribute(
37 Namespace,
39 Cow<'x, NcNameStr>,
41 Cow<'x, str>,
43 ),
44
45 ElementHeadEnd,
47
48 Text(Cow<'x, str>),
50
51 ElementFoot,
61}
62
63impl Item<'_> {
64 pub fn into_owned(self) -> Item<'static> {
67 match self {
68 Self::XmlDeclaration(v) => Item::XmlDeclaration(v),
69 Self::ElementHeadStart(ns, name) => {
70 Item::ElementHeadStart(ns, Cow::Owned(name.into_owned()))
71 }
72 Self::Attribute(ns, name, value) => Item::Attribute(
73 ns,
74 Cow::Owned(name.into_owned()),
75 Cow::Owned(value.into_owned()),
76 ),
77 Self::ElementHeadEnd => Item::ElementHeadEnd,
78 Self::Text(value) => Item::Text(Cow::Owned(value.into_owned())),
79 Self::ElementFoot => Item::ElementFoot,
80 }
81 }
82
83 pub fn as_rxml_item(&self) -> rxml::Item<'_> {
85 match self {
86 Self::XmlDeclaration(ref v) => rxml::Item::XmlDeclaration(*v),
87 Self::ElementHeadStart(ref ns, ref name) => rxml::Item::ElementHeadStart(ns, name),
88 Self::Attribute(ref ns, ref name, ref value) => rxml::Item::Attribute(ns, name, value),
89 Self::ElementHeadEnd => rxml::Item::ElementHeadEnd,
90 Self::Text(ref value) => rxml::Item::Text(value),
91 Self::ElementFoot => rxml::Item::ElementFoot,
92 }
93 }
94}
95
96#[cfg(feature = "minidom")]
102pub(crate) struct EventToItem<I> {
103 inner: I,
104 attributes: Option<rxml::xml_map::IntoIter<alloc::string::String>>,
105}
106
107#[cfg(feature = "minidom")]
108impl<I> EventToItem<I> {
109 pub(crate) fn new(inner: I) -> Self {
110 Self {
111 inner,
112 attributes: None,
113 }
114 }
115
116 fn drain(&mut self) -> Option<Item<'static>> {
117 match self.attributes {
118 Some(ref mut attrs) => {
119 if let Some(((ns, name), value)) = attrs.next() {
120 Some(Item::Attribute(ns, Cow::Owned(name), Cow::Owned(value)))
121 } else {
122 self.attributes = None;
123 Some(Item::ElementHeadEnd)
124 }
125 }
126 None => None,
127 }
128 }
129
130 fn update(&mut self, ev: Event) -> Item<'static> {
131 assert!(self.attributes.is_none());
132 match ev {
133 Event::XmlDeclaration(_, v) => Item::XmlDeclaration(v),
134 Event::StartElement(_, (ns, name), attrs) => {
135 self.attributes = Some(attrs.into_iter());
136 Item::ElementHeadStart(ns, Cow::Owned(name))
137 }
138 Event::Text(_, value) => Item::Text(Cow::Owned(value)),
139 Event::EndElement(_) => Item::ElementFoot,
140 }
141 }
142}
143
144#[cfg(feature = "minidom")]
145impl<I: Iterator<Item = Result<Event, crate::error::Error>>> Iterator for EventToItem<I> {
146 type Item = Result<Item<'static>, crate::error::Error>;
147
148 fn next(&mut self) -> Option<Self::Item> {
149 if let Some(item) = self.drain() {
150 return Some(Ok(item));
151 }
152 let next = match self.inner.next() {
153 Some(Ok(v)) => v,
154 Some(Err(e)) => return Some(Err(e)),
155 None => return None,
156 };
157 Some(Ok(self.update(next)))
158 }
159
160 fn size_hint(&self) -> (usize, Option<usize>) {
161 (self.inner.size_hint().0, None)
164 }
165}
166
167pub(crate) struct ItemToEvent<I> {
173 inner: I,
174 event_buffer: Option<Event>,
175 elem_buffer: Option<(Namespace, NcName, AttrMap)>,
176}
177
178impl<'x, I: Iterator<Item = Result<Item<'x>, crate::error::Error>>> ItemToEvent<I> {
179 pub(crate) fn new(inner: I) -> Self {
181 Self {
182 inner,
183 event_buffer: None,
184 elem_buffer: None,
185 }
186 }
187}
188
189impl<I> ItemToEvent<I> {
190 fn update(&mut self, item: Item<'_>) -> Result<Option<Event>, crate::error::Error> {
191 assert!(self.event_buffer.is_none());
192 match item {
193 Item::XmlDeclaration(v) => {
194 assert!(self.elem_buffer.is_none());
195 Ok(Some(Event::XmlDeclaration(EventMetrics::zero(), v)))
196 }
197 Item::ElementHeadStart(ns, name) => {
198 if self.elem_buffer.is_some() {
199 panic!("got a second ElementHeadStart items without ElementHeadEnd inbetween: ns={:?} name={:?} (state={:?})", ns, name, self.elem_buffer);
203 }
204 self.elem_buffer = Some((ns.to_owned(), name.into_owned(), AttrMap::new()));
205 Ok(None)
206 }
207 Item::Attribute(ns, name, value) => {
208 let Some((_, _, attrs)) = self.elem_buffer.as_mut() else {
209 panic!(
213 "got a second Attribute item without ElementHeadStart: ns={:?}, name={:?}",
214 ns, name
215 );
216 };
217 attrs.insert(ns, name.into_owned(), value.into_owned());
218 Ok(None)
219 }
220 Item::ElementHeadEnd => {
221 let Some((ns, name, attrs)) = self.elem_buffer.take() else {
222 panic!(
226 "got ElementHeadEnd item without ElementHeadStart: {:?}",
227 item
228 );
229 };
230 Ok(Some(Event::StartElement(
231 EventMetrics::zero(),
232 (ns, name),
233 attrs,
234 )))
235 }
236 Item::Text(value) => {
237 if let Some(elem_buffer) = self.elem_buffer.as_ref() {
238 panic!("got Text after ElementHeadStart but before ElementHeadEnd: Text({:?}) (state = {:?})", value, elem_buffer);
242 }
243 Ok(Some(Event::Text(EventMetrics::zero(), value.into_owned())))
244 }
245 Item::ElementFoot => {
246 let end_ev = Event::EndElement(EventMetrics::zero());
247 let result = if let Some((ns, name, attrs)) = self.elem_buffer.take() {
248 self.event_buffer = Some(end_ev);
250 Event::StartElement(EventMetrics::zero(), (ns, name), attrs)
251 } else {
252 end_ev
253 };
254 Ok(Some(result))
255 }
256 }
257 }
258}
259
260impl<'x, I: Iterator<Item = Result<Item<'x>, crate::error::Error>>> Iterator for ItemToEvent<I> {
261 type Item = Result<Event, crate::error::Error>;
262
263 fn next(&mut self) -> Option<Self::Item> {
264 if let Some(event) = self.event_buffer.take() {
265 return Some(Ok(event));
266 }
267 loop {
268 let item = match self.inner.next() {
269 Some(Ok(v)) => v,
270 Some(Err(e)) => return Some(Err(e)),
271 None => return None,
272 };
273 if let Some(v) = self.update(item).transpose() {
274 return Some(v);
275 }
276 }
277 }
278
279 fn size_hint(&self) -> (usize, Option<usize>) {
280 (self.inner.size_hint().0, None)
283 }
284}
285
286#[cfg(all(test, feature = "minidom"))]
287mod tests_minidom {
288 use super::*;
289
290 use alloc::{string::ToString, vec, vec::Vec};
291
292 fn events_to_items<I: Iterator<Item = Event>>(events: I) -> Vec<Item<'static>> {
293 let iter = EventToItem {
294 inner: events.map(|ev| Ok(ev)),
295 attributes: None,
296 };
297 let mut result = Vec::new();
298 for item in iter {
299 let item = item.unwrap();
300 result.push(item);
301 }
302 result
303 }
304
305 #[test]
306 fn event_to_item_xml_declaration() {
307 let events = vec![Event::XmlDeclaration(
308 EventMetrics::zero(),
309 XmlVersion::V1_0,
310 )];
311 let items = events_to_items(events.into_iter());
312 assert_eq!(items.len(), 1);
313 match items[0] {
314 Item::XmlDeclaration(XmlVersion::V1_0) => (),
315 ref other => panic!("unexpected item in position 0: {:?}", other),
316 };
317 }
318
319 #[test]
320 fn event_to_item_empty_element() {
321 let events = vec![
322 Event::StartElement(
323 EventMetrics::zero(),
324 (Namespace::NONE, "elem".try_into().unwrap()),
325 AttrMap::new(),
326 ),
327 Event::EndElement(EventMetrics::zero()),
328 ];
329 let items = events_to_items(events.into_iter());
330 assert_eq!(items.len(), 3);
331 match items[0] {
332 Item::ElementHeadStart(ref ns, ref name) => {
333 assert_eq!(&**ns, Namespace::none());
334 assert_eq!(&**name, "elem");
335 }
336 ref other => panic!("unexpected item in position 0: {:?}", other),
337 };
338 match items[1] {
339 Item::ElementHeadEnd => (),
340 ref other => panic!("unexpected item in position 1: {:?}", other),
341 };
342 match items[2] {
343 Item::ElementFoot => (),
344 ref other => panic!("unexpected item in position 2: {:?}", other),
345 };
346 }
347
348 #[test]
349 fn event_to_item_element_with_attributes() {
350 let mut attrs = AttrMap::new();
351 attrs.insert(
352 Namespace::NONE,
353 "attr".try_into().unwrap(),
354 "value".to_string(),
355 );
356 let events = vec![
357 Event::StartElement(
358 EventMetrics::zero(),
359 (Namespace::NONE, "elem".try_into().unwrap()),
360 attrs,
361 ),
362 Event::EndElement(EventMetrics::zero()),
363 ];
364 let items = events_to_items(events.into_iter());
365 assert_eq!(items.len(), 4);
366 match items[0] {
367 Item::ElementHeadStart(ref ns, ref name) => {
368 assert_eq!(&**ns, Namespace::none());
369 assert_eq!(&**name, "elem");
370 }
371 ref other => panic!("unexpected item in position 0: {:?}", other),
372 };
373 match items[1] {
374 Item::Attribute(ref ns, ref name, ref value) => {
375 assert_eq!(&**ns, Namespace::none());
376 assert_eq!(&**name, "attr");
377 assert_eq!(&**value, "value");
378 }
379 ref other => panic!("unexpected item in position 1: {:?}", other),
380 };
381 match items[2] {
382 Item::ElementHeadEnd => (),
383 ref other => panic!("unexpected item in position 2: {:?}", other),
384 };
385 match items[3] {
386 Item::ElementFoot => (),
387 ref other => panic!("unexpected item in position 3: {:?}", other),
388 };
389 }
390
391 #[test]
392 fn event_to_item_element_with_text() {
393 let events = vec![
394 Event::StartElement(
395 EventMetrics::zero(),
396 (Namespace::NONE, "elem".try_into().unwrap()),
397 AttrMap::new(),
398 ),
399 Event::Text(EventMetrics::zero(), "Hello World!".to_owned()),
400 Event::EndElement(EventMetrics::zero()),
401 ];
402 let items = events_to_items(events.into_iter());
403 assert_eq!(items.len(), 4);
404 match items[0] {
405 Item::ElementHeadStart(ref ns, ref name) => {
406 assert_eq!(&**ns, Namespace::none());
407 assert_eq!(&**name, "elem");
408 }
409 ref other => panic!("unexpected item in position 0: {:?}", other),
410 };
411 match items[1] {
412 Item::ElementHeadEnd => (),
413 ref other => panic!("unexpected item in position 1: {:?}", other),
414 };
415 match items[2] {
416 Item::Text(ref value) => {
417 assert_eq!(value, "Hello World!");
418 }
419 ref other => panic!("unexpected item in position 2: {:?}", other),
420 };
421 match items[3] {
422 Item::ElementFoot => (),
423 ref other => panic!("unexpected item in position 3: {:?}", other),
424 };
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 use alloc::{vec, vec::Vec};
433
434 fn items_to_events<'x, I: IntoIterator<Item = Item<'x>>>(
435 items: I,
436 ) -> Result<Vec<Event>, crate::error::Error> {
437 let iter = ItemToEvent {
438 inner: items.into_iter().map(|x| Ok(x)),
439 event_buffer: None,
440 elem_buffer: None,
441 };
442 let mut result = Vec::new();
443 for ev in iter {
444 let ev = ev?;
445 result.push(ev);
446 }
447 Ok(result)
448 }
449
450 #[test]
451 fn item_to_event_xml_decl() {
452 let items = vec![Item::XmlDeclaration(XmlVersion::V1_0)];
453 let events = items_to_events(items).expect("item conversion");
454 assert_eq!(events.len(), 1);
455 match events[0] {
456 Event::XmlDeclaration(_, XmlVersion::V1_0) => (),
457 ref other => panic!("unexpected event in position 0: {:?}", other),
458 };
459 }
460
461 #[test]
462 fn item_to_event_simple_empty_element() {
463 let items = vec![
464 Item::ElementHeadStart(Namespace::NONE, Cow::Borrowed("elem".try_into().unwrap())),
465 Item::ElementHeadEnd,
466 Item::ElementFoot,
467 ];
468 let events = items_to_events(items).expect("item conversion");
469 assert_eq!(events.len(), 2);
470 match events[0] {
471 Event::StartElement(_, (ref ns, ref name), ref attrs) => {
472 assert_eq!(attrs.len(), 0);
473 assert_eq!(ns, Namespace::none());
474 assert_eq!(name, "elem");
475 }
476 ref other => panic!("unexpected event in position 0: {:?}", other),
477 };
478 match events[1] {
479 Event::EndElement(_) => (),
480 ref other => panic!("unexpected event in position 1: {:?}", other),
481 };
482 }
483
484 #[test]
485 fn item_to_event_short_empty_element() {
486 let items = vec![
487 Item::ElementHeadStart(Namespace::NONE, Cow::Borrowed("elem".try_into().unwrap())),
488 Item::ElementFoot,
489 ];
490 let events = items_to_events(items).expect("item conversion");
491 assert_eq!(events.len(), 2);
492 match events[0] {
493 Event::StartElement(_, (ref ns, ref name), ref attrs) => {
494 assert_eq!(attrs.len(), 0);
495 assert_eq!(ns, Namespace::none());
496 assert_eq!(name, "elem");
497 }
498 ref other => panic!("unexpected event in position 0: {:?}", other),
499 };
500 match events[1] {
501 Event::EndElement(_) => (),
502 ref other => panic!("unexpected event in position 1: {:?}", other),
503 };
504 }
505
506 #[test]
507 fn item_to_event_element_with_text_content() {
508 let items = vec![
509 Item::ElementHeadStart(Namespace::NONE, Cow::Borrowed("elem".try_into().unwrap())),
510 Item::ElementHeadEnd,
511 Item::Text(Cow::Borrowed("Hello World!")),
512 Item::ElementFoot,
513 ];
514 let events = items_to_events(items).expect("item conversion");
515 assert_eq!(events.len(), 3);
516 match events[0] {
517 Event::StartElement(_, (ref ns, ref name), ref attrs) => {
518 assert_eq!(attrs.len(), 0);
519 assert_eq!(ns, Namespace::none());
520 assert_eq!(name, "elem");
521 }
522 ref other => panic!("unexpected event in position 0: {:?}", other),
523 };
524 match events[1] {
525 Event::Text(_, ref value) => {
526 assert_eq!(value, "Hello World!");
527 }
528 ref other => panic!("unexpected event in position 1: {:?}", other),
529 };
530 match events[2] {
531 Event::EndElement(_) => (),
532 ref other => panic!("unexpected event in position 2: {:?}", other),
533 };
534 }
535
536 #[test]
537 fn item_to_event_element_with_attributes() {
538 let items = vec![
539 Item::ElementHeadStart(Namespace::NONE, Cow::Borrowed("elem".try_into().unwrap())),
540 Item::Attribute(
541 Namespace::NONE,
542 Cow::Borrowed("attr".try_into().unwrap()),
543 Cow::Borrowed("value"),
544 ),
545 Item::ElementHeadEnd,
546 Item::ElementFoot,
547 ];
548 let events = items_to_events(items).expect("item conversion");
549 assert_eq!(events.len(), 2);
550 match events[0] {
551 Event::StartElement(_, (ref ns, ref name), ref attrs) => {
552 assert_eq!(ns, Namespace::none());
553 assert_eq!(name, "elem");
554 assert_eq!(attrs.len(), 1);
555 assert_eq!(
556 attrs.get(Namespace::none(), "attr").map(|x| x.as_str()),
557 Some("value")
558 );
559 }
560 ref other => panic!("unexpected event in position 0: {:?}", other),
561 };
562 match events[1] {
563 Event::EndElement(_) => (),
564 ref other => panic!("unexpected event in position 2: {:?}", other),
565 };
566 }
567}