cyclonedx_bom/
xml.rs

1use crate::errors::{XmlReadError, XmlWriteError};
2use std::io::{Read, Write};
3use xml::{
4    attribute::OwnedAttribute,
5    name::OwnedName,
6    namespace::{Namespace, NS_NO_PREFIX},
7    reader::{self},
8    writer::{self, EventWriter, XmlEvent},
9    EventReader,
10};
11
12pub(crate) trait ToXml {
13    fn write_xml_element<W: Write>(&self, writer: &mut EventWriter<W>)
14        -> Result<(), XmlWriteError>;
15
16    fn will_write(&self) -> bool {
17        true
18    }
19}
20
21impl<T: ToXml> ToXml for Option<T> {
22    fn write_xml_element<W: Write>(
23        &self,
24        writer: &mut EventWriter<W>,
25    ) -> Result<(), XmlWriteError> {
26        if let Some(item) = self {
27            item.write_xml_element(writer)?;
28        }
29
30        Ok(())
31    }
32
33    fn will_write(&self) -> bool {
34        self.is_some()
35    }
36}
37
38pub(crate) trait ToInnerXml {
39    fn write_xml_named_element<W: Write>(
40        &self,
41        writer: &mut EventWriter<W>,
42        tag: &str,
43    ) -> Result<(), XmlWriteError>;
44
45    fn will_write(&self) -> bool {
46        true
47    }
48}
49
50impl<T: ToInnerXml> ToInnerXml for Option<T> {
51    fn write_xml_named_element<W: Write>(
52        &self,
53        writer: &mut EventWriter<W>,
54        tag: &str,
55    ) -> Result<(), XmlWriteError> {
56        if let Some(item) = self {
57            item.write_xml_named_element(writer, tag)?;
58        }
59
60        Ok(())
61    }
62
63    fn will_write(&self) -> bool {
64        self.is_some()
65    }
66}
67
68/// Write a tag that is of the form `<tag>content</tag>`
69pub(crate) fn write_simple_tag<W: Write>(
70    writer: &mut EventWriter<W>,
71    tag: &str,
72    content: &str,
73) -> Result<(), XmlWriteError> {
74    writer
75        .write(writer::XmlEvent::start_element(tag))
76        .map_err(to_xml_write_error(tag))?;
77
78    writer
79        .write(writer::XmlEvent::characters(content))
80        .map_err(to_xml_write_error(tag))?;
81
82    writer
83        .write(writer::XmlEvent::end_element())
84        .map_err(to_xml_write_error(tag))?;
85    Ok(())
86}
87
88pub(crate) fn write_simple_option_tag<W: Write>(
89    writer: &mut EventWriter<W>,
90    tag: &str,
91    content: &Option<impl AsRef<str>>,
92) -> Result<(), XmlWriteError> {
93    if let Some(content) = content.as_ref() {
94        write_simple_tag(writer, tag, content.as_ref())?
95    }
96
97    Ok(())
98}
99
100/// Writes a simple start tag of the form `<tag>` without attributes.
101pub(crate) fn write_start_tag<W: Write>(
102    writer: &mut EventWriter<W>,
103    tag: &str,
104) -> Result<(), XmlWriteError> {
105    writer
106        .write(XmlEvent::start_element(tag))
107        .map_err(to_xml_write_error(tag))
108}
109
110/// Writes the closing tag of the form `</tag>`
111pub(crate) fn write_close_tag<W: Write>(
112    writer: &mut EventWriter<W>,
113    tag: &str,
114) -> Result<(), XmlWriteError> {
115    writer
116        .write(XmlEvent::end_element())
117        .map_err(to_xml_write_error(tag))
118}
119
120pub(crate) fn write_list_tag<W: Write>(
121    writer: &mut EventWriter<W>,
122    tag: &str,
123    list: &[impl ToXml],
124) -> Result<(), XmlWriteError> {
125    write_start_tag(writer, tag)?;
126
127    for item in list {
128        item.write_xml_element(writer)?;
129    }
130
131    write_close_tag(writer, tag)
132}
133
134pub(crate) fn write_list_string_tag<W: Write>(
135    writer: &mut EventWriter<W>,
136    tag: &str,
137    child_tag: &str,
138    list: &[impl AsRef<str>],
139) -> Result<(), XmlWriteError> {
140    write_start_tag(writer, tag)?;
141
142    for item in list {
143        write_simple_tag(writer, child_tag, item.as_ref())?;
144    }
145
146    write_close_tag(writer, tag)
147}
148
149pub(crate) fn to_xml_write_error(
150    element: impl AsRef<str>,
151) -> impl FnOnce(xml::writer::Error) -> XmlWriteError {
152    let element = element.as_ref().to_owned();
153    |error| XmlWriteError::XmlElementWriteError { error, element }
154}
155
156pub(crate) trait FromXmlDocument {
157    fn read_xml_document<R: Read>(event_reader: &mut EventReader<R>) -> Result<Self, XmlReadError>
158    where
159        Self: Sized;
160}
161
162pub(crate) trait FromXml {
163    fn read_xml_element<R: Read>(
164        event_reader: &mut EventReader<R>,
165        element_name: &OwnedName,
166        attributes: &[OwnedAttribute],
167    ) -> Result<Self, XmlReadError>
168    where
169        Self: Sized;
170}
171
172#[macro_export]
173macro_rules! get_elements_lax {
174    ($event_reader:ident, $element_name: ident, $($tag:pat => $name:ident: $type:ty,)+) => {
175            $(let mut $name: Option<$type> = None;)*
176
177            let mut got_end_tag = false;
178
179            while !got_end_tag {
180                let next_element = $event_reader.next().map_err($crate::xml::to_xml_read_error(&$element_name.local_name))?;
181                match next_element {
182                    xml::reader::XmlEvent::StartElement {
183                        name: ref elem_name,
184                        ref attributes,
185                        ..
186                    } => {
187                        match elem_name.local_name.as_str() {
188                            $($tag => {
189                                $name = Some(<$type as $crate::xml::FromXml>::read_xml_element(
190                                    $event_reader,
191                                    &elem_name,
192                                    &attributes,
193                                )?);
194                            },)*
195                            _ => $crate::xml::read_lax_validation_tag($event_reader, &elem_name)?,
196                        }
197                    }
198                    xml::reader::XmlEvent::EndElement { name } if &name == $element_name => {
199                        got_end_tag = true;
200                    }
201                    unexpected => return Err($crate::xml::unexpected_element_error($element_name, unexpected)),
202                }
203            }
204    };
205}
206
207#[macro_export]
208macro_rules! get_elements {
209    ($event_reader:ident, $element_name: ident, $($tag:pat => $name:ident: $type:ty,)+) => {
210        $(let mut $name: Option<$type> = None;)*
211
212        let mut got_end_tag = false;
213
214        while !got_end_tag {
215            let next_element = $event_reader.next().map_err($crate::xml::to_xml_read_error(&$element_name.local_name))?;
216            match next_element {
217                xml::reader::XmlEvent::StartElement {
218                    name: ref elem_name,
219                    ref attributes,
220                    ..
221                } => {
222                    match elem_name.local_name.as_str() {
223                        $($tag => {
224                            $name = Some(<$type as $crate::xml::FromXml>::read_xml_element(
225                                $event_reader,
226                                &elem_name,
227                                &attributes,
228                            )?);
229                        },)*
230                        unexpected => return Err($crate::xml::unexpected_element_error(unexpected.to_string(), next_element)),
231                    }
232                }
233                xml::reader::XmlEvent::EndElement { name } if &name == $element_name => {
234                    got_end_tag = true;
235                }
236                unexpected => return Err($crate::xml::unexpected_element_error($element_name, unexpected)),
237            }
238        }
239    };
240}
241
242/// Helper trait that represents the inner tag of a sequence of elements.
243pub(crate) trait VecElemTag {
244    const VALUE: &'static str;
245}
246
247#[macro_export]
248macro_rules! elem_tag {
249    ($name:ident = $value:literal) => {
250        struct $name {}
251
252        impl $crate::xml::VecElemTag for $name {
253            const VALUE: &'static str = $value;
254        }
255    };
256}
257
258/// Helper type to deserialize sequences of elements
259pub(crate) struct VecXmlReader<E: FromXml, T: VecElemTag> {
260    inner: Vec<E>,
261    _marker: std::marker::PhantomData<T>,
262}
263
264impl<E: FromXml, T: VecElemTag> From<VecXmlReader<E, T>> for Vec<E> {
265    fn from(reader: VecXmlReader<E, T>) -> Self {
266        reader.inner
267    }
268}
269
270impl<E: FromXml, T: VecElemTag> FromXml for VecXmlReader<E, T> {
271    fn read_xml_element<R: std::io::prelude::Read>(
272        event_reader: &mut xml::EventReader<R>,
273        element_name: &xml::name::OwnedName,
274        _attributes: &[xml::attribute::OwnedAttribute],
275    ) -> Result<Self, XmlReadError>
276    where
277        Self: Sized,
278    {
279        read_list_tag(event_reader, element_name, T::VALUE).map(|inner| Self {
280            inner,
281            _marker: Default::default(),
282        })
283    }
284}
285
286pub(crate) fn to_xml_read_error(
287    element_name: impl AsRef<str>,
288) -> impl FnOnce(xml::reader::Error) -> XmlReadError {
289    let element_name = element_name.as_ref().to_owned();
290    |error| XmlReadError::ElementReadError {
291        error,
292        element: element_name,
293    }
294}
295
296pub(crate) fn expected_namespace_or_error(
297    expected_version_number: impl AsRef<str>,
298    namespace: &Namespace,
299) -> Result<(), XmlReadError> {
300    let actual_namespace: Option<String> = namespace.get(NS_NO_PREFIX).map(String::from);
301    let expected_namespace = format!(
302        "http://cyclonedx.org/schema/bom/{}",
303        expected_version_number.as_ref()
304    );
305    if actual_namespace.as_ref() == Some(&expected_namespace) {
306        Ok(())
307    } else {
308        Err(XmlReadError::InvalidNamespaceError {
309            expected_namespace,
310            actual_namespace,
311        })
312    }
313}
314
315pub(crate) fn inner_text_or_error(
316    element_name: impl AsRef<str>,
317) -> impl FnOnce(xml::reader::XmlEvent) -> Result<String, XmlReadError> {
318    let element_name = element_name.as_ref().to_owned();
319    |event| match event {
320        reader::XmlEvent::Characters(s) | reader::XmlEvent::CData(s) => Ok(s),
321        unexpected => Err(unexpected_element_error(element_name, unexpected)),
322    }
323}
324
325pub(crate) fn inner_text_or_none(
326    element_name: impl AsRef<str>,
327) -> impl FnOnce(xml::reader::XmlEvent) -> Result<Option<String>, XmlReadError> {
328    let element_name = element_name.as_ref().to_owned();
329    |event| match event {
330        reader::XmlEvent::Characters(s) | reader::XmlEvent::CData(s) => Ok(Some(s)),
331        reader::XmlEvent::EndElement { name } if name.to_string() == element_name => Ok(None),
332        unexpected => Err(unexpected_element_error(element_name, unexpected)),
333    }
334}
335
336pub(crate) fn closing_tag_or_error(
337    element: &OwnedName,
338) -> impl FnOnce(xml::reader::XmlEvent) -> Result<(), XmlReadError> {
339    let element = element.clone();
340    move |event| match event {
341        reader::XmlEvent::EndElement { name } if name == element => Ok(()),
342        unexpected => Err(unexpected_element_error(&element, unexpected)),
343    }
344}
345
346pub(crate) fn attribute_or_error(
347    element_name: &OwnedName,
348    attributes: &[OwnedAttribute],
349    expected_attribute: &str,
350) -> Result<String, XmlReadError> {
351    attributes
352        .iter()
353        .filter(|attr| attr.name.local_name == expected_attribute)
354        .map(|attr| attr.value.to_owned())
355        .next()
356        .ok_or_else(|| XmlReadError::RequiredDataMissing {
357            required_field: expected_attribute.to_string(),
358            element: element_name.local_name.to_string(),
359        })
360}
361
362pub(crate) fn optional_attribute(
363    attributes: &[OwnedAttribute],
364    expected_attribute: &str,
365) -> Option<String> {
366    attributes
367        .iter()
368        .filter(|attr| attr.name.local_name == expected_attribute)
369        .map(|attr| attr.value.to_owned())
370        .next()
371}
372
373pub(crate) trait FromXmlType
374where
375    Self: Sized,
376{
377    fn xml_type_display() -> String;
378
379    fn from_xml_value(element: impl ToString, value: impl AsRef<str>)
380        -> Result<Self, XmlReadError>;
381}
382
383impl FromXmlType for bool {
384    fn xml_type_display() -> String {
385        "xs:boolean".to_string()
386    }
387
388    fn from_xml_value(
389        element: impl ToString,
390        value: impl AsRef<str>,
391    ) -> Result<Self, XmlReadError> {
392        let value = value.as_ref();
393        match value {
394            "true" | "1" => Ok(true),
395            "false" | "0" => Ok(false),
396            _ => Err(XmlReadError::InvalidParseError {
397                value: value.to_string(),
398                data_type: Self::xml_type_display(),
399                element: element.to_string(),
400            }),
401        }
402    }
403}
404
405impl FromXmlType for u32 {
406    fn xml_type_display() -> String {
407        "xs:integer".to_string()
408    }
409
410    fn from_xml_value(
411        element: impl ToString,
412        value: impl AsRef<str>,
413    ) -> Result<Self, XmlReadError> {
414        let value = value.as_ref();
415        let value: u32 = value.parse().map_err(|_| XmlReadError::InvalidParseError {
416            value: value.to_string(),
417            data_type: Self::xml_type_display(),
418            element: element.to_string(),
419        })?;
420
421        Ok(value)
422    }
423}
424
425impl FromXmlType for f32 {
426    fn xml_type_display() -> String {
427        "xs:decimal".to_string()
428    }
429
430    fn from_xml_value(
431        element: impl ToString,
432        value: impl AsRef<str>,
433    ) -> Result<Self, XmlReadError> {
434        let value = value.as_ref();
435        let value: f32 = value.parse().map_err(|_| XmlReadError::InvalidParseError {
436            value: value.to_string(),
437            data_type: Self::xml_type_display(),
438            element: element.to_string(),
439        })?;
440
441        Ok(value)
442    }
443}
444
445/// Reads a simple String tag.
446///
447/// ```xml
448/// <description>Content</description>
449/// ```
450/// &
451/// ```xml
452/// <description />
453/// ```
454///
455/// are valid XML tags. The first returns the string "Content", the latter is an empty string.
456pub(crate) fn read_simple_tag<R: Read>(
457    event_reader: &mut EventReader<R>,
458    element: &OwnedName,
459) -> Result<String, XmlReadError> {
460    let element_display = element.to_string();
461    let content = event_reader
462        .next()
463        .map_err(to_xml_read_error(&element_display))?;
464
465    let content = match content {
466        reader::XmlEvent::EndElement { .. } => String::new(),
467        reader::XmlEvent::Characters(content) | reader::XmlEvent::CData(content) => {
468            event_reader
469                .next()
470                .map_err(to_xml_read_error(&element_display))
471                .and_then(closing_tag_or_error(element))?;
472            content
473        }
474        unexpected => return Err(unexpected_element_error(element, unexpected)),
475    };
476
477    Ok(content)
478}
479
480pub(crate) fn read_optional_tag<R: Read>(
481    event_reader: &mut EventReader<R>,
482    element: &OwnedName,
483) -> Result<Option<String>, XmlReadError> {
484    let element_display = element.to_string();
485    let content = event_reader
486        .next()
487        .map_err(to_xml_read_error(&element_display))
488        .and_then(inner_text_or_none(&element_display))?;
489
490    // If XML tag has content, read next element
491    if content.is_some() {
492        event_reader
493            .next()
494            .map_err(to_xml_read_error(&element_display))
495            .and_then(closing_tag_or_error(element))?;
496    }
497
498    Ok(content)
499}
500
501pub(crate) fn read_u32_tag<R: Read>(
502    event_reader: &mut EventReader<R>,
503    element: &OwnedName,
504) -> Result<u32, XmlReadError> {
505    let element_display = element.to_string();
506    let content = event_reader
507        .next()
508        .map_err(to_xml_read_error(&element_display))
509        .and_then(inner_text_or_error(&element_display))?;
510
511    let number = match content.trim().parse::<u32>() {
512        Ok(n) => n,
513        Err(_) => {
514            return Err(XmlReadError::InvalidParseError {
515                value: content,
516                data_type: "u32".to_string(),
517                element: element_display,
518            })
519        }
520    };
521
522    event_reader
523        .next()
524        .map_err(to_xml_read_error(&element_display))
525        .and_then(closing_tag_or_error(element))?;
526
527    Ok(number)
528}
529
530pub(crate) fn read_f32_tag<R: Read>(
531    event_reader: &mut EventReader<R>,
532    element: &OwnedName,
533) -> Result<f32, XmlReadError> {
534    let element_display = element.to_string();
535    let content = event_reader
536        .next()
537        .map_err(to_xml_read_error(&element_display))
538        .and_then(inner_text_or_error(&element_display))?;
539
540    let number = match content.trim().parse::<f32>() {
541        Ok(n) => n,
542        Err(_) => {
543            return Err(XmlReadError::InvalidParseError {
544                value: content,
545                data_type: "f32".to_string(),
546                element: element_display,
547            })
548        }
549    };
550
551    event_reader
552        .next()
553        .map_err(to_xml_read_error(&element_display))
554        .and_then(closing_tag_or_error(element))?;
555
556    Ok(number)
557}
558
559pub(crate) fn read_boolean_tag<R: Read>(
560    event_reader: &mut EventReader<R>,
561    element: &OwnedName,
562) -> Result<bool, XmlReadError> {
563    read_simple_tag(event_reader, element)
564        .and_then(|modified| bool::from_xml_value(element, modified))
565}
566
567impl FromXml for String {
568    fn read_xml_element<R: Read>(
569        event_reader: &mut EventReader<R>,
570        element_name: &OwnedName,
571        _attributes: &[OwnedAttribute],
572    ) -> Result<Self, XmlReadError>
573    where
574        Self: Sized,
575    {
576        read_simple_tag(event_reader, element_name)
577    }
578}
579
580impl FromXml for u32 {
581    fn read_xml_element<R: Read>(
582        event_reader: &mut EventReader<R>,
583        element_name: &OwnedName,
584        _attributes: &[OwnedAttribute],
585    ) -> Result<Self, XmlReadError>
586    where
587        Self: Sized,
588    {
589        read_u32_tag(event_reader, element_name)
590    }
591}
592
593impl FromXml for f32 {
594    fn read_xml_element<R: Read>(
595        event_reader: &mut EventReader<R>,
596        element_name: &OwnedName,
597        _attributes: &[OwnedAttribute],
598    ) -> Result<Self, XmlReadError>
599    where
600        Self: Sized,
601    {
602        read_f32_tag(event_reader, element_name)
603    }
604}
605
606impl FromXml for bool {
607    fn read_xml_element<R: Read>(
608        event_reader: &mut EventReader<R>,
609        element_name: &OwnedName,
610        _attributes: &[OwnedAttribute],
611    ) -> Result<Self, XmlReadError>
612    where
613        Self: Sized,
614    {
615        read_boolean_tag(event_reader, element_name)
616    }
617}
618
619pub(crate) fn read_list_tag<R: Read, X: FromXml>(
620    event_reader: &mut EventReader<R>,
621    element_name: &OwnedName,
622    inner_element_tag: &str,
623) -> Result<Vec<X>, XmlReadError> {
624    let mut items = Vec::new();
625
626    let mut got_end_tag = false;
627    while !got_end_tag {
628        let next_element = event_reader
629            .next()
630            .map_err(to_xml_read_error(&element_name.local_name))?;
631        match next_element {
632            reader::XmlEvent::StartElement {
633                name, attributes, ..
634            } if name.local_name == inner_element_tag => {
635                items.push(X::read_xml_element(event_reader, &name, &attributes)?);
636            }
637            reader::XmlEvent::EndElement { name } if &name == element_name => {
638                got_end_tag = true;
639            }
640            unexpected => return Err(unexpected_element_error(element_name, unexpected)),
641        }
642    }
643
644    Ok(items)
645}
646
647pub(crate) fn read_lax_validation_tag<R: Read>(
648    event_reader: &mut EventReader<R>,
649    element: &OwnedName,
650) -> Result<(), XmlReadError> {
651    let mut got_end_tag = false;
652    while !got_end_tag {
653        let next_element = event_reader
654            .next()
655            .map_err(to_xml_read_error(&element.local_name))?;
656
657        match next_element {
658            reader::XmlEvent::StartElement { name, .. } => {
659                read_lax_validation_tag(event_reader, &name)?
660            }
661            reader::XmlEvent::EndElement { name } if &name == element => {
662                got_end_tag = true;
663            }
664            unexpected @ reader::XmlEvent::EndDocument => {
665                return Err(unexpected_element_error(element, unexpected))
666            }
667            unexpected @ reader::XmlEvent::EndElement { .. } => {
668                return Err(unexpected_element_error(element, unexpected))
669            }
670            _unknown => (),
671        }
672    }
673
674    Ok(())
675}
676
677pub(crate) fn read_lax_validation_list_tag<R: Read, X: FromXml>(
678    event_reader: &mut EventReader<R>,
679    element_name: &OwnedName,
680    inner_element_tag: &str,
681) -> Result<Vec<X>, XmlReadError> {
682    let mut items = Vec::new();
683
684    let mut got_end_tag = false;
685    while !got_end_tag {
686        let next_element = event_reader
687            .next()
688            .map_err(to_xml_read_error(&element_name.local_name))?;
689        match next_element {
690            reader::XmlEvent::StartElement {
691                name, attributes, ..
692            } if name.local_name == inner_element_tag => {
693                items.push(X::read_xml_element(event_reader, &name, &attributes)?);
694            }
695            reader::XmlEvent::StartElement { name, .. } => {
696                read_lax_validation_tag(event_reader, &name)?
697            }
698            reader::XmlEvent::EndElement { name } if &name == element_name => {
699                got_end_tag = true;
700            }
701            unexpected => return Err(unexpected_element_error(element_name, unexpected)),
702        }
703    }
704
705    Ok(items)
706}
707
708pub(crate) fn unexpected_element_error(
709    element: impl ToString,
710    unexpected: reader::XmlEvent,
711) -> XmlReadError {
712    XmlReadError::UnexpectedElementReadError {
713        error: format!("Got unexpected element {:?}", unexpected),
714        element: element.to_string(),
715    }
716}
717
718#[cfg(test)]
719pub(crate) mod test {
720    use xml::{EmitterConfig, ParserConfig};
721
722    use super::*;
723
724    fn emitter_config() -> EmitterConfig {
725        EmitterConfig::default().perform_indent(true)
726    }
727
728    pub(crate) fn write_element_to_string<X: ToXml>(element: X) -> String {
729        let mut output = Vec::new();
730        let mut event_writer = EventWriter::new_with_config(&mut output, emitter_config());
731        element
732            .write_xml_element(&mut event_writer)
733            .expect("Should have written the element");
734        String::from_utf8_lossy(&output).to_string()
735    }
736
737    pub(crate) fn write_named_element_to_string<X: ToInnerXml>(element: X, tag: &str) -> String {
738        let mut output = Vec::new();
739        let mut event_writer = EventWriter::new_with_config(&mut output, emitter_config());
740        element
741            .write_xml_named_element(&mut event_writer, tag)
742            .expect("Should have written the element");
743        String::from_utf8_lossy(&output).to_string()
744    }
745
746    fn parser_config() -> ParserConfig {
747        ParserConfig::default().trim_whitespace(true)
748    }
749
750    pub(crate) fn read_document_from_string<X: FromXmlDocument>(string: impl AsRef<str>) -> X {
751        let mut event_reader =
752            EventReader::new_with_config(string.as_ref().as_bytes(), parser_config());
753        let output: X = X::read_xml_document(&mut event_reader)
754            .expect("Failed to read the document from the string");
755
756        // According to the documentation, an event reader that returns an
757        // EndDocument event will continue to return that event for subsequent
758        // requests
759        let end_document = event_reader.next().expect("Expected to end the document");
760
761        match end_document {
762            reader::XmlEvent::EndDocument { .. } => (),
763            other => panic!("Expected to end a document, but got {:?}", other),
764        }
765
766        output
767    }
768
769    pub(crate) fn read_element_from_string<X: FromXml>(string: impl AsRef<str>) -> X {
770        let mut event_reader =
771            EventReader::new_with_config(string.as_ref().as_bytes(), parser_config());
772
773        let start_document = event_reader.next().expect("Expected to start the document");
774
775        match start_document {
776            reader::XmlEvent::StartDocument { .. } => (),
777            other => panic!("Expected to start a document, but got {:?}", other),
778        }
779
780        let initial_event = event_reader
781            .next()
782            .expect("Failed to read from the XML input");
783        let output = match initial_event {
784            reader::XmlEvent::StartElement {
785                name, attributes, ..
786            } => X::read_xml_element(&mut event_reader, &name, &attributes)
787                .expect("Failed to read the element from the string"),
788            other => panic!("Expected to start an element, but got {:?}", other),
789        };
790        let end_document = event_reader.next().expect("Expected to end the document");
791
792        match end_document {
793            reader::XmlEvent::EndDocument { .. } => (),
794            other => panic!("Expected to end a document, but got {:?}", other),
795        }
796
797        output
798    }
799
800    #[test]
801    fn it_should_handle_invalid_lax_xml() {
802        let input = r#"
803<recursiveTag>
804  <innerTag>
805    <recursiveTag>
806      Text
807    </recursiveTag>
808  </innerTag>
809"#;
810        let mut event_reader = EventReader::new_with_config(input.as_bytes(), parser_config());
811
812        let start_document = event_reader.next().expect("Expected to start the document");
813
814        match start_document {
815            reader::XmlEvent::StartDocument { .. } => (),
816            other => panic!("Expected to start a document, but got {:?}", other),
817        }
818
819        let start_lax_element = event_reader.next().expect("Expected to start the document");
820
821        match start_lax_element {
822            reader::XmlEvent::StartElement { name, .. } => {
823                read_lax_validation_tag(&mut event_reader, &name)
824                    .expect_err("Should have failed to parse invalid input");
825            }
826            other => panic!("Expected to start an element, but got {:?}", other),
827        }
828
829        // no end document, because it returns an error during the read_lax_validation_tag call
830    }
831}