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