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 `<` or `&` or `{`
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}