• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Contains `XmlEvent` datatype, instances of which are emitted by the parser.
2 
3 use std::fmt;
4 use std::borrow::Cow;
5 
6 use name::OwnedName;
7 use attribute::OwnedAttribute;
8 use common::XmlVersion;
9 use 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)]
16 pub 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 
117 impl fmt::Debug for XmlEvent {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result118     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 
152 impl 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.
as_writer_event<'a>(&'a self) -> Option<::writer::events::XmlEvent<'a>>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 }
220