Revert^2 "Import xml-rs 0.8.3"

2fc140166d67619ad4a9ce3013e2604b8b5845aa

Change-Id: I6fdc0f5dc86abd2b5417e43bae3da28070ad8636
diff --git a/src/writer/config.rs b/src/writer/config.rs
new file mode 100644
index 0000000..ebabf18
--- /dev/null
+++ b/src/writer/config.rs
@@ -0,0 +1,157 @@
+//! Contains emitter configuration structure.
+
+use std::io::Write;
+use std::borrow::Cow;
+
+use writer::EventWriter;
+
+/// Emitter configuration structure.
+///
+/// This structure contains various options which control XML document emitter behavior.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct EmitterConfig {
+    /// Line separator used to separate lines in formatted output. Default is `"\n"`.
+    pub line_separator: Cow<'static, str>,
+
+    /// A string which will be used for a single level of indentation. Default is `"  "`
+    /// (two spaces).
+    pub indent_string: Cow<'static, str>,
+
+    /// Whether or not the emitted document should be indented. Default is false.
+    ///
+    /// The emitter is capable to perform automatic indentation of the emitted XML document.
+    /// It is done in stream-like fashion and does not require the knowledge of the whole
+    /// document in advance.
+    ///
+    /// Sometimes, however, automatic indentation is undesirable, e.g. when you want to keep
+    /// existing layout when processing an existing XML document. Also the indentiation algorithm
+    /// is not thoroughly tested. Hence by default it is disabled.
+    pub perform_indent: bool,
+
+    /// Whether or not characters in output events will be escaped. Default is true.
+    ///
+    /// The emitter can automatically escape characters which can't appear in PCDATA sections
+    /// or element attributes of an XML document, like `<` or `"` (in attributes). This may
+    /// introduce some overhead because then every corresponding piece of character data
+    /// should be scanned for invalid characters.
+    ///
+    /// If this option is disabled, the XML writer may produce non-well-formed documents, so
+    /// use `false` value for this option with care.
+    pub perform_escaping: bool,
+
+    /// Whether or not to write XML document declaration at the beginning of a document.
+    /// Default is true.
+    ///
+    /// This option controls whether the document declaration should be emitted automatically
+    /// before a root element is written if it was not emitted explicitly by the user.
+    pub write_document_declaration: bool,
+
+    /// Whether or not to convert elements with empty content to empty elements. Default is true.
+    ///
+    /// This option allows turning elements like `<a></a>` (an element with empty content)
+    /// into `<a />` (an empty element).
+    pub normalize_empty_elements: bool,
+
+    /// Whether or not to emit CDATA events as plain characters. Default is false.
+    ///
+    /// This option forces the emitter to convert CDATA events into regular character events,
+    /// performing all the necessary escaping beforehand. This may be occasionally useful
+    /// for feeding the document into incorrect parsers which do not support CDATA.
+    pub cdata_to_characters: bool,
+
+    /// Whether or not to keep element names to support `EndElement` events without explicit names.
+    /// Default is true.
+    ///
+    /// This option makes the emitter to keep names of written elements in order to allow
+    /// omitting names when writing closing element tags. This could incur some memory overhead.
+    pub keep_element_names_stack: bool,
+
+    /// Whether or not to automatically insert leading and trailing spaces in emitted comments,
+    /// if necessary. Default is true.
+    ///
+    /// This is a convenience option in order for the user not to append spaces before and after
+    /// comments text in order to get more pretty comments: `<!-- something -->` instead of
+    /// `<!--something-->`.
+    pub autopad_comments: bool,
+
+    /// Whether or not to automatically insert spaces before the trailing `/>` in self-closing
+    /// elements. Default is true.
+    ///
+    /// This option is only meaningful if `normalize_empty_elements` is true. For example, the
+    /// element `<a></a>` would be unaffected. When `normalize_empty_elements` is true, then when
+    /// this option is also true, the same element would appear `<a />`. If this option is false,
+    /// then the same element would appear `<a/>`.
+    pub pad_self_closing: bool,
+}
+
+impl EmitterConfig {
+    /// Creates an emitter configuration with default values.
+    ///
+    /// You can tweak default options with builder-like pattern:
+    ///
+    /// ```rust
+    /// use xml::writer::EmitterConfig;
+    ///
+    /// let config = EmitterConfig::new()
+    ///     .line_separator("\r\n")
+    ///     .perform_indent(true)
+    ///     .normalize_empty_elements(false);
+    /// ```
+    #[inline]
+    pub fn new() -> EmitterConfig {
+        EmitterConfig {
+            line_separator: "\n".into(),
+            indent_string: "  ".into(),  // two spaces
+            perform_indent: false,
+            perform_escaping: true,
+            write_document_declaration: true,
+            normalize_empty_elements: true,
+            cdata_to_characters: false,
+            keep_element_names_stack: true,
+            autopad_comments: true,
+            pad_self_closing: true
+        }
+    }
+
+    /// Creates an XML writer with this configuration.
+    ///
+    /// This is a convenience method for configuring and creating a writer at the same time:
+    ///
+    /// ```rust
+    /// use xml::writer::EmitterConfig;
+    ///
+    /// let mut target: Vec<u8> = Vec::new();
+    ///
+    /// let writer = EmitterConfig::new()
+    ///     .line_separator("\r\n")
+    ///     .perform_indent(true)
+    ///     .normalize_empty_elements(false)
+    ///     .create_writer(&mut target);
+    /// ```
+    ///
+    /// This method is exactly equivalent to calling `EventWriter::new_with_config()` with
+    /// this configuration object.
+    #[inline]
+    pub fn create_writer<W: Write>(self, sink: W) -> EventWriter<W> {
+        EventWriter::new_with_config(sink, self)
+    }
+}
+
+impl Default for EmitterConfig {
+    #[inline]
+    fn default() -> EmitterConfig {
+        EmitterConfig::new()
+    }
+}
+
+gen_setters!(EmitterConfig,
+    line_separator: into Cow<'static, str>,
+    indent_string: into Cow<'static, str>,
+    perform_indent: val bool,
+    write_document_declaration: val bool,
+    normalize_empty_elements: val bool,
+    cdata_to_characters: val bool,
+    keep_element_names_stack: val bool,
+    autopad_comments: val bool,
+    pad_self_closing: val bool
+);
diff --git a/src/writer/emitter.rs b/src/writer/emitter.rs
new file mode 100644
index 0000000..bfd9205
--- /dev/null
+++ b/src/writer/emitter.rs
@@ -0,0 +1,446 @@
+use std::io;
+use std::io::prelude::*;
+use std::fmt;
+use std::result;
+use std::borrow::Cow;
+use std::error::Error;
+
+use common;
+use name::{Name, OwnedName};
+use attribute::Attribute;
+use escape::{escape_str_attribute, escape_str_pcdata};
+use common::XmlVersion;
+use namespace::{NamespaceStack, NS_NO_PREFIX, NS_EMPTY_URI, NS_XMLNS_PREFIX, NS_XML_PREFIX};
+
+use writer::config::EmitterConfig;
+
+/// An error which may be returned by `XmlWriter` when writing XML events.
+#[derive(Debug)]
+pub enum EmitterError {
+    /// An I/O error occured in the underlying `Write` instance.
+    Io(io::Error),
+
+    /// Document declaration has already been written to the output stream.
+    DocumentStartAlreadyEmitted,
+
+    /// The name of the last opening element is not available.
+    LastElementNameNotAvailable,
+
+    /// The name of the last opening element is not equal to the name of the provided
+    /// closing element.
+    EndElementNameIsNotEqualToLastStartElementName,
+
+    /// End element name is not specified when it is needed, for example, when automatic
+    /// closing is not enabled in configuration.
+    EndElementNameIsNotSpecified
+}
+
+impl From<io::Error> for EmitterError {
+    fn from(err: io::Error) -> EmitterError {
+        EmitterError::Io(err)
+    }
+}
+
+impl fmt::Display for EmitterError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+
+        write!(f, "emitter error: ")?;
+        match *self {
+            EmitterError::Io(ref e) =>
+                write!(f, "I/O error: {}", e),
+            ref other =>
+                write!(f, "{}", other.description()),
+        }
+    }
+}
+
+impl Error for EmitterError {
+    fn description(&self) -> &str {
+        match *self {
+            EmitterError::Io(_) =>
+                "I/O error",
+            EmitterError::DocumentStartAlreadyEmitted =>
+                "document start event has already been emitted",
+            EmitterError::LastElementNameNotAvailable =>
+                "last element name is not available",
+            EmitterError::EndElementNameIsNotEqualToLastStartElementName =>
+                "end element name is not equal to last start element name",
+            EmitterError::EndElementNameIsNotSpecified =>
+                "end element name is not specified and can't be inferred",
+        }
+    }
+}
+
+/// A result type yielded by `XmlWriter`.
+pub type Result<T> = result::Result<T, EmitterError>;
+
+// TODO: split into a low-level fast writer without any checks and formatting logic and a
+// high-level indenting validating writer
+pub struct Emitter {
+    config: EmitterConfig,
+
+    nst: NamespaceStack,
+
+    indent_level: usize,
+    indent_stack: Vec<IndentFlags>,
+
+    element_names: Vec<OwnedName>,
+
+    start_document_emitted: bool,
+    just_wrote_start_element: bool
+}
+
+impl Emitter {
+    pub fn new(config: EmitterConfig) -> Emitter {
+        Emitter {
+            config,
+
+            nst: NamespaceStack::empty(),
+
+            indent_level: 0,
+            indent_stack: vec![IndentFlags::WroteNothing],
+
+            element_names: Vec::new(),
+
+            start_document_emitted: false,
+            just_wrote_start_element: false
+        }
+    }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+enum IndentFlags {
+    WroteNothing,
+    WroteMarkup,
+    WroteText,
+}
+
+impl Emitter {
+    /// Returns the current state of namespaces.
+    #[inline]
+    pub fn namespace_stack_mut(&mut self) -> &mut NamespaceStack {
+        &mut self.nst
+    }
+
+    #[inline]
+    fn wrote_text(&self) -> bool {
+        *self.indent_stack.last().unwrap() == IndentFlags::WroteText
+    }
+
+    #[inline]
+    fn wrote_markup(&self) -> bool {
+        *self.indent_stack.last().unwrap() == IndentFlags::WroteMarkup
+    }
+
+    #[inline]
+    fn set_wrote_text(&mut self) {
+        *self.indent_stack.last_mut().unwrap() = IndentFlags::WroteText;
+    }
+
+    #[inline]
+    fn set_wrote_markup(&mut self) {
+        *self.indent_stack.last_mut().unwrap() = IndentFlags::WroteMarkup;
+    }
+
+    #[inline]
+    fn reset_state(&mut self) {
+        *self.indent_stack.last_mut().unwrap() = IndentFlags::WroteNothing;
+    }
+
+    fn write_newline<W: Write>(&mut self, target: &mut W, level: usize) -> Result<()> {
+        target.write(self.config.line_separator.as_bytes())?;
+        for _ in 0..level {
+            target.write(self.config.indent_string.as_bytes())?;
+        }
+        Ok(())
+    }
+
+    fn before_markup<W: Write>(&mut self, target: &mut W) -> Result<()> {
+        if self.config.perform_indent && !self.wrote_text() &&
+           (self.indent_level > 0 || self.wrote_markup()) {
+            let indent_level = self.indent_level;
+            self.write_newline(target, indent_level)?;
+            if self.indent_level > 0 && self.config.indent_string.len() > 0 {
+                self.after_markup();
+            }
+        }
+        Ok(())
+    }
+
+    fn after_markup(&mut self) {
+        self.set_wrote_markup();
+    }
+
+    fn before_start_element<W: Write>(&mut self, target: &mut W) -> Result<()> {
+        self.before_markup(target)?;
+        self.indent_stack.push(IndentFlags::WroteNothing);
+        Ok(())
+    }
+
+    fn after_start_element(&mut self) {
+        self.after_markup();
+        self.indent_level += 1;
+    }
+
+    fn before_end_element<W: Write>(&mut self, target: &mut W) -> Result<()> {
+        if self.config.perform_indent && self.indent_level > 0 && self.wrote_markup() &&
+           !self.wrote_text() {
+            let indent_level = self.indent_level;
+            self.write_newline(target, indent_level - 1)
+        } else {
+            Ok(())
+        }
+    }
+
+    fn after_end_element(&mut self) {
+        if self.indent_level > 0 {
+            self.indent_level -= 1;
+            self.indent_stack.pop();
+        }
+        self.set_wrote_markup();
+    }
+
+    fn after_text(&mut self) {
+        self.set_wrote_text();
+    }
+
+    pub fn emit_start_document<W: Write>(&mut self, target: &mut W,
+                                         version: XmlVersion,
+                                         encoding: &str,
+                                         standalone: Option<bool>) -> Result<()> {
+        if self.start_document_emitted {
+            return Err(EmitterError::DocumentStartAlreadyEmitted);
+        }
+        self.start_document_emitted = true;
+
+        self.before_markup(target)?;
+        let result = {
+            let mut write = move || {
+                write!(target, "<?xml version=\"{}\" encoding=\"{}\"", version, encoding)?;
+
+                if let Some(standalone) = standalone {
+                    write!(target, " standalone=\"{}\"", if standalone { "yes" } else { "no" })?;
+                }
+
+                write!(target, "?>")?;
+
+                Ok(())
+            };
+            write()
+        };
+        self.after_markup();
+
+        result
+    }
+
+    fn check_document_started<W: Write>(&mut self, target: &mut W) -> Result<()> {
+        if !self.start_document_emitted && self.config.write_document_declaration {
+            self.emit_start_document(target, common::XmlVersion::Version10, "utf-8", None)
+        } else {
+            Ok(())
+        }
+    }
+
+    fn fix_non_empty_element<W: Write>(&mut self, target: &mut W) -> Result<()> {
+        if self.config.normalize_empty_elements && self.just_wrote_start_element {
+            self.just_wrote_start_element = false;
+            target.write(b">").map(|_| ()).map_err(From::from)
+        } else {
+            Ok(())
+        }
+    }
+
+    pub fn emit_processing_instruction<W: Write>(&mut self,
+                                                 target: &mut W,
+                                                 name: &str,
+                                                 data: Option<&str>) -> Result<()> {
+        self.check_document_started(target)?;
+        self.fix_non_empty_element(target)?;
+
+        self.before_markup(target)?;
+
+        let result = {
+            let mut write = || {
+                write!(target, "<?{}", name)?;
+
+                if let Some(data) = data {
+                    write!(target, " {}", data)?;
+                }
+
+                write!(target, "?>")?;
+
+                Ok(())
+            };
+            write()
+        };
+
+        self.after_markup();
+
+        result
+    }
+
+    fn emit_start_element_initial<W>(&mut self, target: &mut W,
+                                     name: Name,
+                                     attributes: &[Attribute]) -> Result<()>
+        where W: Write
+    {
+        self.check_document_started(target)?;
+        self.fix_non_empty_element(target)?;
+        self.before_start_element(target)?;
+        write!(target, "<{}", name.repr_display())?;
+        self.emit_current_namespace_attributes(target)?;
+        self.emit_attributes(target, attributes)?;
+        self.after_start_element();
+        Ok(())
+    }
+
+    pub fn emit_start_element<W>(&mut self, target: &mut W,
+                                 name: Name,
+                                 attributes: &[Attribute]) -> Result<()>
+        where W: Write
+    {
+        if self.config.keep_element_names_stack {
+            self.element_names.push(name.to_owned());
+        }
+
+        self.emit_start_element_initial(target, name, attributes)?;
+        self.just_wrote_start_element = true;
+
+        if !self.config.normalize_empty_elements {
+            write!(target, ">")?;
+        }
+
+        Ok(())
+    }
+
+    pub fn emit_current_namespace_attributes<W>(&mut self, target: &mut W) -> Result<()>
+        where W: Write
+    {
+        for (prefix, uri) in self.nst.peek() {
+            match prefix {
+                // internal namespaces are not emitted
+                NS_XMLNS_PREFIX | NS_XML_PREFIX => Ok(()),
+                //// there is already a namespace binding with this prefix in scope
+                //prefix if self.nst.get(prefix) == Some(uri) => Ok(()),
+                // emit xmlns only if it is overridden
+                NS_NO_PREFIX => if uri != NS_EMPTY_URI {
+                    write!(target, " xmlns=\"{}\"", uri)
+                } else { Ok(()) },
+                // everything else
+                prefix => write!(target, " xmlns:{}=\"{}\"", prefix, uri)
+            }?;
+        }
+        Ok(())
+    }
+
+    pub fn emit_attributes<W: Write>(&mut self, target: &mut W,
+                                      attributes: &[Attribute]) -> Result<()> {
+        for attr in attributes.iter() {
+            write!(
+                target, " {}=\"{}\"",
+                attr.name.repr_display(),
+                if self.config.perform_escaping { escape_str_attribute(attr.value) } else { Cow::Borrowed(attr.value) }
+            )?
+        }
+        Ok(())
+    }
+
+    pub fn emit_end_element<W: Write>(&mut self, target: &mut W,
+                                      name: Option<Name>) -> Result<()> {
+        let owned_name = if self.config.keep_element_names_stack {
+            Some(self.element_names.pop().ok_or(EmitterError::LastElementNameNotAvailable)?)
+        } else {
+            None
+        };
+
+        // Check that last started element name equals to the provided name, if there are both
+        if let Some(ref last_name) = owned_name {
+            if let Some(ref name) = name {
+                if last_name.borrow() != *name {
+                    return Err(EmitterError::EndElementNameIsNotEqualToLastStartElementName);
+                }
+            }
+        }
+
+        if let Some(name) = owned_name.as_ref().map(|n| n.borrow()).or(name) {
+            if self.config.normalize_empty_elements && self.just_wrote_start_element {
+                self.just_wrote_start_element = false;
+                let termination = if self.config.pad_self_closing { " />" } else { "/>" };
+                let result = target.write(termination.as_bytes()).map_err(From::from);
+                self.after_end_element();
+                result.map(|_| ())
+            } else {
+                self.just_wrote_start_element = false;
+
+                self.before_end_element(target)?;
+                let result = write!(target, "</{}>", name.repr_display()).map_err(From::from);
+                self.after_end_element();
+
+                result
+            }
+        } else {
+            Err(EmitterError::EndElementNameIsNotSpecified)
+        }
+    }
+
+    pub fn emit_cdata<W: Write>(&mut self, target: &mut W, content: &str) -> Result<()> {
+        self.fix_non_empty_element(target)?;
+        if self.config.cdata_to_characters {
+            self.emit_characters(target, content)
+        } else {
+            // TODO: escape ']]>' characters in CDATA as two adjacent CDATA blocks
+            target.write(b"<![CDATA[")?;
+            target.write(content.as_bytes())?;
+            target.write(b"]]>")?;
+
+            self.after_text();
+
+            Ok(())
+        }
+    }
+
+    pub fn emit_characters<W: Write>(&mut self, target: &mut W,
+                                      content: &str) -> Result<()> {
+        self.fix_non_empty_element(target)?;
+        target.write(
+            (if self.config.perform_escaping {
+                escape_str_pcdata(content)
+            } else {
+                Cow::Borrowed(content)
+            }).as_bytes()
+        )?;
+        self.after_text();
+        Ok(())
+    }
+
+    pub fn emit_comment<W: Write>(&mut self, target: &mut W, content: &str) -> Result<()> {
+        self.fix_non_empty_element(target)?;
+
+        // TODO: add escaping dashes at the end of the comment
+
+        let autopad_comments = self.config.autopad_comments;
+        let write = |target: &mut W| -> Result<()> {
+            target.write(b"<!--")?;
+
+            if autopad_comments && !content.starts_with(char::is_whitespace) {
+                target.write(b" ")?;
+            }
+
+            target.write(content.as_bytes())?;
+
+            if autopad_comments && !content.ends_with(char::is_whitespace) {
+                target.write(b" ")?;
+            }
+
+            target.write(b"-->")?;
+
+            Ok(())
+        };
+
+        self.before_markup(target)?;
+        let result = write(target);
+        self.after_markup();
+
+        result
+    }
+}
diff --git a/src/writer/events.rs b/src/writer/events.rs
new file mode 100644
index 0000000..1f7040f
--- /dev/null
+++ b/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)
+        }
+    }
+}
diff --git a/src/writer/mod.rs b/src/writer/mod.rs
new file mode 100644
index 0000000..ea1b242
--- /dev/null
+++ b/src/writer/mod.rs
@@ -0,0 +1,93 @@
+//! Contains high-level interface for an events-based XML emitter.
+//!
+//! The most important type in this module is `EventWriter` which allows writing an XML document
+//! to some output stream.
+
+pub use self::emitter::Result;
+pub use self::emitter::EmitterError as Error;
+pub use self::config::EmitterConfig;
+pub use self::events::XmlEvent;
+
+use self::emitter::Emitter;
+
+use std::io::prelude::*;
+
+mod emitter;
+mod config;
+pub mod events;
+
+/// A wrapper around an `std::io::Write` instance which emits XML document according to provided
+/// events.
+pub struct EventWriter<W> {
+    sink: W,
+    emitter: Emitter
+}
+
+impl<W: Write> EventWriter<W> {
+    /// Creates a new `EventWriter` out of an `std::io::Write` instance using the default
+    /// configuration.
+    #[inline]
+    pub fn new(sink: W) -> EventWriter<W> {
+        EventWriter::new_with_config(sink, EmitterConfig::new())
+    }
+
+    /// Creates a new `EventWriter` out of an `std::io::Write` instance using the provided
+    /// configuration.
+    #[inline]
+    pub fn new_with_config(sink: W, config: EmitterConfig) -> EventWriter<W> {
+        EventWriter {
+            sink,
+            emitter: Emitter::new(config)
+        }
+    }
+
+    /// Writes the next piece of XML document according to the provided event.
+    ///
+    /// Note that output data may not exactly correspond to the written event because
+    /// of various configuration options. For example, `XmlEvent::EndElement` may
+    /// correspond to a separate closing element or it may cause writing an empty element.
+    /// Another example is that `XmlEvent::CData` may be represented as characters in
+    /// the output stream.
+    pub fn write<'a, E>(&mut self, event: E) -> Result<()> where E: Into<XmlEvent<'a>> {
+        match event.into() {
+            XmlEvent::StartDocument { version, encoding, standalone } =>
+                self.emitter.emit_start_document(&mut self.sink, version, encoding.unwrap_or("UTF-8"), standalone),
+            XmlEvent::ProcessingInstruction { name, data } =>
+                self.emitter.emit_processing_instruction(&mut self.sink, name, data),
+            XmlEvent::StartElement { name, attributes, namespace } => {
+                self.emitter.namespace_stack_mut().push_empty().checked_target().extend(namespace.as_ref());
+                self.emitter.emit_start_element(&mut self.sink, name, &attributes)
+            }
+            XmlEvent::EndElement { name } => {
+                let r = self.emitter.emit_end_element(&mut self.sink, name);
+                self.emitter.namespace_stack_mut().try_pop();
+                r
+            }
+            XmlEvent::Comment(content) =>
+                self.emitter.emit_comment(&mut self.sink, content),
+            XmlEvent::CData(content) =>
+                self.emitter.emit_cdata(&mut self.sink, content),
+            XmlEvent::Characters(content) =>
+                self.emitter.emit_characters(&mut self.sink, content)
+        }
+    }
+
+    /// Returns a mutable reference to the underlying `Writer`.
+    ///
+    /// Note that having a reference to the underlying sink makes it very easy to emit invalid XML
+    /// documents. Use this method with care. Valid use cases for this method include accessing
+    /// methods like `Write::flush`, which do not emit new data but rather change the state
+    /// of the stream itself.
+    pub fn inner_mut(&mut self) -> &mut W {
+        &mut self.sink
+    }
+
+    /// Unwraps this `EventWriter`, returning the underlying writer.
+    ///
+    /// Note that this is a destructive operation: unwrapping a writer and then wrapping
+    /// it again with `EventWriter::new()` will create a fresh writer whose state will be
+    /// blank; for example, accumulated namespaces will be reset.
+    pub fn into_inner(self) -> W {
+        self.sink
+    }
+}