quick_xml/
writer.rs

1//! Contains high-level interface for an events-based XML emitter.
2
3use std::borrow::Cow;
4use std::io::Write;
5use std::result::Result as StdResult;
6
7use crate::encoding::UTF8_BOM;
8use crate::errors::{Error, Result};
9use crate::events::{attributes::Attribute, BytesCData, BytesStart, BytesText, Event};
10
11#[cfg(feature = "async-tokio")]
12mod async_tokio;
13
14/// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] or [`tokio::io::AsyncWrite`] implementor.
15#[cfg(feature = "serialize")]
16use {crate::de::DeError, serde::Serialize};
17
18/// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] implementor.
19///
20/// # Examples
21///
22/// ```
23/// # use pretty_assertions::assert_eq;
24/// use quick_xml::events::{Event, BytesEnd, BytesStart};
25/// use quick_xml::reader::Reader;
26/// use quick_xml::writer::Writer;
27/// use std::io::Cursor;
28///
29/// let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
30/// let mut reader = Reader::from_str(xml);
31/// reader.config_mut().trim_text(true);
32/// let mut writer = Writer::new(Cursor::new(Vec::new()));
33/// loop {
34///     match reader.read_event() {
35///         Ok(Event::Start(e)) if e.name().as_ref() == b"this_tag" => {
36///
37///             // crates a new element ... alternatively we could reuse `e` by calling
38///             // `e.into_owned()`
39///             let mut elem = BytesStart::new("my_elem");
40///
41///             // collect existing attributes
42///             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
43///
44///             // copy existing attributes, adds a new my-key="some value" attribute
45///             elem.push_attribute(("my-key", "some value"));
46///
47///             // writes the event to the writer
48///             assert!(writer.write_event(Event::Start(elem)).is_ok());
49///         },
50///         Ok(Event::End(e)) if e.name().as_ref() == b"this_tag" => {
51///             assert!(writer.write_event(Event::End(BytesEnd::new("my_elem"))).is_ok());
52///         },
53///         Ok(Event::Eof) => break,
54///         // we can either move or borrow the event to write, depending on your use-case
55///         Ok(e) => assert!(writer.write_event(e).is_ok()),
56///         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
57///     }
58/// }
59///
60/// let result = writer.into_inner().into_inner();
61/// let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
62/// assert_eq!(result, expected.as_bytes());
63/// ```
64#[derive(Clone)]
65pub struct Writer<W> {
66    /// underlying writer
67    writer: W,
68    indent: Option<Indentation>,
69}
70
71impl<W> Writer<W> {
72    /// Creates a `Writer` from a generic writer.
73    pub fn new(inner: W) -> Writer<W> {
74        Writer {
75            writer: inner,
76            indent: None,
77        }
78    }
79
80    /// Creates a `Writer` with configured indents from a generic writer.
81    pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer<W> {
82        Writer {
83            writer: inner,
84            indent: Some(Indentation::new(indent_char, indent_size)),
85        }
86    }
87
88    /// Consumes this `Writer`, returning the underlying writer.
89    pub fn into_inner(self) -> W {
90        self.writer
91    }
92
93    /// Get a mutable reference to the underlying writer.
94    pub fn get_mut(&mut self) -> &mut W {
95        &mut self.writer
96    }
97
98    /// Get a reference to the underlying writer.
99    pub fn get_ref(&self) -> &W {
100        &self.writer
101    }
102
103    /// Provides a simple, high-level API for writing XML elements.
104    ///
105    /// Returns an [`ElementWriter`] that simplifies setting attributes and writing
106    /// content inside the element.
107    ///
108    /// # Example
109    ///
110    /// ```
111    /// # use quick_xml::Result;
112    /// # fn main() -> Result<()> {
113    /// use quick_xml::events::{BytesStart, BytesText, Event};
114    /// use quick_xml::writer::Writer;
115    /// use quick_xml::Error;
116    /// use std::io::Cursor;
117    ///
118    /// let mut writer = Writer::new(Cursor::new(Vec::new()));
119    ///
120    /// // writes <tag attr1="value1"/>
121    /// writer.create_element("tag")
122    ///     .with_attribute(("attr1", "value1"))  // chain `with_attribute()` calls to add many attributes
123    ///     .write_empty()?;
124    ///
125    /// // writes <tag attr1="value1" attr2="value2">with some text inside</tag>
126    /// writer.create_element("tag")
127    ///     .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter())  // or add attributes from an iterator
128    ///     .write_text_content(BytesText::new("with some text inside"))?;
129    ///
130    /// // writes <tag><fruit quantity="0">apple</fruit><fruit quantity="1">orange</fruit></tag>
131    /// writer.create_element("tag")
132    ///     // We need to provide error type, because it is not named somewhere explicitly
133    ///     .write_inner_content::<_, Error>(|writer| {
134    ///         let fruits = ["apple", "orange"];
135    ///         for (quant, item) in fruits.iter().enumerate() {
136    ///             writer
137    ///                 .create_element("fruit")
138    ///                 .with_attribute(("quantity", quant.to_string().as_str()))
139    ///                 .write_text_content(BytesText::new(item))?;
140    ///         }
141    ///         Ok(())
142    ///     })?;
143    /// # Ok(())
144    /// # }
145    /// ```
146    #[must_use]
147    pub fn create_element<'a, N>(&'a mut self, name: N) -> ElementWriter<W>
148    where
149        N: Into<Cow<'a, str>>,
150    {
151        ElementWriter {
152            writer: self,
153            start_tag: BytesStart::new(name),
154            state: AttributeIndent::NoneAttributesWritten,
155            spaces: Vec::new(),
156        }
157    }
158}
159
160impl<W: Write> Writer<W> {
161    /// Write a [Byte-Order-Mark] character to the document.
162    ///
163    /// # Example
164    ///
165    /// ```rust
166    /// # use quick_xml::Result;
167    /// # fn main() -> Result<()> {
168    /// use quick_xml::events::{BytesStart, BytesText, Event};
169    /// use quick_xml::writer::Writer;
170    /// use quick_xml::Error;
171    /// use std::io::Cursor;
172    ///
173    /// let mut buffer = Vec::new();
174    /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
175    ///
176    /// writer.write_bom()?;
177    /// writer
178    ///     .create_element("empty")
179    ///     .with_attribute(("attr1", "value1"))
180    ///     .write_empty()
181    ///     .expect("failure");
182    ///
183    /// assert_eq!(
184    ///     std::str::from_utf8(&buffer).unwrap(),
185    ///     "\u{FEFF}<empty attr1=\"value1\"/>"
186    /// );
187    /// # Ok(())
188    /// # }
189    /// ```
190    /// [Byte-Order-Mark]: https://unicode.org/faq/utf_bom.html#BOM
191    pub fn write_bom(&mut self) -> Result<()> {
192        self.write(UTF8_BOM)
193    }
194
195    /// Writes the given event to the underlying writer.
196    pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<()> {
197        let mut next_should_line_break = true;
198        let result = match *event.as_ref() {
199            Event::Start(ref e) => {
200                let result = self.write_wrapped(b"<", e, b">");
201                if let Some(i) = self.indent.as_mut() {
202                    i.grow();
203                }
204                result
205            }
206            Event::End(ref e) => {
207                if let Some(i) = self.indent.as_mut() {
208                    i.shrink();
209                }
210                self.write_wrapped(b"</", e, b">")
211            }
212            Event::Empty(ref e) => self.write_wrapped(b"<", e, b"/>"),
213            Event::Text(ref e) => {
214                next_should_line_break = false;
215                self.write(e)
216            }
217            Event::Comment(ref e) => self.write_wrapped(b"<!--", e, b"-->"),
218            Event::CData(ref e) => {
219                next_should_line_break = false;
220                self.write(b"<![CDATA[")?;
221                self.write(e)?;
222                self.write(b"]]>")
223            }
224            Event::Decl(ref e) => self.write_wrapped(b"<?", e, b"?>"),
225            Event::PI(ref e) => self.write_wrapped(b"<?", e, b"?>"),
226            Event::DocType(ref e) => self.write_wrapped(b"<!DOCTYPE ", e, b">"),
227            Event::Eof => Ok(()),
228        };
229        if let Some(i) = self.indent.as_mut() {
230            i.should_line_break = next_should_line_break;
231        }
232        result
233    }
234
235    /// Writes bytes
236    #[inline]
237    pub(crate) fn write(&mut self, value: &[u8]) -> Result<()> {
238        self.writer.write_all(value).map_err(Into::into)
239    }
240
241    #[inline]
242    fn write_wrapped(&mut self, before: &[u8], value: &[u8], after: &[u8]) -> Result<()> {
243        if let Some(ref i) = self.indent {
244            if i.should_line_break {
245                self.writer.write_all(b"\n")?;
246                self.writer.write_all(i.current())?;
247            }
248        }
249        self.write(before)?;
250        self.write(value)?;
251        self.write(after)?;
252        Ok(())
253    }
254
255    /// Manually write a newline and indentation at the proper level.
256    ///
257    /// This can be used when the heuristic to line break and indent after any
258    /// [`Event`] apart from [`Text`] fails such as when a [`Start`] occurs directly
259    /// after [`Text`].
260    ///
261    /// This method will do nothing if `Writer` was not constructed with [`new_with_indent`].
262    ///
263    /// [`Text`]: Event::Text
264    /// [`Start`]: Event::Start
265    /// [`new_with_indent`]: Self::new_with_indent
266    pub fn write_indent(&mut self) -> Result<()> {
267        if let Some(ref i) = self.indent {
268            self.writer.write_all(b"\n")?;
269            self.writer.write_all(i.current())?;
270        }
271        Ok(())
272    }
273
274    /// Write an arbitrary serializable type
275    ///
276    /// Note: If you are attempting to write XML in a non-UTF-8 encoding, this may not
277    /// be safe to use. Rust basic types assume UTF-8 encodings.
278    ///
279    /// ```rust
280    /// # use pretty_assertions::assert_eq;
281    /// # use serde::Serialize;
282    /// # use quick_xml::events::{BytesStart, Event};
283    /// # use quick_xml::writer::Writer;
284    /// # use quick_xml::DeError;
285    /// # fn main() -> Result<(), DeError> {
286    /// #[derive(Debug, PartialEq, Serialize)]
287    /// struct MyData {
288    ///     question: String,
289    ///     answer: u32,
290    /// }
291    ///
292    /// let data = MyData {
293    ///     question: "The Ultimate Question of Life, the Universe, and Everything".into(),
294    ///     answer: 42,
295    /// };
296    ///
297    /// let mut buffer = Vec::new();
298    /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
299    ///
300    /// let start = BytesStart::new("root");
301    /// let end = start.to_end();
302    ///
303    /// writer.write_event(Event::Start(start.clone()))?;
304    /// writer.write_serializable("my_data", &data)?;
305    /// writer.write_event(Event::End(end))?;
306    ///
307    /// assert_eq!(
308    ///     std::str::from_utf8(&buffer)?,
309    ///     r#"<root>
310    ///     <my_data>
311    ///         <question>The Ultimate Question of Life, the Universe, and Everything</question>
312    ///         <answer>42</answer>
313    ///     </my_data>
314    /// </root>"#
315    /// );
316    /// # Ok(())
317    /// # }
318    /// ```
319    #[cfg(feature = "serialize")]
320    pub fn write_serializable<T: Serialize>(
321        &mut self,
322        tag_name: &str,
323        content: &T,
324    ) -> std::result::Result<(), DeError> {
325        use crate::se::{Indent, Serializer};
326
327        self.write_indent()?;
328        let mut fmt = ToFmtWrite(&mut self.writer);
329        let mut serializer = Serializer::with_root(&mut fmt, Some(tag_name))?;
330
331        if let Some(indent) = &mut self.indent {
332            serializer.set_indent(Indent::Borrow(indent));
333        }
334
335        content.serialize(serializer)?;
336
337        Ok(())
338    }
339}
340
341/// Track indent inside elements state
342///
343/// ```mermaid
344/// stateDiagram-v2
345///     [*] --> NoneAttributesWritten
346///     NoneAttributesWritten --> Spaces : .with_attribute()
347///     NoneAttributesWritten --> WriteConfigured : .new_line()
348///
349///     Spaces --> Spaces : .with_attribute()
350///     Spaces --> WriteSpaces : .new_line()
351///
352///     WriteSpaces --> Spaces : .with_attribute()
353///     WriteSpaces --> WriteSpaces : .new_line()
354///
355///     Configured --> Configured : .with_attribute()
356///     Configured --> WriteConfigured : .new_line()
357///
358///     WriteConfigured --> Configured : .with_attribute()
359///     WriteConfigured --> WriteConfigured : .new_line()
360/// ```
361#[derive(Debug)]
362enum AttributeIndent {
363    /// Initial state. `ElementWriter` was just created and no attributes written yet
364    NoneAttributesWritten,
365    /// Write specified count of spaces to indent before writing attribute in `with_attribute()`
366    WriteSpaces(usize),
367    /// Keep space indent that should be used if `new_line()` would be called
368    Spaces(usize),
369    /// Write specified count of indent characters before writing attribute in `with_attribute()`
370    WriteConfigured(usize),
371    /// Keep indent that should be used if `new_line()` would be called
372    Configured(usize),
373}
374
375/// A struct to write an element. Contains methods to add attributes and inner
376/// elements to the element
377pub struct ElementWriter<'a, W> {
378    writer: &'a mut Writer<W>,
379    start_tag: BytesStart<'a>,
380    state: AttributeIndent,
381    /// Contains spaces used to write space indents of attributes
382    spaces: Vec<u8>,
383}
384
385impl<'a, W> ElementWriter<'a, W> {
386    /// Adds an attribute to this element.
387    pub fn with_attribute<'b, I>(mut self, attr: I) -> Self
388    where
389        I: Into<Attribute<'b>>,
390    {
391        self.write_attr(attr.into());
392        self
393    }
394
395    /// Add additional attributes to this element using an iterator.
396    ///
397    /// The yielded items must be convertible to [`Attribute`] using `Into`.
398    pub fn with_attributes<'b, I>(mut self, attributes: I) -> Self
399    where
400        I: IntoIterator,
401        I::Item: Into<Attribute<'b>>,
402    {
403        let mut iter = attributes.into_iter();
404        if let Some(attr) = iter.next() {
405            self.write_attr(attr.into());
406            self.start_tag.extend_attributes(iter);
407        }
408        self
409    }
410
411    /// Push a new line inside an element between attributes. Note, that this
412    /// method does nothing if [`Writer`] was created without indentation support.
413    ///
414    /// # Examples
415    ///
416    /// The following code
417    ///
418    /// ```
419    /// # use quick_xml::writer::Writer;
420    /// let mut buffer = Vec::new();
421    /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 2);
422    /// writer
423    ///   .create_element("element")
424    ///     //.new_line() (1)
425    ///     .with_attribute(("first", "1"))
426    ///     .with_attribute(("second", "2"))
427    ///     .new_line()
428    ///     .with_attributes([
429    ///         ("third", "3"),
430    ///         ("fourth", "4"),
431    ///     ])
432    ///     //.new_line() (2)
433    ///     .write_empty();
434    /// ```
435    /// will produce the following XMLs:
436    /// ```xml
437    /// <!-- result of the code above. Spaces always is used -->
438    /// <element first="1" second="2"
439    ///          third="3" fourth="4"/>
440    ///
441    /// <!-- if uncomment only (1) - indent depends on indentation
442    ///      settings - 2 spaces here -->
443    /// <element
444    ///   first="1" second="2"
445    ///   third="3" fourth="4"/>
446    ///
447    /// <!-- if uncomment only (2). Spaces always is used  -->
448    /// <element first="1" second="2"
449    ///          third="3" fourth="4"
450    /// />
451    /// ```
452    pub fn new_line(mut self) -> Self {
453        if let Some(i) = self.writer.indent.as_mut() {
454            match self.state {
455                // .new_line() called just after .create_element().
456                // Use element indent to additionally indent attributes
457                AttributeIndent::NoneAttributesWritten => {
458                    self.state = AttributeIndent::WriteConfigured(i.indent_size)
459                }
460
461                AttributeIndent::WriteSpaces(_) => {}
462                // .new_line() called when .with_attribute() was called at least once.
463                // The spaces should be used to indent
464                // Plan saved indent
465                AttributeIndent::Spaces(indent) => {
466                    self.state = AttributeIndent::WriteSpaces(indent)
467                }
468
469                AttributeIndent::WriteConfigured(_) => {}
470                // .new_line() called when .with_attribute() was called at least once.
471                // The configured indent characters should be used to indent
472                // Plan saved indent
473                AttributeIndent::Configured(indent) => {
474                    self.state = AttributeIndent::WriteConfigured(indent)
475                }
476            }
477            self.start_tag.push_newline();
478        };
479        self
480    }
481
482    /// Writes attribute and maintain indentation state
483    fn write_attr<'b>(&mut self, attr: Attribute<'b>) {
484        if let Some(i) = self.writer.indent.as_mut() {
485            // Save the indent that we should use next time when .new_line() be called
486            self.state = match self.state {
487                // Neither .new_line() or .with_attribute() yet called
488                // If newline inside attributes will be requested, we should indent them
489                // by the length of tag name and +1 for `<` and +1 for one space
490                AttributeIndent::NoneAttributesWritten => {
491                    self.start_tag.push_attribute(attr);
492                    AttributeIndent::Spaces(self.start_tag.name().as_ref().len() + 2)
493                }
494
495                // Indent was requested by previous call to .new_line(), write it
496                // New line was already written
497                AttributeIndent::WriteSpaces(indent) => {
498                    if self.spaces.len() < indent {
499                        self.spaces.resize(indent, b' ');
500                    }
501                    self.start_tag.push_indent(&self.spaces[..indent]);
502                    self.start_tag.push_attr(attr.into());
503                    AttributeIndent::Spaces(indent)
504                }
505                // .new_line() was not called, but .with_attribute() was.
506                // use the previously calculated indent
507                AttributeIndent::Spaces(indent) => {
508                    self.start_tag.push_attribute(attr);
509                    AttributeIndent::Spaces(indent)
510                }
511
512                // Indent was requested by previous call to .new_line(), write it
513                // New line was already written
514                AttributeIndent::WriteConfigured(indent) => {
515                    self.start_tag.push_indent(i.additional(indent));
516                    self.start_tag.push_attr(attr.into());
517                    AttributeIndent::Configured(indent)
518                }
519                // .new_line() was not called, but .with_attribute() was.
520                // use the previously calculated indent
521                AttributeIndent::Configured(indent) => {
522                    self.start_tag.push_attribute(attr);
523                    AttributeIndent::Configured(indent)
524                }
525            };
526        } else {
527            self.start_tag.push_attribute(attr);
528        }
529    }
530}
531
532impl<'a, W: Write> ElementWriter<'a, W> {
533    /// Write some text inside the current element.
534    pub fn write_text_content(self, text: BytesText) -> Result<&'a mut Writer<W>> {
535        self.writer
536            .write_event(Event::Start(self.start_tag.borrow()))?;
537        self.writer.write_event(Event::Text(text))?;
538        self.writer
539            .write_event(Event::End(self.start_tag.to_end()))?;
540        Ok(self.writer)
541    }
542
543    /// Write a CData event `<![CDATA[...]]>` inside the current element.
544    pub fn write_cdata_content(self, text: BytesCData) -> Result<&'a mut Writer<W>> {
545        self.writer
546            .write_event(Event::Start(self.start_tag.borrow()))?;
547        self.writer.write_event(Event::CData(text))?;
548        self.writer
549            .write_event(Event::End(self.start_tag.to_end()))?;
550        Ok(self.writer)
551    }
552
553    /// Write a processing instruction `<?...?>` inside the current element.
554    pub fn write_pi_content(self, text: BytesText) -> Result<&'a mut Writer<W>> {
555        self.writer
556            .write_event(Event::Start(self.start_tag.borrow()))?;
557        self.writer.write_event(Event::PI(text))?;
558        self.writer
559            .write_event(Event::End(self.start_tag.to_end()))?;
560        Ok(self.writer)
561    }
562
563    /// Write an empty (self-closing) tag.
564    pub fn write_empty(self) -> Result<&'a mut Writer<W>> {
565        self.writer.write_event(Event::Empty(self.start_tag))?;
566        Ok(self.writer)
567    }
568
569    /// Create a new scope for writing XML inside the current element.
570    pub fn write_inner_content<F, E>(self, closure: F) -> StdResult<&'a mut Writer<W>, E>
571    where
572        F: FnOnce(&mut Writer<W>) -> StdResult<(), E>,
573        E: From<Error>,
574    {
575        self.writer
576            .write_event(Event::Start(self.start_tag.borrow()))?;
577        closure(self.writer)?;
578        self.writer
579            .write_event(Event::End(self.start_tag.to_end()))?;
580        Ok(self.writer)
581    }
582}
583#[cfg(feature = "serialize")]
584struct ToFmtWrite<T>(pub T);
585
586#[cfg(feature = "serialize")]
587impl<T> std::fmt::Write for ToFmtWrite<T>
588where
589    T: std::io::Write,
590{
591    fn write_str(&mut self, s: &str) -> std::fmt::Result {
592        self.0.write_all(s.as_bytes()).map_err(|_| std::fmt::Error)
593    }
594}
595
596#[derive(Clone)]
597pub(crate) struct Indentation {
598    /// todo: this is an awkward fit as it has no impact on indentation logic, but it is
599    /// only applicable when an indentation exists. Potentially refactor later
600    should_line_break: bool,
601    /// The character code to be used for indentations (e.g. ` ` or `\t`)
602    indent_char: u8,
603    /// How many instances of the indent character ought to be used for each level of indentation
604    indent_size: usize,
605    /// Used as a cache for the bytes used for indentation
606    indents: Vec<u8>,
607    /// The current amount of indentation
608    current_indent_len: usize,
609}
610
611impl Indentation {
612    pub fn new(indent_char: u8, indent_size: usize) -> Self {
613        Self {
614            should_line_break: false,
615            indent_char,
616            indent_size,
617            indents: vec![indent_char; 128],
618            current_indent_len: 0, // invariant - needs to remain less than indents.len()
619        }
620    }
621
622    /// Increase indentation by one level
623    pub fn grow(&mut self) {
624        self.current_indent_len += self.indent_size;
625        self.ensure(self.current_indent_len);
626    }
627
628    /// Decrease indentation by one level. Do nothing, if level already zero
629    pub fn shrink(&mut self) {
630        self.current_indent_len = self.current_indent_len.saturating_sub(self.indent_size);
631    }
632
633    /// Returns indent string for current level
634    pub fn current(&self) -> &[u8] {
635        &self.indents[..self.current_indent_len]
636    }
637
638    /// Returns indent with current indent plus additional indent
639    pub fn additional(&mut self, additional_indent: usize) -> &[u8] {
640        let new_len = self.current_indent_len + additional_indent;
641        self.ensure(new_len);
642        &self.indents[..new_len]
643    }
644
645    fn ensure(&mut self, new_len: usize) {
646        if self.indents.len() < new_len {
647            self.indents.resize(new_len, self.indent_char);
648        }
649    }
650}
651
652#[cfg(test)]
653mod indentation {
654    use super::*;
655    use crate::events::*;
656    use pretty_assertions::assert_eq;
657
658    #[test]
659    fn self_closed() {
660        let mut buffer = Vec::new();
661        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
662
663        let tag = BytesStart::new("self-closed")
664            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
665        writer
666            .write_event(Event::Empty(tag))
667            .expect("write tag failed");
668
669        assert_eq!(
670            std::str::from_utf8(&buffer).unwrap(),
671            r#"<self-closed attr1="value1" attr2="value2"/>"#
672        );
673    }
674
675    #[test]
676    fn empty_paired() {
677        let mut buffer = Vec::new();
678        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
679
680        let start = BytesStart::new("paired")
681            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
682        let end = start.to_end();
683        writer
684            .write_event(Event::Start(start.clone()))
685            .expect("write start tag failed");
686        writer
687            .write_event(Event::End(end))
688            .expect("write end tag failed");
689
690        assert_eq!(
691            std::str::from_utf8(&buffer).unwrap(),
692            r#"<paired attr1="value1" attr2="value2">
693</paired>"#
694        );
695    }
696
697    #[test]
698    fn paired_with_inner() {
699        let mut buffer = Vec::new();
700        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
701
702        let start = BytesStart::new("paired")
703            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
704        let end = start.to_end();
705        let inner = BytesStart::new("inner");
706
707        writer
708            .write_event(Event::Start(start.clone()))
709            .expect("write start tag failed");
710        writer
711            .write_event(Event::Empty(inner))
712            .expect("write inner tag failed");
713        writer
714            .write_event(Event::End(end))
715            .expect("write end tag failed");
716
717        assert_eq!(
718            std::str::from_utf8(&buffer).unwrap(),
719            r#"<paired attr1="value1" attr2="value2">
720    <inner/>
721</paired>"#
722        );
723    }
724
725    #[test]
726    fn paired_with_text() {
727        let mut buffer = Vec::new();
728        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
729
730        let start = BytesStart::new("paired")
731            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
732        let end = start.to_end();
733        let text = BytesText::new("text");
734
735        writer
736            .write_event(Event::Start(start.clone()))
737            .expect("write start tag failed");
738        writer
739            .write_event(Event::Text(text))
740            .expect("write text failed");
741        writer
742            .write_event(Event::End(end))
743            .expect("write end tag failed");
744
745        assert_eq!(
746            std::str::from_utf8(&buffer).unwrap(),
747            r#"<paired attr1="value1" attr2="value2">text</paired>"#
748        );
749    }
750
751    #[test]
752    fn mixed_content() {
753        let mut buffer = Vec::new();
754        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
755
756        let start = BytesStart::new("paired")
757            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
758        let end = start.to_end();
759        let text = BytesText::new("text");
760        let inner = BytesStart::new("inner");
761
762        writer
763            .write_event(Event::Start(start.clone()))
764            .expect("write start tag failed");
765        writer
766            .write_event(Event::Text(text))
767            .expect("write text failed");
768        writer
769            .write_event(Event::Empty(inner))
770            .expect("write inner tag failed");
771        writer
772            .write_event(Event::End(end))
773            .expect("write end tag failed");
774
775        assert_eq!(
776            std::str::from_utf8(&buffer).unwrap(),
777            r#"<paired attr1="value1" attr2="value2">text<inner/>
778</paired>"#
779        );
780    }
781
782    #[test]
783    fn nested() {
784        let mut buffer = Vec::new();
785        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
786
787        let start = BytesStart::new("paired")
788            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
789        let end = start.to_end();
790        let inner = BytesStart::new("inner");
791
792        writer
793            .write_event(Event::Start(start.clone()))
794            .expect("write start 1 tag failed");
795        writer
796            .write_event(Event::Start(start.clone()))
797            .expect("write start 2 tag failed");
798        writer
799            .write_event(Event::Empty(inner))
800            .expect("write inner tag failed");
801        writer
802            .write_event(Event::End(end.clone()))
803            .expect("write end tag 2 failed");
804        writer
805            .write_event(Event::End(end))
806            .expect("write end tag 1 failed");
807
808        assert_eq!(
809            std::str::from_utf8(&buffer).unwrap(),
810            r#"<paired attr1="value1" attr2="value2">
811    <paired attr1="value1" attr2="value2">
812        <inner/>
813    </paired>
814</paired>"#
815        );
816    }
817
818    #[cfg(feature = "serialize")]
819    #[test]
820    fn serializable() {
821        #[derive(Serialize)]
822        struct Foo {
823            #[serde(rename = "@attribute")]
824            attribute: &'static str,
825
826            element: Bar,
827            list: Vec<&'static str>,
828
829            #[serde(rename = "$text")]
830            text: &'static str,
831
832            val: String,
833        }
834
835        #[derive(Serialize)]
836        struct Bar {
837            baz: usize,
838            bat: usize,
839        }
840
841        let mut buffer = Vec::new();
842        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
843
844        let content = Foo {
845            attribute: "attribute",
846            element: Bar { baz: 42, bat: 43 },
847            list: vec!["first element", "second element"],
848            text: "text",
849            val: "foo".to_owned(),
850        };
851
852        let start = BytesStart::new("paired")
853            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
854        let end = start.to_end();
855
856        writer
857            .write_event(Event::Start(start.clone()))
858            .expect("write start tag failed");
859        writer
860            .write_serializable("foo_element", &content)
861            .expect("write serializable inner contents failed");
862        writer
863            .write_event(Event::End(end))
864            .expect("write end tag failed");
865
866        assert_eq!(
867            std::str::from_utf8(&buffer).unwrap(),
868            r#"<paired attr1="value1" attr2="value2">
869    <foo_element attribute="attribute">
870        <element>
871            <baz>42</baz>
872            <bat>43</bat>
873        </element>
874        <list>first element</list>
875        <list>second element</list>
876        text
877        <val>foo</val>
878    </foo_element>
879</paired>"#
880        );
881    }
882
883    #[test]
884    fn element_writer_empty() {
885        let mut buffer = Vec::new();
886        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
887
888        writer
889            .create_element("empty")
890            .with_attribute(("attr1", "value1"))
891            .with_attribute(("attr2", "value2"))
892            .write_empty()
893            .expect("failure");
894
895        assert_eq!(
896            std::str::from_utf8(&buffer).unwrap(),
897            r#"<empty attr1="value1" attr2="value2"/>"#
898        );
899    }
900
901    #[test]
902    fn element_writer_text() {
903        let mut buffer = Vec::new();
904        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
905
906        writer
907            .create_element("paired")
908            .with_attribute(("attr1", "value1"))
909            .with_attribute(("attr2", "value2"))
910            .write_text_content(BytesText::new("text"))
911            .expect("failure");
912
913        assert_eq!(
914            std::str::from_utf8(&buffer).unwrap(),
915            r#"<paired attr1="value1" attr2="value2">text</paired>"#
916        );
917    }
918
919    #[test]
920    fn element_writer_nested() {
921        let mut buffer = Vec::new();
922        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
923
924        writer
925            .create_element("outer")
926            .with_attribute(("attr1", "value1"))
927            .with_attribute(("attr2", "value2"))
928            .write_inner_content::<_, Error>(|writer| {
929                let fruits = ["apple", "orange", "banana"];
930                for (quant, item) in fruits.iter().enumerate() {
931                    writer
932                        .create_element("fruit")
933                        .with_attribute(("quantity", quant.to_string().as_str()))
934                        .write_text_content(BytesText::new(item))?;
935                }
936                writer
937                    .create_element("inner")
938                    .write_inner_content(|writer| {
939                        writer.create_element("empty").write_empty().map(|_| ())
940                    })?;
941
942                Ok(())
943            })
944            .expect("failure");
945
946        assert_eq!(
947            std::str::from_utf8(&buffer).unwrap(),
948            r#"<outer attr1="value1" attr2="value2">
949    <fruit quantity="0">apple</fruit>
950    <fruit quantity="1">orange</fruit>
951    <fruit quantity="2">banana</fruit>
952    <inner>
953        <empty/>
954    </inner>
955</outer>"#
956        );
957    }
958
959    mod in_attributes {
960        use super::*;
961        use pretty_assertions::assert_eq;
962
963        #[test]
964        fn newline_first() {
965            let mut buffer = Vec::new();
966            let mut writer = Writer::new_with_indent(&mut buffer, b'_', 1);
967
968            writer
969                .create_element("element")
970                .new_line()
971                .with_attribute(("first", "1"))
972                .with_attribute(("second", "2"))
973                .new_line()
974                .with_attribute(("third", "3"))
975                .with_attribute(("fourth", "4"))
976                .write_empty()
977                .expect("write tag failed");
978
979            assert_eq!(
980                std::str::from_utf8(&buffer).unwrap(),
981                "<element\
982                    \n_first=\"1\" second=\"2\"\
983                    \n_third=\"3\" fourth=\"4\"/>"
984            );
985        }
986
987        #[test]
988        fn newline_inside() {
989            let mut buffer = Vec::new();
990            let mut writer = Writer::new_with_indent(&mut buffer, b'_', 1);
991
992            writer
993                .create_element("element")
994                .with_attribute(("first", "1"))
995                .with_attribute(("second", "2"))
996                .new_line()
997                .with_attribute(("third", "3"))
998                .with_attribute(("fourth", "4"))
999                .write_empty()
1000                .expect("write tag failed");
1001
1002            assert_eq!(
1003                std::str::from_utf8(&buffer).unwrap(),
1004                "<element first=\"1\" second=\"2\"\
1005                \n         third=\"3\" fourth=\"4\"/>"
1006            );
1007        }
1008
1009        #[test]
1010        fn newline_last() {
1011            let mut buffer = Vec::new();
1012            let mut writer = Writer::new_with_indent(&mut buffer, b'_', 1);
1013
1014            writer
1015                .create_element("element")
1016                .new_line()
1017                .with_attribute(("first", "1"))
1018                .with_attribute(("second", "2"))
1019                .new_line()
1020                .with_attribute(("third", "3"))
1021                .with_attribute(("fourth", "4"))
1022                .new_line()
1023                .write_empty()
1024                .expect("write tag failed");
1025
1026            writer
1027                .create_element("element")
1028                .with_attribute(("first", "1"))
1029                .with_attribute(("second", "2"))
1030                .new_line()
1031                .with_attribute(("third", "3"))
1032                .with_attribute(("fourth", "4"))
1033                .new_line()
1034                .write_empty()
1035                .expect("write tag failed");
1036
1037            assert_eq!(
1038                std::str::from_utf8(&buffer).unwrap(),
1039                "<element\
1040                    \n_first=\"1\" second=\"2\"\
1041                    \n_third=\"3\" fourth=\"4\"\
1042                \n/>\
1043                \n<element first=\"1\" second=\"2\"\
1044                \n         third=\"3\" fourth=\"4\"\
1045                \n/>"
1046            );
1047        }
1048
1049        #[test]
1050        fn newline_twice() {
1051            let mut buffer = Vec::new();
1052            let mut writer = Writer::new_with_indent(&mut buffer, b'_', 1);
1053
1054            writer
1055                .create_element("element")
1056                .new_line()
1057                .new_line()
1058                .write_empty()
1059                .expect("write tag failed");
1060
1061            writer
1062                .create_element("element")
1063                .with_attribute(("first", "1"))
1064                .new_line()
1065                .new_line()
1066                .with_attribute(("second", "2"))
1067                .write_empty()
1068                .expect("write tag failed");
1069
1070            assert_eq!(
1071                std::str::from_utf8(&buffer).unwrap(),
1072                r#"<element
1073
1074/>
1075<element first="1"
1076
1077         second="2"/>"#
1078            );
1079        }
1080
1081        #[test]
1082        fn without_indent() {
1083            let mut buffer = Vec::new();
1084            let mut writer = Writer::new(&mut buffer);
1085
1086            writer
1087                .create_element("element")
1088                .new_line()
1089                .new_line()
1090                .write_empty()
1091                .expect("write tag failed");
1092
1093            writer
1094                .create_element("element")
1095                .with_attribute(("first", "1"))
1096                .new_line()
1097                .new_line()
1098                .with_attribute(("second", "2"))
1099                .write_empty()
1100                .expect("write tag failed");
1101
1102            assert_eq!(
1103                std::str::from_utf8(&buffer).unwrap(),
1104                r#"<element/><element first="1" second="2"/>"#
1105            );
1106        }
1107
1108        #[test]
1109        fn long_element_name() {
1110            let mut buffer = Vec::new();
1111            let mut writer = Writer::new_with_indent(&mut buffer, b't', 1);
1112
1113            writer
1114                .create_element(String::from("x").repeat(128).as_str())
1115                .with_attribute(("first", "1"))
1116                .new_line()
1117                .with_attribute(("second", "2"))
1118                .write_empty()
1119                .expect("Problem with indentation reference");
1120        }
1121    }
1122
1123    mod in_attributes_multi {
1124        use super::*;
1125        use pretty_assertions::assert_eq;
1126
1127        #[test]
1128        fn newline_first() {
1129            let mut buffer = Vec::new();
1130            let mut writer = Writer::new_with_indent(&mut buffer, b'_', 1);
1131
1132            writer
1133                .create_element("element")
1134                .new_line()
1135                .with_attributes([("first", "1"), ("second", "2")])
1136                .new_line()
1137                .with_attributes([("third", "3"), ("fourth", "4")])
1138                .write_empty()
1139                .expect("write tag failed");
1140
1141            assert_eq!(
1142                std::str::from_utf8(&buffer).unwrap(),
1143                "<element\
1144                    \n_first=\"1\" second=\"2\"\
1145                    \n_third=\"3\" fourth=\"4\"/>"
1146            );
1147        }
1148
1149        #[test]
1150        fn newline_inside() {
1151            let mut buffer = Vec::new();
1152            let mut writer = Writer::new_with_indent(&mut buffer, b'_', 1);
1153
1154            writer
1155                .create_element("element")
1156                .with_attributes([("first", "1"), ("second", "2")])
1157                .new_line()
1158                .with_attributes([("third", "3"), ("fourth", "4")])
1159                .write_empty()
1160                .expect("write tag failed");
1161
1162            assert_eq!(
1163                std::str::from_utf8(&buffer).unwrap(),
1164                r#"<element first="1" second="2"
1165         third="3" fourth="4"/>"#
1166            );
1167        }
1168
1169        #[test]
1170        fn newline_last() {
1171            let mut buffer = Vec::new();
1172            let mut writer = Writer::new_with_indent(&mut buffer, b'_', 1);
1173
1174            writer
1175                .create_element("element")
1176                .new_line()
1177                .with_attributes([("first", "1"), ("second", "2")])
1178                .new_line()
1179                .with_attributes([("third", "3"), ("fourth", "4")])
1180                .new_line()
1181                .write_empty()
1182                .expect("write tag failed");
1183
1184            writer
1185                .create_element("element")
1186                .with_attributes([("first", "1"), ("second", "2")])
1187                .new_line()
1188                .with_attributes([("third", "3"), ("fourth", "4")])
1189                .new_line()
1190                .write_empty()
1191                .expect("write tag failed");
1192
1193            assert_eq!(
1194                std::str::from_utf8(&buffer).unwrap(),
1195                "<element\
1196                    \n_first=\"1\" second=\"2\"\
1197                    \n_third=\"3\" fourth=\"4\"\
1198                \n/>\
1199                \n<element first=\"1\" second=\"2\"\
1200                \n         third=\"3\" fourth=\"4\"\
1201                \n/>"
1202            );
1203        }
1204    }
1205}