//! 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 }, /// 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> }, /// 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(name: S) -> StartElementBuilder<'a> where S: Into> { 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> } /// 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(mut self, name: N) -> EndElementBuilder<'a> where N: Into> { self.name = Some(name.into()); self } } impl<'a> From> 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>, 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(mut self, name: N, value: &'a str) -> StartElementBuilder<'a> where N: Into> { 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(mut self, prefix: S1, uri: S2) -> StartElementBuilder<'a> where S1: Into, S2: Into { 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(mut self, uri: S) -> StartElementBuilder<'a> where S: Into { self.namespace.put(NS_NO_PREFIX, uri); self } } impl<'a> From> 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) } } }