1 //! Contains high-level interface for an events-based XML emitter.
2 //!
3 //! The most important type in this module is `EventWriter` which allows writing an XML document
4 //! to some output stream.
5 
6 pub use self::config::EmitterConfig;
7 pub use self::emitter::EmitterError as Error;
8 pub use self::emitter::Result;
9 pub use self::events::XmlEvent;
10 
11 use self::emitter::Emitter;
12 
13 use std::io::prelude::*;
14 
15 mod config;
16 mod emitter;
17 pub mod events;
18 
19 /// A wrapper around an `std::io::Write` instance which emits XML document according to provided
20 /// events.
21 pub struct EventWriter<W> {
22     sink: W,
23     emitter: Emitter,
24 }
25 
26 impl<W: Write> EventWriter<W> {
27     /// Creates a new `EventWriter` out of an `std::io::Write` instance using the default
28     /// configuration.
29     #[inline]
new(sink: W) -> EventWriter<W>30     pub fn new(sink: W) -> EventWriter<W> {
31         EventWriter::new_with_config(sink, EmitterConfig::new())
32     }
33 
34     /// Creates a new `EventWriter` out of an `std::io::Write` instance using the provided
35     /// configuration.
36     #[inline]
new_with_config(sink: W, config: EmitterConfig) -> EventWriter<W>37     pub fn new_with_config(sink: W, config: EmitterConfig) -> EventWriter<W> {
38         EventWriter {
39             sink,
40             emitter: Emitter::new(config),
41         }
42     }
43 
44     /// Writes the next piece of XML document according to the provided event.
45     ///
46     /// Note that output data may not exactly correspond to the written event because
47     /// of various configuration options. For example, `XmlEvent::EndElement` may
48     /// correspond to a separate closing element or it may cause writing an empty element.
49     /// Another example is that `XmlEvent::CData` may be represented as characters in
50     /// the output stream.
write<'a, E>(&mut self, event: E) -> Result<()> where E: Into<XmlEvent<'a>>51     pub fn write<'a, E>(&mut self, event: E) -> Result<()> where E: Into<XmlEvent<'a>> {
52         match event.into() {
53             XmlEvent::StartDocument { version, encoding, standalone } =>
54                 self.emitter.emit_start_document(&mut self.sink, version, encoding.unwrap_or("UTF-8"), standalone),
55             XmlEvent::ProcessingInstruction { name, data } =>
56                 self.emitter.emit_processing_instruction(&mut self.sink, name, data),
57             XmlEvent::StartElement { name, attributes, namespace } => {
58                 self.emitter.namespace_stack_mut().push_empty().checked_target().extend(namespace.as_ref());
59                 self.emitter.emit_start_element(&mut self.sink, name, &attributes)
60             }
61             XmlEvent::EndElement { name } => {
62                 let r = self.emitter.emit_end_element(&mut self.sink, name);
63                 self.emitter.namespace_stack_mut().try_pop();
64                 r
65             }
66             XmlEvent::Comment(content) => self.emitter.emit_comment(&mut self.sink, content),
67             XmlEvent::CData(content) => self.emitter.emit_cdata(&mut self.sink, content),
68             XmlEvent::Characters(content) => self.emitter.emit_characters(&mut self.sink, content),
69         }
70     }
71 
72     /// Returns a mutable reference to the underlying `Writer`.
73     ///
74     /// Note that having a reference to the underlying sink makes it very easy to emit invalid XML
75     /// documents. Use this method with care. Valid use cases for this method include accessing
76     /// methods like `Write::flush`, which do not emit new data but rather change the state
77     /// of the stream itself.
inner_mut(&mut self) -> &mut W78     pub fn inner_mut(&mut self) -> &mut W {
79         &mut self.sink
80     }
81 
82     /// Unwraps this `EventWriter`, returning the underlying writer.
83     ///
84     /// Note that this is a destructive operation: unwrapping a writer and then wrapping
85     /// it again with `EventWriter::new()` will create a fresh writer whose state will be
86     /// blank; for example, accumulated namespaces will be reset.
into_inner(self) -> W87     pub fn into_inner(self) -> W {
88         self.sink
89     }
90 }
91