diff options
Diffstat (limited to 'third_party/rust/xml-rs/src/writer/events.rs')
-rw-r--r-- | third_party/rust/xml-rs/src/writer/events.rs | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/third_party/rust/xml-rs/src/writer/events.rs b/third_party/rust/xml-rs/src/writer/events.rs new file mode 100644 index 0000000000..1f7040f66a --- /dev/null +++ b/third_party/rust/xml-rs/src/writer/events.rs @@ -0,0 +1,241 @@ +//! Contains `XmlEvent` datatype, instances of which are consumed by the writer. + +use std::borrow::Cow; + +use name::Name; +use attribute::Attribute; +use common::XmlVersion; +use namespace::{Namespace, NS_NO_PREFIX}; + +/// A part of an XML output stream. +/// +/// Objects of this enum are consumed by `EventWriter`. They correspond to different parts of +/// an XML document. +#[derive(Debug)] +pub enum XmlEvent<'a> { + /// Corresponds to XML document declaration. + /// + /// This event should always be written before any other event. If it is not written + /// at all, a default XML declaration will be outputted if the corresponding option + /// is set in the configuration. Otherwise an error will be returned. + StartDocument { + /// XML version. + /// + /// Defaults to `XmlVersion::Version10`. + version: XmlVersion, + + /// XML document encoding. + /// + /// Defaults to `Some("UTF-8")`. + encoding: Option<&'a str>, + + /// XML standalone declaration. + /// + /// Defaults to `None`. + standalone: Option<bool> + }, + + /// Denotes an XML processing instruction. + ProcessingInstruction { + /// Processing instruction target. + name: &'a str, + + /// Processing instruction content. + data: Option<&'a str> + }, + + /// Denotes a beginning of an XML element. + StartElement { + /// Qualified name of the element. + name: Name<'a>, + + /// A list of attributes associated with the element. + /// + /// Currently attributes are not checked for duplicates (TODO). Attribute values + /// will be escaped, and all characters invalid for attribute values like `"` or `<` + /// will be changed into character entities. + attributes: Cow<'a, [Attribute<'a>]>, + + /// Contents of the namespace mapping at this point of the document. + /// + /// This mapping will be inspected for "new" entries, and if at this point of the document + /// a particular pair of prefix and namespace URI is already defined, no namespace + /// attributes will be emitted. + namespace: Cow<'a, Namespace>, + }, + + /// Denotes an end of an XML element. + EndElement { + /// Optional qualified name of the element. + /// + /// If `None`, then it is assumed that the element name should be the last valid one. + /// If `Some` and element names tracking is enabled, then the writer will check it for + /// correctness. + name: Option<Name<'a>> + }, + + /// Denotes CDATA content. + /// + /// This event contains unparsed data, and no escaping will be performed when writing it + /// to the output stream. + CData(&'a str), + + /// Denotes a comment. + /// + /// The string will be checked for invalid sequences and error will be returned by the + /// write operation + Comment(&'a str), + + /// Denotes character data outside of tags. + /// + /// Contents of this event will be escaped if `perform_escaping` option is enabled, + /// that is, every character invalid for PCDATA will appear as a character entity. + Characters(&'a str) +} + +impl<'a> XmlEvent<'a> { + /// Returns an writer event for a processing instruction. + #[inline] + pub fn processing_instruction(name: &'a str, data: Option<&'a str>) -> XmlEvent<'a> { + XmlEvent::ProcessingInstruction { name: name, data: data } + } + + /// Returns a builder for a starting element. + /// + /// This builder can then be used to tweak attributes and namespace starting at + /// this element. + #[inline] + pub fn start_element<S>(name: S) -> StartElementBuilder<'a> where S: Into<Name<'a>> { + StartElementBuilder { + name: name.into(), + attributes: Vec::new(), + namespace: Namespace::empty().into() + } + } + + /// Returns a builder for an closing element. + /// + /// This method, unline `start_element()`, does not accept a name because by default + /// the writer is able to determine it automatically. However, when this functionality + /// is disabled, it is possible to specify the name with `name()` method on the builder. + #[inline] + pub fn end_element() -> EndElementBuilder<'a> { + EndElementBuilder { name: None } + } + + /// Returns a CDATA event. + /// + /// Naturally, the provided string won't be escaped, except for closing CDATA token `]]>` + /// (depending on the configuration). + #[inline] + pub fn cdata(data: &'a str) -> XmlEvent<'a> { XmlEvent::CData(data) } + + /// Returns a regular characters (PCDATA) event. + /// + /// All offending symbols, in particular, `&` and `<`, will be escaped by the writer. + #[inline] + pub fn characters(data: &'a str) -> XmlEvent<'a> { XmlEvent::Characters(data) } + + /// Returns a comment event. + #[inline] + pub fn comment(data: &'a str) -> XmlEvent<'a> { XmlEvent::Comment(data) } +} + +impl<'a> From<&'a str> for XmlEvent<'a> { + #[inline] + fn from(s: &'a str) -> XmlEvent<'a> { XmlEvent::Characters(s) } +} + +pub struct EndElementBuilder<'a> { + name: Option<Name<'a>> +} + +/// A builder for a closing element event. +impl<'a> EndElementBuilder<'a> { + /// Sets the name of this closing element. + /// + /// Usually the writer is able to determine closing element names automatically. If + /// this functionality is enabled (by default it is), then this name is checked for correctness. + /// It is possible, however, to disable such behavior; then the user must ensure that + /// closing element name is correct manually. + #[inline] + pub fn name<N>(mut self, name: N) -> EndElementBuilder<'a> where N: Into<Name<'a>> { + self.name = Some(name.into()); + self + } +} + +impl<'a> From<EndElementBuilder<'a>> for XmlEvent<'a> { + fn from(b: EndElementBuilder<'a>) -> XmlEvent<'a> { + XmlEvent::EndElement { name: b.name } + } +} + +/// A builder for a starting element event. +pub struct StartElementBuilder<'a> { + name: Name<'a>, + attributes: Vec<Attribute<'a>>, + namespace: Namespace +} + +impl<'a> StartElementBuilder<'a> { + /// Sets an attribute value of this element to the given string. + /// + /// This method can be used to add attributes to the starting element. Name is a qualified + /// name; its namespace is ignored, but its prefix is checked for correctness, that is, + /// it is checked that the prefix is bound to some namespace in the current context. + /// + /// Currently attributes are not checked for duplicates. Note that duplicate attributes + /// are a violation of XML document well-formedness. + /// + /// The writer checks that you don't specify reserved prefix names, for example `xmlns`. + #[inline] + pub fn attr<N>(mut self, name: N, value: &'a str) -> StartElementBuilder<'a> + where N: Into<Name<'a>> + { + self.attributes.push(Attribute::new(name.into(), value)); + self + } + + /// Adds a namespace to the current namespace context. + /// + /// If no namespace URI was bound to the provided prefix at this point of the document, + /// then the mapping from the prefix to the provided namespace URI will be written as + /// a part of this element attribute set. + /// + /// If the same namespace URI was bound to the provided prefix at this point of the document, + /// then no namespace attributes will be emitted. + /// + /// If some other namespace URI was bound to the provided prefix at this point of the document, + /// then another binding will be added as a part of this element attribute set, shadowing + /// the outer binding. + #[inline] + pub fn ns<S1, S2>(mut self, prefix: S1, uri: S2) -> StartElementBuilder<'a> + where S1: Into<String>, S2: Into<String> + { + self.namespace.put(prefix, uri); + self + } + + /// Adds a default namespace mapping to the current namespace context. + /// + /// Same rules as for `ns()` are also valid for the default namespace mapping. + #[inline] + pub fn default_ns<S>(mut self, uri: S) -> StartElementBuilder<'a> + where S: Into<String> + { + self.namespace.put(NS_NO_PREFIX, uri); + self + } +} + +impl<'a> From<StartElementBuilder<'a>> for XmlEvent<'a> { + #[inline] + fn from(b: StartElementBuilder<'a>) -> XmlEvent<'a> { + XmlEvent::StartElement { + name: b.name, + attributes: Cow::Owned(b.attributes), + namespace: Cow::Owned(b.namespace) + } + } +} |