quick_xml/
writer.rs

1//! Contains high-level interface for an events-based XML emitter.
2
3use std::io::Write;
4use std::result::Result as StdResult;
5
6use crate::encoding::UTF8_BOM;
7use crate::errors::{Error, Result};
8use crate::events::{attributes::Attribute, BytesCData, BytesStart, BytesText, Event};
9
10#[cfg(feature = "async-tokio")]
11mod async_tokio;
12
13/// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] or [`tokio::io::AsyncWrite`] implementor.
14#[cfg(feature = "serialize")]
15use {crate::de::DeError, serde::Serialize};
16
17/// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] implementor.
18///
19/// # Examples
20///
21/// ```
22/// # use pretty_assertions::assert_eq;
23/// use quick_xml::events::{Event, BytesEnd, BytesStart};
24/// use quick_xml::reader::Reader;
25/// use quick_xml::writer::Writer;
26/// use std::io::Cursor;
27///
28/// let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
29/// let mut reader = Reader::from_str(xml);
30/// reader.trim_text(true);
31/// let mut writer = Writer::new(Cursor::new(Vec::new()));
32/// loop {
33///     match reader.read_event() {
34///         Ok(Event::Start(e)) if e.name().as_ref() == b"this_tag" => {
35///
36///             // crates a new element ... alternatively we could reuse `e` by calling
37///             // `e.into_owned()`
38///             let mut elem = BytesStart::new("my_elem");
39///
40///             // collect existing attributes
41///             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
42///
43///             // copy existing attributes, adds a new my-key="some value" attribute
44///             elem.push_attribute(("my-key", "some value"));
45///
46///             // writes the event to the writer
47///             assert!(writer.write_event(Event::Start(elem)).is_ok());
48///         },
49///         Ok(Event::End(e)) if e.name().as_ref() == b"this_tag" => {
50///             assert!(writer.write_event(Event::End(BytesEnd::new("my_elem"))).is_ok());
51///         },
52///         Ok(Event::Eof) => break,
53///         // we can either move or borrow the event to write, depending on your use-case
54///         Ok(e) => assert!(writer.write_event(e).is_ok()),
55///         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
56///     }
57/// }
58///
59/// let result = writer.into_inner().into_inner();
60/// let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
61/// assert_eq!(result, expected.as_bytes());
62/// ```
63#[derive(Clone)]
64pub struct Writer<W> {
65    /// underlying writer
66    writer: W,
67    indent: Option<Indentation>,
68}
69
70impl<W> Writer<W> {
71    /// Creates a `Writer` from a generic writer.
72    pub fn new(inner: W) -> Writer<W> {
73        Writer {
74            writer: inner,
75            indent: None,
76        }
77    }
78
79    /// Creates a `Writer` with configured indents from a generic writer.
80    pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer<W> {
81        Writer {
82            writer: inner,
83            indent: Some(Indentation::new(indent_char, indent_size)),
84        }
85    }
86
87    /// Consumes this `Writer`, returning the underlying writer.
88    pub fn into_inner(self) -> W {
89        self.writer
90    }
91
92    /// Get a mutable reference to the underlying writer.
93    pub fn get_mut(&mut self) -> &mut W {
94        &mut self.writer
95    }
96
97    /// Get a reference to the underlying writer.
98    pub fn get_ref(&self) -> &W {
99        &self.writer
100    }
101
102    /// Provides a simple, high-level API for writing XML elements.
103    ///
104    /// Returns an [`ElementWriter`] that simplifies setting attributes and writing
105    /// content inside the element.
106    ///
107    /// # Example
108    ///
109    /// ```
110    /// # use quick_xml::Result;
111    /// # fn main() -> Result<()> {
112    /// use quick_xml::events::{BytesStart, BytesText, Event};
113    /// use quick_xml::writer::Writer;
114    /// use quick_xml::Error;
115    /// use std::io::Cursor;
116    ///
117    /// let mut writer = Writer::new(Cursor::new(Vec::new()));
118    ///
119    /// // writes <tag attr1="value1"/>
120    /// writer.create_element("tag")
121    ///     .with_attribute(("attr1", "value1"))  // chain `with_attribute()` calls to add many attributes
122    ///     .write_empty()?;
123    ///
124    /// // writes <tag attr1="value1" attr2="value2">with some text inside</tag>
125    /// writer.create_element("tag")
126    ///     .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter())  // or add attributes from an iterator
127    ///     .write_text_content(BytesText::new("with some text inside"))?;
128    ///
129    /// // writes <tag><fruit quantity="0">apple</fruit><fruit quantity="1">orange</fruit></tag>
130    /// writer.create_element("tag")
131    ///     // We need to provide error type, because it is not named somewhere explicitly
132    ///     .write_inner_content::<_, Error>(|writer| {
133    ///         let fruits = ["apple", "orange"];
134    ///         for (quant, item) in fruits.iter().enumerate() {
135    ///             writer
136    ///                 .create_element("fruit")
137    ///                 .with_attribute(("quantity", quant.to_string().as_str()))
138    ///                 .write_text_content(BytesText::new(item))?;
139    ///         }
140    ///         Ok(())
141    ///     })?;
142    /// # Ok(())
143    /// # }
144    /// ```
145    #[must_use]
146    pub fn create_element<'a, N>(&'a mut self, name: &'a N) -> ElementWriter<W>
147    where
148        N: 'a + AsRef<str> + ?Sized,
149    {
150        ElementWriter {
151            writer: self,
152            start_tag: BytesStart::new(name.as_ref()),
153        }
154    }
155}
156
157impl<W: Write> Writer<W> {
158    /// Write a [Byte-Order-Mark] character to the document.
159    ///
160    /// # Example
161    ///
162    /// ```rust
163    /// # use quick_xml::Result;
164    /// # fn main() -> Result<()> {
165    /// use quick_xml::events::{BytesStart, BytesText, Event};
166    /// use quick_xml::writer::Writer;
167    /// use quick_xml::Error;
168    /// use std::io::Cursor;
169    ///
170    /// let mut buffer = Vec::new();
171    /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
172    ///
173    /// writer.write_bom()?;
174    /// writer
175    ///     .create_element("empty")
176    ///     .with_attribute(("attr1", "value1"))
177    ///     .write_empty()
178    ///     .expect("failure");
179    ///
180    /// assert_eq!(
181    ///     std::str::from_utf8(&buffer).unwrap(),
182    ///     "\u{FEFF}<empty attr1=\"value1\"/>"
183    /// );
184    /// # Ok(())
185    /// # }
186    /// ```
187    /// [Byte-Order-Mark]: https://unicode.org/faq/utf_bom.html#BOM
188    pub fn write_bom(&mut self) -> Result<()> {
189        self.write(UTF8_BOM)
190    }
191
192    /// Writes the given event to the underlying writer.
193    pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<()> {
194        let mut next_should_line_break = true;
195        let result = match *event.as_ref() {
196            Event::Start(ref e) => {
197                let result = self.write_wrapped(b"<", e, b">");
198                if let Some(i) = self.indent.as_mut() {
199                    i.grow();
200                }
201                result
202            }
203            Event::End(ref e) => {
204                if let Some(i) = self.indent.as_mut() {
205                    i.shrink();
206                }
207                self.write_wrapped(b"</", e, b">")
208            }
209            Event::Empty(ref e) => self.write_wrapped(b"<", e, b"/>"),
210            Event::Text(ref e) => {
211                next_should_line_break = false;
212                self.write(e)
213            }
214            Event::Comment(ref e) => self.write_wrapped(b"<!--", e, b"-->"),
215            Event::CData(ref e) => {
216                next_should_line_break = false;
217                self.write(b"<![CDATA[")?;
218                self.write(e)?;
219                self.write(b"]]>")
220            }
221            Event::Decl(ref e) => self.write_wrapped(b"<?", e, b"?>"),
222            Event::PI(ref e) => self.write_wrapped(b"<?", e, b"?>"),
223            Event::DocType(ref e) => self.write_wrapped(b"<!DOCTYPE ", e, b">"),
224            Event::Eof => Ok(()),
225        };
226        if let Some(i) = self.indent.as_mut() {
227            i.should_line_break = next_should_line_break;
228        }
229        result
230    }
231
232    /// Writes bytes
233    #[inline]
234    pub(crate) fn write(&mut self, value: &[u8]) -> Result<()> {
235        self.writer.write_all(value).map_err(Into::into)
236    }
237
238    #[inline]
239    fn write_wrapped(&mut self, before: &[u8], value: &[u8], after: &[u8]) -> Result<()> {
240        if let Some(ref i) = self.indent {
241            if i.should_line_break {
242                self.writer.write_all(b"\n")?;
243                self.writer.write_all(i.current())?;
244            }
245        }
246        self.write(before)?;
247        self.write(value)?;
248        self.write(after)?;
249        Ok(())
250    }
251
252    /// Manually write a newline and indentation at the proper level.
253    ///
254    /// This can be used when the heuristic to line break and indent after any
255    /// [`Event`] apart from [`Text`] fails such as when a [`Start`] occurs directly
256    /// after [`Text`].
257    ///
258    /// This method will do nothing if `Writer` was not constructed with [`new_with_indent`].
259    ///
260    /// [`Text`]: Event::Text
261    /// [`Start`]: Event::Start
262    /// [`new_with_indent`]: Self::new_with_indent
263    pub fn write_indent(&mut self) -> Result<()> {
264        if let Some(ref i) = self.indent {
265            self.writer.write_all(b"\n")?;
266            self.writer.write_all(i.current())?;
267        }
268        Ok(())
269    }
270
271    /// Write an arbitrary serializable type
272    ///
273    /// Note: If you are attempting to write XML in a non-UTF-8 encoding, this may not
274    /// be safe to use. Rust basic types assume UTF-8 encodings.
275    ///
276    /// ```rust
277    /// # use pretty_assertions::assert_eq;
278    /// # use serde::Serialize;
279    /// # use quick_xml::events::{BytesStart, Event};
280    /// # use quick_xml::writer::Writer;
281    /// # use quick_xml::DeError;
282    /// # fn main() -> Result<(), DeError> {
283    /// #[derive(Debug, PartialEq, Serialize)]
284    /// struct MyData {
285    ///     question: String,
286    ///     answer: u32,
287    /// }
288    ///
289    /// let data = MyData {
290    ///     question: "The Ultimate Question of Life, the Universe, and Everything".into(),
291    ///     answer: 42,
292    /// };
293    ///
294    /// let mut buffer = Vec::new();
295    /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
296    ///
297    /// let start = BytesStart::new("root");
298    /// let end = start.to_end();
299    ///
300    /// writer.write_event(Event::Start(start.clone()))?;
301    /// writer.write_serializable("my_data", &data)?;
302    /// writer.write_event(Event::End(end))?;
303    ///
304    /// assert_eq!(
305    ///     std::str::from_utf8(&buffer)?,
306    ///     r#"<root>
307    ///     <my_data>
308    ///         <question>The Ultimate Question of Life, the Universe, and Everything</question>
309    ///         <answer>42</answer>
310    ///     </my_data>
311    /// </root>"#
312    /// );
313    /// # Ok(())
314    /// # }
315    /// ```
316    #[cfg(feature = "serialize")]
317    pub fn write_serializable<T: Serialize>(
318        &mut self,
319        tag_name: &str,
320        content: &T,
321    ) -> std::result::Result<(), DeError> {
322        use crate::se::{Indent, Serializer};
323
324        self.write_indent()?;
325        let mut fmt = ToFmtWrite(&mut self.writer);
326        let mut serializer = Serializer::with_root(&mut fmt, Some(tag_name))?;
327
328        if let Some(indent) = &mut self.indent {
329            serializer.set_indent(Indent::Borrow(indent));
330        }
331
332        content.serialize(serializer)?;
333
334        Ok(())
335    }
336}
337
338/// A struct to write an element. Contains methods to add attributes and inner
339/// elements to the element
340pub struct ElementWriter<'a, W> {
341    writer: &'a mut Writer<W>,
342    start_tag: BytesStart<'a>,
343}
344
345impl<'a, W> ElementWriter<'a, W> {
346    /// Adds an attribute to this element.
347    pub fn with_attribute<'b, I>(mut self, attr: I) -> Self
348    where
349        I: Into<Attribute<'b>>,
350    {
351        self.start_tag.push_attribute(attr);
352        self
353    }
354
355    /// Add additional attributes to this element using an iterator.
356    ///
357    /// The yielded items must be convertible to [`Attribute`] using `Into`.
358    pub fn with_attributes<'b, I>(mut self, attributes: I) -> Self
359    where
360        I: IntoIterator,
361        I::Item: Into<Attribute<'b>>,
362    {
363        self.start_tag.extend_attributes(attributes);
364        self
365    }
366}
367
368impl<'a, W: Write> ElementWriter<'a, W> {
369    /// Write some text inside the current element.
370    pub fn write_text_content(self, text: BytesText) -> Result<&'a mut Writer<W>> {
371        self.writer
372            .write_event(Event::Start(self.start_tag.borrow()))?;
373        self.writer.write_event(Event::Text(text))?;
374        self.writer
375            .write_event(Event::End(self.start_tag.to_end()))?;
376        Ok(self.writer)
377    }
378
379    /// Write a CData event `<![CDATA[...]]>` inside the current element.
380    pub fn write_cdata_content(self, text: BytesCData) -> Result<&'a mut Writer<W>> {
381        self.writer
382            .write_event(Event::Start(self.start_tag.borrow()))?;
383        self.writer.write_event(Event::CData(text))?;
384        self.writer
385            .write_event(Event::End(self.start_tag.to_end()))?;
386        Ok(self.writer)
387    }
388
389    /// Write a processing instruction `<?...?>` inside the current element.
390    pub fn write_pi_content(self, text: BytesText) -> Result<&'a mut Writer<W>> {
391        self.writer
392            .write_event(Event::Start(self.start_tag.borrow()))?;
393        self.writer.write_event(Event::PI(text))?;
394        self.writer
395            .write_event(Event::End(self.start_tag.to_end()))?;
396        Ok(self.writer)
397    }
398
399    /// Write an empty (self-closing) tag.
400    pub fn write_empty(self) -> Result<&'a mut Writer<W>> {
401        self.writer.write_event(Event::Empty(self.start_tag))?;
402        Ok(self.writer)
403    }
404
405    /// Create a new scope for writing XML inside the current element.
406    pub fn write_inner_content<F, E>(self, closure: F) -> StdResult<&'a mut Writer<W>, E>
407    where
408        F: FnOnce(&mut Writer<W>) -> StdResult<(), E>,
409        E: From<Error>,
410    {
411        self.writer
412            .write_event(Event::Start(self.start_tag.borrow()))?;
413        closure(self.writer)?;
414        self.writer
415            .write_event(Event::End(self.start_tag.to_end()))?;
416        Ok(self.writer)
417    }
418}
419#[cfg(feature = "serialize")]
420struct ToFmtWrite<T>(pub T);
421
422#[cfg(feature = "serialize")]
423impl<T> std::fmt::Write for ToFmtWrite<T>
424where
425    T: std::io::Write,
426{
427    fn write_str(&mut self, s: &str) -> std::fmt::Result {
428        self.0.write_all(s.as_bytes()).map_err(|_| std::fmt::Error)
429    }
430}
431
432#[derive(Clone)]
433pub(crate) struct Indentation {
434    /// todo: this is an awkward fit as it has no impact on indentation logic, but it is
435    /// only applicable when an indentation exists. Potentially refactor later
436    should_line_break: bool,
437    /// The character code to be used for indentations (e.g. ` ` or `\t`)
438    indent_char: u8,
439    /// How many instances of the indent character ought to be used for each level of indentation
440    indent_size: usize,
441    /// Used as a cache for the bytes used for indentation
442    indents: Vec<u8>,
443    /// The current amount of indentation
444    current_indent_len: usize,
445}
446
447impl Indentation {
448    pub fn new(indent_char: u8, indent_size: usize) -> Self {
449        Self {
450            should_line_break: false,
451            indent_char,
452            indent_size,
453            indents: vec![indent_char; 128],
454            current_indent_len: 0, // invariant - needs to remain less than indents.len()
455        }
456    }
457
458    /// Increase indentation by one level
459    pub fn grow(&mut self) {
460        self.current_indent_len += self.indent_size;
461        if self.current_indent_len > self.indents.len() {
462            self.indents
463                .resize(self.current_indent_len, self.indent_char);
464        }
465    }
466
467    /// Decrease indentation by one level. Do nothing, if level already zero
468    pub fn shrink(&mut self) {
469        self.current_indent_len = self.current_indent_len.saturating_sub(self.indent_size);
470    }
471
472    /// Returns indent string for current level
473    pub fn current(&self) -> &[u8] {
474        &self.indents[..self.current_indent_len]
475    }
476}
477
478#[cfg(test)]
479mod indentation {
480    use super::*;
481    use crate::events::*;
482    use pretty_assertions::assert_eq;
483
484    #[test]
485    fn self_closed() {
486        let mut buffer = Vec::new();
487        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
488
489        let tag = BytesStart::new("self-closed")
490            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
491        writer
492            .write_event(Event::Empty(tag))
493            .expect("write tag failed");
494
495        assert_eq!(
496            std::str::from_utf8(&buffer).unwrap(),
497            r#"<self-closed attr1="value1" attr2="value2"/>"#
498        );
499    }
500
501    #[test]
502    fn empty_paired() {
503        let mut buffer = Vec::new();
504        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
505
506        let start = BytesStart::new("paired")
507            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
508        let end = start.to_end();
509        writer
510            .write_event(Event::Start(start.clone()))
511            .expect("write start tag failed");
512        writer
513            .write_event(Event::End(end))
514            .expect("write end tag failed");
515
516        assert_eq!(
517            std::str::from_utf8(&buffer).unwrap(),
518            r#"<paired attr1="value1" attr2="value2">
519</paired>"#
520        );
521    }
522
523    #[test]
524    fn paired_with_inner() {
525        let mut buffer = Vec::new();
526        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
527
528        let start = BytesStart::new("paired")
529            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
530        let end = start.to_end();
531        let inner = BytesStart::new("inner");
532
533        writer
534            .write_event(Event::Start(start.clone()))
535            .expect("write start tag failed");
536        writer
537            .write_event(Event::Empty(inner))
538            .expect("write inner tag failed");
539        writer
540            .write_event(Event::End(end))
541            .expect("write end tag failed");
542
543        assert_eq!(
544            std::str::from_utf8(&buffer).unwrap(),
545            r#"<paired attr1="value1" attr2="value2">
546    <inner/>
547</paired>"#
548        );
549    }
550
551    #[test]
552    fn paired_with_text() {
553        let mut buffer = Vec::new();
554        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
555
556        let start = BytesStart::new("paired")
557            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
558        let end = start.to_end();
559        let text = BytesText::new("text");
560
561        writer
562            .write_event(Event::Start(start.clone()))
563            .expect("write start tag failed");
564        writer
565            .write_event(Event::Text(text))
566            .expect("write text failed");
567        writer
568            .write_event(Event::End(end))
569            .expect("write end tag failed");
570
571        assert_eq!(
572            std::str::from_utf8(&buffer).unwrap(),
573            r#"<paired attr1="value1" attr2="value2">text</paired>"#
574        );
575    }
576
577    #[test]
578    fn mixed_content() {
579        let mut buffer = Vec::new();
580        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
581
582        let start = BytesStart::new("paired")
583            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
584        let end = start.to_end();
585        let text = BytesText::new("text");
586        let inner = BytesStart::new("inner");
587
588        writer
589            .write_event(Event::Start(start.clone()))
590            .expect("write start tag failed");
591        writer
592            .write_event(Event::Text(text))
593            .expect("write text failed");
594        writer
595            .write_event(Event::Empty(inner))
596            .expect("write inner tag failed");
597        writer
598            .write_event(Event::End(end))
599            .expect("write end tag failed");
600
601        assert_eq!(
602            std::str::from_utf8(&buffer).unwrap(),
603            r#"<paired attr1="value1" attr2="value2">text<inner/>
604</paired>"#
605        );
606    }
607
608    #[test]
609    fn nested() {
610        let mut buffer = Vec::new();
611        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
612
613        let start = BytesStart::new("paired")
614            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
615        let end = start.to_end();
616        let inner = BytesStart::new("inner");
617
618        writer
619            .write_event(Event::Start(start.clone()))
620            .expect("write start 1 tag failed");
621        writer
622            .write_event(Event::Start(start.clone()))
623            .expect("write start 2 tag failed");
624        writer
625            .write_event(Event::Empty(inner))
626            .expect("write inner tag failed");
627        writer
628            .write_event(Event::End(end.clone()))
629            .expect("write end tag 2 failed");
630        writer
631            .write_event(Event::End(end))
632            .expect("write end tag 1 failed");
633
634        assert_eq!(
635            std::str::from_utf8(&buffer).unwrap(),
636            r#"<paired attr1="value1" attr2="value2">
637    <paired attr1="value1" attr2="value2">
638        <inner/>
639    </paired>
640</paired>"#
641        );
642    }
643
644    #[cfg(feature = "serialize")]
645    #[test]
646    fn serializable() {
647        #[derive(Serialize)]
648        struct Foo {
649            #[serde(rename = "@attribute")]
650            attribute: &'static str,
651
652            element: Bar,
653            list: Vec<&'static str>,
654
655            #[serde(rename = "$text")]
656            text: &'static str,
657
658            val: String,
659        }
660
661        #[derive(Serialize)]
662        struct Bar {
663            baz: usize,
664            bat: usize,
665        }
666
667        let mut buffer = Vec::new();
668        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
669
670        let content = Foo {
671            attribute: "attribute",
672            element: Bar { baz: 42, bat: 43 },
673            list: vec!["first element", "second element"],
674            text: "text",
675            val: "foo".to_owned(),
676        };
677
678        let start = BytesStart::new("paired")
679            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
680        let end = start.to_end();
681
682        writer
683            .write_event(Event::Start(start.clone()))
684            .expect("write start tag failed");
685        writer
686            .write_serializable("foo_element", &content)
687            .expect("write serializable inner contents failed");
688        writer
689            .write_event(Event::End(end))
690            .expect("write end tag failed");
691
692        assert_eq!(
693            std::str::from_utf8(&buffer).unwrap(),
694            r#"<paired attr1="value1" attr2="value2">
695    <foo_element attribute="attribute">
696        <element>
697            <baz>42</baz>
698            <bat>43</bat>
699        </element>
700        <list>first element</list>
701        <list>second element</list>
702        text
703        <val>foo</val>
704    </foo_element>
705</paired>"#
706        );
707    }
708
709    #[test]
710    fn element_writer_empty() {
711        let mut buffer = Vec::new();
712        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
713
714        writer
715            .create_element("empty")
716            .with_attribute(("attr1", "value1"))
717            .with_attribute(("attr2", "value2"))
718            .write_empty()
719            .expect("failure");
720
721        assert_eq!(
722            std::str::from_utf8(&buffer).unwrap(),
723            r#"<empty attr1="value1" attr2="value2"/>"#
724        );
725    }
726
727    #[test]
728    fn element_writer_text() {
729        let mut buffer = Vec::new();
730        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
731
732        writer
733            .create_element("paired")
734            .with_attribute(("attr1", "value1"))
735            .with_attribute(("attr2", "value2"))
736            .write_text_content(BytesText::new("text"))
737            .expect("failure");
738
739        assert_eq!(
740            std::str::from_utf8(&buffer).unwrap(),
741            r#"<paired attr1="value1" attr2="value2">text</paired>"#
742        );
743    }
744
745    #[test]
746    fn element_writer_nested() {
747        let mut buffer = Vec::new();
748        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
749
750        writer
751            .create_element("outer")
752            .with_attribute(("attr1", "value1"))
753            .with_attribute(("attr2", "value2"))
754            .write_inner_content::<_, Error>(|writer| {
755                let fruits = ["apple", "orange", "banana"];
756                for (quant, item) in fruits.iter().enumerate() {
757                    writer
758                        .create_element("fruit")
759                        .with_attribute(("quantity", quant.to_string().as_str()))
760                        .write_text_content(BytesText::new(item))?;
761                }
762                writer
763                    .create_element("inner")
764                    .write_inner_content(|writer| {
765                        writer.create_element("empty").write_empty().map(|_| ())
766                    })?;
767
768                Ok(())
769            })
770            .expect("failure");
771
772        assert_eq!(
773            std::str::from_utf8(&buffer).unwrap(),
774            r#"<outer attr1="value1" attr2="value2">
775    <fruit quantity="0">apple</fruit>
776    <fruit quantity="1">orange</fruit>
777    <fruit quantity="2">banana</fruit>
778    <inner>
779        <empty/>
780    </inner>
781</outer>"#
782        );
783    }
784}