xml/reader/
events.rs

1//! Contains `XmlEvent` datatype, instances of which are emitted by the parser.
2
3use std::fmt;
4use std::borrow::Cow;
5
6use name::OwnedName;
7use attribute::OwnedAttribute;
8use common::XmlVersion;
9use namespace::Namespace;
10
11/// An element of an XML input stream.
12///
13/// Items of this enum are emitted by `reader::EventReader`. They correspond to different
14/// elements of an XML document.
15#[derive(PartialEq, Clone)]
16pub enum XmlEvent {
17    /// Corresponds to XML document declaration.
18    ///
19    /// This event is always emitted before any other event. It is emitted
20    /// even if the actual declaration is not present in the document.
21    StartDocument {
22        /// XML version.
23        ///
24        /// If XML declaration is not present, defaults to `Version10`.
25        version: XmlVersion,
26
27        /// XML document encoding.
28        ///
29        /// If XML declaration is not present or does not contain `encoding` attribute,
30        /// defaults to `"UTF-8"`. This field is currently used for no other purpose than
31        /// informational.
32        encoding: String,
33
34        /// XML standalone declaration.
35        ///
36        /// If XML document is not present or does not contain `standalone` attribute,
37        /// defaults to `None`. This field is currently used for no other purpose than
38        /// informational.
39        standalone: Option<bool>
40    },
41
42    /// Denotes to the end of the document stream.
43    ///
44    /// This event is always emitted after any other event (except `Error`). After it
45    /// is emitted for the first time, it will always be emitted on next event pull attempts.
46    EndDocument,
47
48    /// Denotes an XML processing instruction.
49    ///
50    /// This event contains a processing instruction target (`name`) and opaque `data`. It
51    /// is up to the application to process them.
52    ProcessingInstruction {
53        /// Processing instruction target.
54        name: String,
55
56        /// Processing instruction content.
57        data: Option<String>
58    },
59
60    /// Denotes a beginning of an XML element.
61    ///
62    /// This event is emitted after parsing opening tags or after parsing bodiless tags. In the
63    /// latter case `EndElement` event immediately follows.
64    StartElement {
65        /// Qualified name of the element.
66        name: OwnedName,
67
68        /// A list of attributes associated with the element.
69        ///
70        /// Currently attributes are not checked for duplicates (TODO)
71        attributes: Vec<OwnedAttribute>,
72
73        /// Contents of the namespace mapping at this point of the document.
74        namespace: Namespace,
75    },
76
77    /// Denotes an end of an XML element.
78    ///
79    /// This event is emitted after parsing closing tags or after parsing bodiless tags. In the
80    /// latter case it is emitted immediately after corresponding `StartElement` event.
81    EndElement {
82        /// Qualified name of the element.
83        name: OwnedName
84    },
85
86    /// Denotes CDATA content.
87    ///
88    /// This event contains unparsed data. No unescaping will be performed.
89    ///
90    /// It is possible to configure a parser to emit `Characters` event instead of `CData`. See
91    /// `pull::ParserConfiguration` structure for more information.
92    CData(String),
93
94    /// Denotes a comment.
95    ///
96    /// It is possible to configure a parser to ignore comments, so this event will never be emitted.
97    /// See `pull::ParserConfiguration` structure for more information.
98    Comment(String),
99
100    /// Denotes character data outside of tags.
101    ///
102    /// Contents of this event will always be unescaped, so no entities like `&lt;` or `&amp;` or `&#123;`
103    /// will appear in it.
104    ///
105    /// It is possible to configure a parser to trim leading and trailing whitespace for this event.
106    /// See `pull::ParserConfiguration` structure for more information.
107    Characters(String),
108
109    /// Denotes a chunk of whitespace outside of tags.
110    ///
111    /// It is possible to configure a parser to emit `Characters` event instead of `Whitespace`.
112    /// See `pull::ParserConfiguration` structure for more information. When combined with whitespace
113    /// trimming, it will eliminate standalone whitespace from the event stream completely.
114    Whitespace(String)
115}
116
117impl fmt::Debug for XmlEvent {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        match *self {
120            XmlEvent::StartDocument { ref version, ref encoding, ref standalone } =>
121                write!(f, "StartDocument({}, {}, {:?})", version, *encoding, *standalone),
122            XmlEvent::EndDocument =>
123                write!(f, "EndDocument"),
124            XmlEvent::ProcessingInstruction { ref name, ref data } =>
125                write!(f, "ProcessingInstruction({}{})", *name, match *data {
126                    Some(ref data) => format!(", {}", data),
127                    None       => String::new()
128                }),
129            XmlEvent::StartElement { ref name, ref attributes, namespace: Namespace(ref namespace) } =>
130                write!(f, "StartElement({}, {:?}{})", name, namespace, if attributes.is_empty() {
131                    String::new()
132                } else {
133                    let attributes: Vec<String> = attributes.iter().map(
134                        |a| format!("{} -> {}", a.name, a.value)
135                    ).collect();
136                    format!(", [{}]", attributes.join(", "))
137                }),
138            XmlEvent::EndElement { ref name } =>
139                write!(f, "EndElement({})", name),
140            XmlEvent::Comment(ref data) =>
141                write!(f, "Comment({})", data),
142            XmlEvent::CData(ref data) =>
143                write!(f, "CData({})", data),
144            XmlEvent::Characters(ref data) =>
145                write!(f, "Characters({})", data),
146            XmlEvent::Whitespace(ref data) =>
147                write!(f, "Whitespace({})", data)
148        }
149    }
150}
151
152impl XmlEvent {
153    /// Obtains a writer event from this reader event.
154    ///
155    /// This method is useful for streaming processing of XML documents where the output
156    /// is also an XML document. With this method it is possible to process some events
157    /// while passing other events through to the writer unchanged:
158    ///
159    /// ```rust
160    /// use std::str;
161    ///
162    /// use xml::{EventReader, EventWriter};
163    /// use xml::reader::XmlEvent as ReaderEvent;
164    /// use xml::writer::XmlEvent as WriterEvent;
165    ///
166    /// let mut input: &[u8] = b"<hello>world</hello>";
167    /// let mut output: Vec<u8> = Vec::new();
168    ///
169    /// {
170    ///     let mut reader = EventReader::new(&mut input);
171    ///     let mut writer = EventWriter::new(&mut output);
172    ///
173    ///     for e in reader {
174    ///         match e.unwrap() {
175    ///             ReaderEvent::Characters(s) =>
176    ///                 writer.write(WriterEvent::characters(&s.to_uppercase())).unwrap(),
177    ///             e => if let Some(e) = e.as_writer_event() {
178    ///                 writer.write(e).unwrap()
179    ///             }
180    ///         }
181    ///     }
182    /// }
183    ///
184    /// assert_eq!(
185    ///     str::from_utf8(&output).unwrap(),
186    ///     r#"<?xml version="1.0" encoding="UTF-8"?><hello>WORLD</hello>"#
187    /// );
188    /// ```
189    ///
190    /// Note that this API may change or get additions in future to improve its ergonomics.
191    pub fn as_writer_event<'a>(&'a self) -> Option<::writer::events::XmlEvent<'a>> {
192        match *self {
193            XmlEvent::StartDocument { version, ref encoding, standalone } =>
194                Some(::writer::events::XmlEvent::StartDocument {
195                    version: version,
196                    encoding: Some(encoding),
197                    standalone: standalone
198                }),
199            XmlEvent::ProcessingInstruction { ref name, ref data } =>
200                Some(::writer::events::XmlEvent::ProcessingInstruction {
201                    name: name,
202                    data: data.as_ref().map(|s| &s[..])
203                }),
204            XmlEvent::StartElement { ref name, ref attributes, ref namespace } =>
205                Some(::writer::events::XmlEvent::StartElement {
206                    name: name.borrow(),
207                    attributes: attributes.iter().map(|a| a.borrow()).collect(),
208                    namespace: Cow::Borrowed(namespace)
209                }),
210            XmlEvent::EndElement { ref name } =>
211                Some(::writer::events::XmlEvent::EndElement { name: Some(name.borrow()) }),
212            XmlEvent::Comment(ref data) => Some(::writer::events::XmlEvent::Comment(data)),
213            XmlEvent::CData(ref data) => Some(::writer::events::XmlEvent::CData(data)),
214            XmlEvent::Characters(ref data) => Some(::writer::events::XmlEvent::Characters(data)),
215            XmlEvent::Whitespace(ref data) => Some(::writer::events::XmlEvent::Characters(data)),
216            _ => None
217        }
218    }
219}