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