1 //! Contains `XmlEvent` datatype, instances of which are consumed by the writer. 2 3 use std::borrow::Cow; 4 5 use crate::attribute::Attribute; 6 use crate::common::XmlVersion; 7 use crate::name::Name; 8 use crate::namespace::{Namespace, NS_NO_PREFIX}; 9 10 /// A part of an XML output stream. 11 /// 12 /// Objects of this enum are consumed by `EventWriter`. They correspond to different parts of 13 /// an XML document. 14 #[derive(Debug, Clone)] 15 pub enum XmlEvent<'a> { 16 /// Corresponds to XML document declaration. 17 /// 18 /// This event should always be written before any other event. If it is not written 19 /// at all, a default XML declaration will be outputted if the corresponding option 20 /// is set in the configuration. Otherwise an error will be returned. 21 StartDocument { 22 /// XML version. 23 /// 24 /// Defaults to `XmlVersion::Version10`. 25 version: XmlVersion, 26 27 /// XML document encoding. 28 /// 29 /// Defaults to `Some("UTF-8")`. 30 encoding: Option<&'a str>, 31 32 /// XML standalone declaration. 33 /// 34 /// Defaults to `None`. 35 standalone: Option<bool>, 36 }, 37 38 /// Denotes an XML processing instruction. 39 ProcessingInstruction { 40 /// Processing instruction target. 41 name: &'a str, 42 43 /// Processing instruction content. 44 data: Option<&'a str>, 45 }, 46 47 /// Denotes a beginning of an XML element. 48 StartElement { 49 /// Qualified name of the element. 50 name: Name<'a>, 51 52 /// A list of attributes associated with the element. 53 /// 54 /// Currently attributes are not checked for duplicates (TODO). Attribute values 55 /// will be escaped, and all characters invalid for attribute values like `"` or `<` 56 /// will be changed into character entities. 57 attributes: Cow<'a, [Attribute<'a>]>, 58 59 /// Contents of the namespace mapping at this point of the document. 60 /// 61 /// This mapping will be inspected for "new" entries, and if at this point of the document 62 /// a particular pair of prefix and namespace URI is already defined, no namespace 63 /// attributes will be emitted. 64 namespace: Cow<'a, Namespace>, 65 }, 66 67 /// Denotes an end of an XML element. 68 EndElement { 69 /// Optional qualified name of the element. 70 /// 71 /// If `None`, then it is assumed that the element name should be the last valid one. 72 /// If `Some` and element names tracking is enabled, then the writer will check it for 73 /// correctness. 74 name: Option<Name<'a>>, 75 }, 76 77 /// Denotes CDATA content. 78 /// 79 /// This event contains unparsed data, and no escaping will be performed when writing it 80 /// to the output stream. 81 CData(&'a str), 82 83 /// Denotes a comment. 84 /// 85 /// The string will be checked for invalid sequences and error will be returned by the 86 /// write operation 87 Comment(&'a str), 88 89 /// Denotes character data outside of tags. 90 /// 91 /// Contents of this event will be escaped if `perform_escaping` option is enabled, 92 /// that is, every character invalid for PCDATA will appear as a character entity. 93 Characters(&'a str), 94 } 95 96 impl<'a> XmlEvent<'a> { 97 /// Returns an writer event for a processing instruction. 98 #[inline] 99 #[must_use] processing_instruction(name: &'a str, data: Option<&'a str>) -> XmlEvent<'a>100 pub fn processing_instruction(name: &'a str, data: Option<&'a str>) -> XmlEvent<'a> { 101 XmlEvent::ProcessingInstruction { name, data } 102 } 103 104 /// Returns a builder for a starting element. 105 /// 106 /// This builder can then be used to tweak attributes and namespace starting at 107 /// this element. 108 #[inline] start_element<S>(name: S) -> StartElementBuilder<'a> where S: Into<Name<'a>>109 pub fn start_element<S>(name: S) -> StartElementBuilder<'a> where S: Into<Name<'a>> { 110 StartElementBuilder { 111 name: name.into(), 112 attributes: Vec::new(), 113 namespace: Namespace::empty(), 114 } 115 } 116 117 /// Returns a builder for an closing element. 118 /// 119 /// This method, unline `start_element()`, does not accept a name because by default 120 /// the writer is able to determine it automatically. However, when this functionality 121 /// is disabled, it is possible to specify the name with `name()` method on the builder. 122 #[inline] 123 #[must_use] end_element() -> EndElementBuilder<'a>124 pub fn end_element() -> EndElementBuilder<'a> { 125 EndElementBuilder { name: None } 126 } 127 128 /// Returns a CDATA event. 129 /// 130 /// Naturally, the provided string won't be escaped, except for closing CDATA token `]]>` 131 /// (depending on the configuration). 132 #[inline] 133 #[must_use] cdata(data: &'a str) -> XmlEvent<'a>134 pub fn cdata(data: &'a str) -> XmlEvent<'a> { 135 XmlEvent::CData(data) 136 } 137 138 /// Returns a regular characters (PCDATA) event. 139 /// 140 /// All offending symbols, in particular, `&` and `<`, will be escaped by the writer. 141 #[inline] 142 #[must_use] characters(data: &'a str) -> XmlEvent<'a>143 pub fn characters(data: &'a str) -> XmlEvent<'a> { 144 XmlEvent::Characters(data) 145 } 146 147 /// Returns a comment event. 148 #[inline] 149 #[must_use] comment(data: &'a str) -> XmlEvent<'a>150 pub fn comment(data: &'a str) -> XmlEvent<'a> { 151 XmlEvent::Comment(data) 152 } 153 } 154 155 impl<'a> From<&'a str> for XmlEvent<'a> { 156 #[inline] from(s: &'a str) -> XmlEvent<'a>157 fn from(s: &'a str) -> XmlEvent<'a> { 158 XmlEvent::Characters(s) 159 } 160 } 161 162 pub struct EndElementBuilder<'a> { 163 name: Option<Name<'a>>, 164 } 165 166 /// A builder for a closing element event. 167 impl<'a> EndElementBuilder<'a> { 168 /// Sets the name of this closing element. 169 /// 170 /// Usually the writer is able to determine closing element names automatically. If 171 /// this functionality is enabled (by default it is), then this name is checked for correctness. 172 /// It is possible, however, to disable such behavior; then the user must ensure that 173 /// closing element name is correct manually. 174 #[inline] name<N>(mut self, name: N) -> EndElementBuilder<'a> where N: Into<Name<'a>>175 pub fn name<N>(mut self, name: N) -> EndElementBuilder<'a> where N: Into<Name<'a>> { 176 self.name = Some(name.into()); 177 self 178 } 179 } 180 181 impl<'a> From<EndElementBuilder<'a>> for XmlEvent<'a> { from(b: EndElementBuilder<'a>) -> XmlEvent<'a>182 fn from(b: EndElementBuilder<'a>) -> XmlEvent<'a> { 183 XmlEvent::EndElement { name: b.name } 184 } 185 } 186 187 /// A builder for a starting element event. 188 pub struct StartElementBuilder<'a> { 189 name: Name<'a>, 190 attributes: Vec<Attribute<'a>>, 191 namespace: Namespace, 192 } 193 194 impl<'a> StartElementBuilder<'a> { 195 /// Sets an attribute value of this element to the given string. 196 /// 197 /// This method can be used to add attributes to the starting element. Name is a qualified 198 /// name; its namespace is ignored, but its prefix is checked for correctness, that is, 199 /// it is checked that the prefix is bound to some namespace in the current context. 200 /// 201 /// Currently attributes are not checked for duplicates. Note that duplicate attributes 202 /// are a violation of XML document well-formedness. 203 /// 204 /// The writer checks that you don't specify reserved prefix names, for example `xmlns`. 205 #[inline] attr<N>(mut self, name: N, value: &'a str) -> StartElementBuilder<'a> where N: Into<Name<'a>>206 pub fn attr<N>(mut self, name: N, value: &'a str) -> StartElementBuilder<'a> 207 where N: Into<Name<'a>> 208 { 209 self.attributes.push(Attribute::new(name.into(), value)); 210 self 211 } 212 213 /// Adds a namespace to the current namespace context. 214 /// 215 /// If no namespace URI was bound to the provided prefix at this point of the document, 216 /// then the mapping from the prefix to the provided namespace URI will be written as 217 /// a part of this element attribute set. 218 /// 219 /// If the same namespace URI was bound to the provided prefix at this point of the document, 220 /// then no namespace attributes will be emitted. 221 /// 222 /// If some other namespace URI was bound to the provided prefix at this point of the document, 223 /// then another binding will be added as a part of this element attribute set, shadowing 224 /// the outer binding. 225 #[inline] 226 #[must_use] ns<S1, S2>(mut self, prefix: S1, uri: S2) -> StartElementBuilder<'a> where S1: Into<String>, S2: Into<String>227 pub fn ns<S1, S2>(mut self, prefix: S1, uri: S2) -> StartElementBuilder<'a> 228 where S1: Into<String>, S2: Into<String> 229 { 230 self.namespace.put(prefix, uri); 231 self 232 } 233 234 /// Adds a default namespace mapping to the current namespace context. 235 /// 236 /// Same rules as for `ns()` are also valid for the default namespace mapping. 237 #[inline] 238 #[must_use] default_ns<S>(mut self, uri: S) -> StartElementBuilder<'a> where S: Into<String>239 pub fn default_ns<S>(mut self, uri: S) -> StartElementBuilder<'a> 240 where S: Into<String> 241 { 242 self.namespace.put(NS_NO_PREFIX, uri); 243 self 244 } 245 } 246 247 impl<'a> From<StartElementBuilder<'a>> for XmlEvent<'a> { 248 #[inline] from(b: StartElementBuilder<'a>) -> XmlEvent<'a>249 fn from(b: StartElementBuilder<'a>) -> XmlEvent<'a> { 250 XmlEvent::StartElement { 251 name: b.name, 252 attributes: Cow::Owned(b.attributes), 253 namespace: Cow::Owned(b.namespace), 254 } 255 } 256 } 257