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 `<` 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 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