quick_xml/se/
mod.rs

1//! Module to handle custom serde `Serializer`
2
3/// Implements writing primitives to the underlying writer.
4/// Implementor must provide `write_str(self, &str) -> Result<(), DeError>` method
5macro_rules! write_primitive {
6    ($method:ident ( $ty:ty )) => {
7        fn $method(mut self, value: $ty) -> Result<Self::Ok, Self::Error> {
8            self.write_fmt(format_args!("{}", value))?;
9            Ok(self.writer)
10        }
11    };
12    () => {
13        fn serialize_bool(mut self, value: bool) -> Result<Self::Ok, Self::Error> {
14            self.write_str(if value { "true" } else { "false" })?;
15            Ok(self.writer)
16        }
17
18        write_primitive!(serialize_i8(i8));
19        write_primitive!(serialize_i16(i16));
20        write_primitive!(serialize_i32(i32));
21        write_primitive!(serialize_i64(i64));
22
23        write_primitive!(serialize_u8(u8));
24        write_primitive!(serialize_u16(u16));
25        write_primitive!(serialize_u32(u32));
26        write_primitive!(serialize_u64(u64));
27
28        write_primitive!(serialize_i128(i128));
29        write_primitive!(serialize_u128(u128));
30
31        write_primitive!(serialize_f32(f32));
32        write_primitive!(serialize_f64(f64));
33
34        fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
35            self.serialize_str(value.encode_utf8(&mut [0u8; 4]))
36        }
37
38        fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
39            //TODO: customization point - allow user to decide how to encode bytes
40            Err(Self::Error::Unsupported(
41                "`serialize_bytes` not supported yet".into(),
42            ))
43        }
44
45        fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
46            Ok(self.writer)
47        }
48
49        fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
50            value.serialize(self)
51        }
52
53        fn serialize_unit_variant(
54            self,
55            _name: &'static str,
56            _variant_index: u32,
57            variant: &'static str,
58        ) -> Result<Self::Ok, Self::Error> {
59            self.serialize_str(variant)
60        }
61
62        fn serialize_newtype_struct<T: ?Sized + Serialize>(
63            self,
64            _name: &'static str,
65            value: &T,
66        ) -> Result<Self::Ok, Self::Error> {
67            value.serialize(self)
68        }
69    };
70}
71
72////////////////////////////////////////////////////////////////////////////////////////////////////
73
74mod content;
75mod element;
76pub(crate) mod key;
77pub(crate) mod simple_type;
78mod text;
79
80use self::content::ContentSerializer;
81use self::element::{ElementSerializer, Map, Struct, Tuple};
82use crate::de::TEXT_KEY;
83use crate::writer::{Indentation, ToFmtWrite};
84use serde::ser::{self, Serialize};
85use std::fmt::Write;
86use std::str::from_utf8;
87
88pub use self::simple_type::SimpleTypeSerializer;
89pub use crate::errors::serialize::SeError;
90
91/// Serialize struct into a `Write`r.
92///
93/// Returns the classification of the last written type.
94///
95/// # Examples
96///
97/// ```
98/// # use quick_xml::se::to_writer;
99/// # use serde::Serialize;
100/// # use pretty_assertions::assert_eq;
101/// #[derive(Serialize)]
102/// struct Root<'a> {
103///     #[serde(rename = "@attribute")]
104///     attribute: &'a str,
105///     element: &'a str,
106///     #[serde(rename = "$text")]
107///     text: &'a str,
108/// }
109///
110/// let data = Root {
111///     attribute: "attribute content",
112///     element: "element content",
113///     text: "text content",
114/// };
115///
116/// let mut buffer = String::new();
117/// to_writer(&mut buffer, &data).unwrap();
118/// assert_eq!(
119///     buffer,
120///     // The root tag name is automatically deduced from the struct name
121///     // This will not work for other types or struct with #[serde(flatten)] fields
122///     "<Root attribute=\"attribute content\">\
123///         <element>element content</element>\
124///         text content\
125///     </Root>"
126/// );
127/// ```
128pub fn to_writer<W, T>(mut writer: W, value: &T) -> Result<WriteResult, SeError>
129where
130    W: Write,
131    T: ?Sized + Serialize,
132{
133    value.serialize(Serializer::new(&mut writer))
134}
135
136/// Serialize struct into a `io::Write`r restricted to utf-8 encoding.
137///
138/// Returns the classification of the last written type.
139///
140/// # Examples
141///
142/// ```
143/// # use quick_xml::se::to_utf8_io_writer;
144/// # use serde::Serialize;
145/// # use pretty_assertions::assert_eq;
146/// # use std::io::BufWriter;
147/// #[derive(Serialize)]
148/// struct Root<'a> {
149///     #[serde(rename = "@attribute")]
150///     attribute: &'a str,
151///     element: &'a str,
152///     #[serde(rename = "$text")]
153///     text: &'a str,
154/// }
155///
156/// let data = Root {
157///     attribute: "attribute content",
158///     element: "element content",
159///     text: "text content",
160/// };
161///
162/// let mut buffer = Vec::new();
163/// to_utf8_io_writer(&mut BufWriter::new(&mut buffer), &data).unwrap();
164///
165/// assert_eq!(
166///     std::str::from_utf8(&buffer).unwrap(),
167///     // The root tag name is automatically deduced from the struct name
168///     // This will not work for other types or struct with #[serde(flatten)] fields
169///     "<Root attribute=\"attribute content\">\
170///         <element>element content</element>\
171///         text content\
172///     </Root>"
173/// );
174/// ```
175pub fn to_utf8_io_writer<W, T>(writer: W, value: &T) -> Result<WriteResult, SeError>
176where
177    W: std::io::Write,
178    T: ?Sized + Serialize,
179{
180    value.serialize(Serializer::new(&mut ToFmtWrite(writer)))
181}
182
183/// Serialize struct into a `String`.
184///
185/// # Examples
186///
187/// ```
188/// # use quick_xml::se::to_string;
189/// # use serde::Serialize;
190/// # use pretty_assertions::assert_eq;
191/// #[derive(Serialize)]
192/// struct Root<'a> {
193///     #[serde(rename = "@attribute")]
194///     attribute: &'a str,
195///     element: &'a str,
196///     #[serde(rename = "$text")]
197///     text: &'a str,
198/// }
199///
200/// let data = Root {
201///     attribute: "attribute content",
202///     element: "element content",
203///     text: "text content",
204/// };
205///
206/// assert_eq!(
207///     to_string(&data).unwrap(),
208///     // The root tag name is automatically deduced from the struct name
209///     // This will not work for other types or struct with #[serde(flatten)] fields
210///     "<Root attribute=\"attribute content\">\
211///         <element>element content</element>\
212///         text content\
213///     </Root>"
214/// );
215/// ```
216pub fn to_string<T>(value: &T) -> Result<String, SeError>
217where
218    T: ?Sized + Serialize,
219{
220    let mut buffer = String::new();
221    to_writer(&mut buffer, value)?;
222    Ok(buffer)
223}
224
225/// Serialize struct into a `Write`r using specified root tag name.
226/// `root_tag` should be valid [XML name], otherwise error is returned.
227///
228/// Returns the classification of the last written type.
229///
230/// # Examples
231///
232/// ```
233/// # use quick_xml::se::to_writer_with_root;
234/// # use serde::Serialize;
235/// # use pretty_assertions::assert_eq;
236/// #[derive(Serialize)]
237/// struct Root<'a> {
238///     #[serde(rename = "@attribute")]
239///     attribute: &'a str,
240///     element: &'a str,
241///     #[serde(rename = "$text")]
242///     text: &'a str,
243/// }
244///
245/// let data = Root {
246///     attribute: "attribute content",
247///     element: "element content",
248///     text: "text content",
249/// };
250///
251/// let mut buffer = String::new();
252/// to_writer_with_root(&mut buffer, "top-level", &data).unwrap();
253/// assert_eq!(
254///     buffer,
255///     "<top-level attribute=\"attribute content\">\
256///         <element>element content</element>\
257///         text content\
258///     </top-level>"
259/// );
260/// ```
261///
262/// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
263pub fn to_writer_with_root<W, T>(
264    mut writer: W,
265    root_tag: &str,
266    value: &T,
267) -> Result<WriteResult, SeError>
268where
269    W: Write,
270    T: ?Sized + Serialize,
271{
272    value.serialize(Serializer::with_root(&mut writer, Some(root_tag))?)
273}
274
275/// Serialize struct into a `String` using specified root tag name.
276/// `root_tag` should be valid [XML name], otherwise error is returned.
277///
278/// # Examples
279///
280/// ```
281/// # use quick_xml::se::to_string_with_root;
282/// # use serde::Serialize;
283/// # use pretty_assertions::assert_eq;
284/// #[derive(Serialize)]
285/// struct Root<'a> {
286///     #[serde(rename = "@attribute")]
287///     attribute: &'a str,
288///     element: &'a str,
289///     #[serde(rename = "$text")]
290///     text: &'a str,
291/// }
292///
293/// let data = Root {
294///     attribute: "attribute content",
295///     element: "element content",
296///     text: "text content",
297/// };
298///
299/// assert_eq!(
300///     to_string_with_root("top-level", &data).unwrap(),
301///     "<top-level attribute=\"attribute content\">\
302///         <element>element content</element>\
303///         text content\
304///     </top-level>"
305/// );
306/// ```
307///
308/// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
309pub fn to_string_with_root<T>(root_tag: &str, value: &T) -> Result<String, SeError>
310where
311    T: ?Sized + Serialize,
312{
313    let mut buffer = String::new();
314    to_writer_with_root(&mut buffer, root_tag, value)?;
315    Ok(buffer)
316}
317
318////////////////////////////////////////////////////////////////////////////////////////////////////
319
320/// Defines the format for text content serialization
321#[derive(Debug, Clone, Copy, PartialEq, Eq)]
322#[non_exhaustive]
323pub enum TextFormat {
324    /// Serialize as regular text content with escaping
325    Text,
326    /// Serialize as CDATA section without escaping
327    CData,
328}
329
330/// Defines which characters would be escaped in [`Text`] events and attribute
331/// values.
332///
333/// [`Text`]: crate::events::Event::Text
334#[derive(Debug, Clone, Copy, PartialEq, Eq)]
335pub enum QuoteLevel {
336    /// Performs escaping, escape all characters that could have special meaning
337    /// in the XML. This mode is compatible with SGML specification.
338    ///
339    /// Characters that will be replaced:
340    ///
341    /// Original | Replacement
342    /// ---------|------------
343    /// `<`      | `&lt;`
344    /// `>`      | `&gt;`
345    /// `&`      | `&amp;`
346    /// `"`      | `&quot;`
347    /// `'`      | `&apos;`
348    Full,
349    /// Performs escaping that is compatible with SGML specification.
350    ///
351    /// This level adds escaping of `>` to the `Minimal` level, which is [required]
352    /// for compatibility with SGML.
353    ///
354    /// Characters that will be replaced:
355    ///
356    /// Original | Replacement
357    /// ---------|------------
358    /// `<`      | `&lt;`
359    /// `>`      | `&gt;`
360    /// `&`      | `&amp;`
361    ///
362    /// [required]: https://www.w3.org/TR/xml11/#syntax
363    Partial,
364    /// Performs the minimal possible escaping, escape only strictly necessary
365    /// characters.
366    ///
367    /// Characters that will be replaced:
368    ///
369    /// Original | Replacement
370    /// ---------|------------
371    /// `<`      | `&lt;`
372    /// `&`      | `&amp;`
373    Minimal,
374}
375
376/// Specifies how empty elements are serialized.
377/// The default is self-closed with no space before the slash.
378#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
379pub enum EmptyElementHandling {
380    /// Empty elements will be written as `<element/>`. This is the default behavior.
381    #[default]
382    SelfClosed,
383
384    /// The same, as [`SelfClosed`], but an extra space will be written before
385    /// the slash, so empty elements will be written as `<element />`.
386    /// This is recommended by the [W3C guidelines] for XHTML.
387    ///
388    /// [`SelfClosed`]: Self::SelfClosed
389    /// [W3C guidelines]: https://www.w3.org/TR/xhtml1/#guidelines
390    SelfClosedWithSpace,
391
392    /// Empty elements will be expanded, as in: `<element></element>`.
393    Expanded,
394}
395
396/// Classification of the type written by the serializer.
397#[derive(Debug, Clone, Copy, PartialEq, Eq)]
398pub enum WriteResult {
399    /// Text with insignificant spaces was written, for example a number. Adding indent to the
400    /// serialized data does not change meaning of the data.
401    Text,
402    /// The XML tag was written. Adding indent to the serialized data does not change meaning of the data.
403    Element,
404    /// Nothing was written (i. e. serialized type not represented in XML a all). Adding indent to the
405    /// serialized data does not change meaning of the data. This is returned for units, unit structs
406    /// and unit variants.
407    Nothing,
408    /// Text with significant spaces was written, for example a string. Adding indent to the
409    /// serialized data may change meaning of the data.
410    SensitiveText,
411    /// `None` was serialized and nothing was written. `None` does not represented in XML,
412    /// but adding indent after it may change meaning of the data.
413    SensitiveNothing,
414}
415
416impl WriteResult {
417    /// Returns `true` if indent should be written after the object (if configured) and `false` otherwise.
418    #[inline]
419    pub fn allow_indent(&self) -> bool {
420        matches!(self, Self::Element | Self::Nothing)
421    }
422
423    /// Returns `true` if self is `Text` or `SensitiveText`.
424    #[inline]
425    pub fn is_text(&self) -> bool {
426        matches!(self, Self::Text | Self::SensitiveText)
427    }
428}
429
430////////////////////////////////////////////////////////////////////////////////////////////////////
431
432/// Implements serialization method by forwarding it to the serializer created by
433/// the helper method [`Serializer::ser`].
434macro_rules! forward {
435    ($name:ident($ty:ty)) => {
436        fn $name(self, value: $ty) -> Result<Self::Ok, Self::Error> {
437            self.ser(&concat!("`", stringify!($ty), "`"))?.$name(value)
438        }
439    };
440}
441
442////////////////////////////////////////////////////////////////////////////////////////////////////
443
444/// Almost all characters can form a name. Citation from <https://www.w3.org/TR/xml11/#sec-xml11>:
445///
446/// > The overall philosophy of names has changed since XML 1.0. Whereas XML 1.0
447/// > provided a rigid definition of names, wherein everything that was not permitted
448/// > was forbidden, XML 1.1 names are designed so that everything that is not
449/// > forbidden (for a specific reason) is permitted. Since Unicode will continue
450/// > to grow past version 4.0, further changes to XML can be avoided by allowing
451/// > almost any character, including those not yet assigned, in names.
452///
453/// <https://www.w3.org/TR/xml11/#NT-NameStartChar>
454const fn is_xml11_name_start_char(ch: char) -> bool {
455    // Not need to use macro when core primitives is enough
456    #[allow(clippy::match_like_matches_macro)]
457    match ch {
458        ':'
459        | 'A'..='Z'
460        | '_'
461        | 'a'..='z'
462        | '\u{00C0}'..='\u{00D6}'
463        | '\u{00D8}'..='\u{00F6}'
464        | '\u{00F8}'..='\u{02FF}'
465        | '\u{0370}'..='\u{037D}'
466        | '\u{037F}'..='\u{1FFF}'
467        | '\u{200C}'..='\u{200D}'
468        | '\u{2070}'..='\u{218F}'
469        | '\u{2C00}'..='\u{2FEF}'
470        | '\u{3001}'..='\u{D7FF}'
471        | '\u{F900}'..='\u{FDCF}'
472        | '\u{FDF0}'..='\u{FFFD}'
473        | '\u{10000}'..='\u{EFFFF}' => true,
474        _ => false,
475    }
476}
477/// <https://www.w3.org/TR/xml11/#NT-NameChar>
478const fn is_xml11_name_char(ch: char) -> bool {
479    match ch {
480        '-' | '.' | '0'..='9' | '\u{00B7}' | '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}' => {
481            true
482        }
483        _ => is_xml11_name_start_char(ch),
484    }
485}
486
487/// Helper struct to self-defense from errors
488#[derive(Clone, Copy, Debug, PartialEq)]
489struct XmlName<'n>(&'n str);
490
491impl<'n> XmlName<'n> {
492    /// Checks correctness of the XML name according to [XML 1.1 specification]
493    ///
494    /// [XML 1.1 specification]: https://www.w3.org/TR/xml11/#NT-Name
495    pub fn try_from(name: &'n str) -> Result<XmlName<'n>, SeError> {
496        //TODO: Customization point: allow user to decide if he want to reject or encode the name
497        match name.chars().next() {
498            Some(ch) if !is_xml11_name_start_char(ch) => Err(SeError::Unsupported(
499                format!("character `{ch}` is not allowed at the start of an XML name `{name}`")
500                    .into(),
501            )),
502            _ => match name.matches(|ch| !is_xml11_name_char(ch)).next() {
503                Some(s) => Err(SeError::Unsupported(
504                    format!("character `{s}` is not allowed in an XML name `{name}`").into(),
505                )),
506                None => Ok(XmlName(name)),
507            },
508        }
509    }
510}
511
512////////////////////////////////////////////////////////////////////////////////////////////////////
513
514pub(crate) enum Indent<'i> {
515    /// No indent should be written before the element
516    None,
517    /// The specified indent should be written. The type owns the buffer with indent
518    Owned(Indentation),
519    /// The specified indent should be written. The type borrows buffer with indent
520    /// from its owner
521    Borrow(&'i mut Indentation),
522}
523
524impl<'i> Indent<'i> {
525    pub fn borrow(&mut self) -> Indent<'_> {
526        match self {
527            Self::None => Indent::None,
528            Self::Owned(ref mut i) => Indent::Borrow(i),
529            Self::Borrow(i) => Indent::Borrow(i),
530        }
531    }
532
533    pub fn increase(&mut self) {
534        match self {
535            Self::None => {}
536            Self::Owned(i) => i.grow(),
537            Self::Borrow(i) => i.grow(),
538        }
539    }
540
541    pub fn decrease(&mut self) {
542        match self {
543            Self::None => {}
544            Self::Owned(i) => i.shrink(),
545            Self::Borrow(i) => i.shrink(),
546        }
547    }
548
549    pub fn write_indent<W: std::fmt::Write>(&mut self, mut writer: W) -> Result<(), SeError> {
550        match self {
551            Self::None => {}
552            Self::Owned(i) => {
553                writer.write_char('\n')?;
554                writer.write_str(from_utf8(i.current())?)?;
555            }
556            Self::Borrow(i) => {
557                writer.write_char('\n')?;
558                writer.write_str(from_utf8(i.current())?)?;
559            }
560        }
561        Ok(())
562    }
563}
564
565////////////////////////////////////////////////////////////////////////////////////////////////////
566
567/// A Serializer.
568///
569/// Returns the classification of the last written type.
570pub struct Serializer<'w, 'r, W: Write> {
571    ser: ContentSerializer<'w, 'r, W>,
572    /// Name of the root tag. If not specified, deduced from the structure name
573    root_tag: Option<XmlName<'r>>,
574}
575
576impl<'w, 'r, W: Write> Serializer<'w, 'r, W> {
577    /// Creates a new `Serializer` that uses struct name as a root tag name.
578    ///
579    /// Note, that attempt to serialize a non-struct (including unit structs
580    /// and newtype structs) will end up to an error. Use `with_root` to create
581    /// serializer with explicitly defined root element name
582    pub fn new(writer: &'w mut W) -> Self {
583        Self {
584            ser: ContentSerializer {
585                writer,
586                level: QuoteLevel::Partial,
587                indent: Indent::None,
588                write_indent: false,
589                text_format: TextFormat::Text,
590                allow_primitive: true,
591                empty_element_handling: EmptyElementHandling::SelfClosed,
592            },
593            root_tag: None,
594        }
595    }
596
597    /// Creates a new `Serializer` that uses specified root tag name. `name` should
598    /// be valid [XML name], otherwise error is returned.
599    ///
600    /// # Examples
601    ///
602    /// When serializing a primitive type, only its representation will be written:
603    ///
604    /// ```
605    /// # use pretty_assertions::assert_eq;
606    /// # use serde::Serialize;
607    /// # use quick_xml::se::Serializer;
608    ///
609    /// let mut buffer = String::new();
610    /// let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap();
611    ///
612    /// "node".serialize(ser).unwrap();
613    /// assert_eq!(buffer, "<root>node</root>");
614    /// ```
615    ///
616    /// When serializing a struct, newtype struct, unit struct or tuple `root_tag`
617    /// is used as tag name of root(s) element(s):
618    ///
619    /// ```
620    /// # use pretty_assertions::assert_eq;
621    /// # use serde::Serialize;
622    /// # use quick_xml::se::Serializer;
623    ///
624    /// #[derive(Debug, PartialEq, Serialize)]
625    /// struct Struct {
626    ///     question: String,
627    ///     answer: u32,
628    /// }
629    ///
630    /// let mut buffer = String::new();
631    /// let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap();
632    ///
633    /// let data = Struct {
634    ///     question: "The Ultimate Question of Life, the Universe, and Everything".into(),
635    ///     answer: 42,
636    /// };
637    ///
638    /// data.serialize(ser).unwrap();
639    /// assert_eq!(
640    ///     buffer,
641    ///     "<root>\
642    ///         <question>The Ultimate Question of Life, the Universe, and Everything</question>\
643    ///         <answer>42</answer>\
644    ///      </root>"
645    /// );
646    /// ```
647    ///
648    /// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
649    pub fn with_root(writer: &'w mut W, root_tag: Option<&'r str>) -> Result<Self, SeError> {
650        Ok(Self {
651            ser: ContentSerializer {
652                writer,
653                level: QuoteLevel::Partial,
654                indent: Indent::None,
655                write_indent: false,
656                text_format: TextFormat::Text,
657                allow_primitive: true,
658                empty_element_handling: EmptyElementHandling::SelfClosed,
659            },
660            root_tag: root_tag.map(XmlName::try_from).transpose()?,
661        })
662    }
663
664    /// Enable or disable expansion of empty elements. Defaults to [`EmptyElementHandling::SelfClosed`].
665    ///
666    /// # Examples
667    ///
668    /// ```
669    /// # use pretty_assertions::assert_eq;
670    /// # use serde::Serialize;
671    /// # use quick_xml::se::{Serializer, EmptyElementHandling};
672    /// #
673    /// #[derive(Debug, PartialEq, Serialize)]
674    /// struct Struct {
675    ///     question: Option<String>,
676    /// }
677    ///
678    /// let data = Struct {
679    ///     question: None,
680    /// };
681    ///
682    /// {
683    ///     let mut buffer = String::new();
684    ///     let mut ser = Serializer::new(&mut buffer);
685    ///     ser.empty_element_handling(EmptyElementHandling::SelfClosed);
686    ///     data.serialize(ser).unwrap();
687    ///     assert_eq!(
688    ///         buffer,
689    ///         "<Struct><question/></Struct>"
690    ///     );
691    /// }
692    ///
693    /// {
694    ///     let mut buffer = String::new();
695    ///     let mut ser = Serializer::new(&mut buffer);
696    ///     ser.empty_element_handling(EmptyElementHandling::SelfClosedWithSpace);
697    ///     data.serialize(ser).unwrap();
698    ///     assert_eq!(
699    ///         buffer,
700    ///         "<Struct><question /></Struct>"
701    ///     );
702    /// }
703    ///
704    /// {
705    ///     let mut buffer = String::new();
706    ///     let mut ser = Serializer::new(&mut buffer);
707    ///     ser.empty_element_handling(EmptyElementHandling::Expanded);
708    ///     data.serialize(ser).unwrap();
709    ///     assert_eq!(
710    ///         buffer,
711    ///         "<Struct><question></question></Struct>"
712    ///     );
713    /// }
714    /// ```
715    pub fn empty_element_handling(&mut self, handling: EmptyElementHandling) -> &mut Self {
716        self.ser.empty_element_handling = handling;
717        self
718    }
719
720    /// Enable or disable expansion of empty elements (without adding space before `/>`).
721    ///
722    /// This is the historycally first way to configure empty element handling. You can use
723    /// [`empty_element_handling`](Self::empty_element_handling) for more control.
724    ///
725    /// # Examples
726    ///
727    /// ```
728    /// # use pretty_assertions::assert_eq;
729    /// # use serde::Serialize;
730    /// # use quick_xml::se::Serializer;
731    /// #
732    /// #[derive(Debug, PartialEq, Serialize)]
733    /// struct Struct {
734    ///     question: Option<String>,
735    /// }
736    ///
737    /// let mut buffer = String::new();
738    /// let mut ser = Serializer::new(&mut buffer);
739    /// ser.expand_empty_elements(true);
740    ///
741    /// let data = Struct {
742    ///     question: None,
743    /// };
744    ///
745    /// data.serialize(ser).unwrap();
746    /// assert_eq!(
747    ///     buffer,
748    ///     "<Struct><question></question></Struct>"
749    /// );
750    /// ```
751    pub fn expand_empty_elements(&mut self, expand: bool) -> &mut Self {
752        self.empty_element_handling(if expand {
753            EmptyElementHandling::Expanded
754        } else {
755            EmptyElementHandling::SelfClosed
756        })
757    }
758
759    /// Set the text format used for serializing text content.
760    ///
761    /// - [`TextFormat::Text`]: Regular XML escaping (default)
762    /// - [`TextFormat::CData`]: CDATA sections for text content
763    ///
764    /// # Examples
765    ///
766    /// ```
767    /// # use pretty_assertions::assert_eq;
768    /// # use serde::Serialize;
769    /// # use quick_xml::se::{Serializer, TextFormat};
770    ///
771    /// #[derive(Debug, PartialEq, Serialize)]
772    /// struct Document {
773    ///     #[serde(rename = "$text")]
774    ///     content: String,
775    /// }
776    ///
777    /// let mut buffer = String::new();
778    /// let mut ser = Serializer::with_root(&mut buffer, Some("doc")).unwrap();
779    /// ser.text_format(TextFormat::CData);
780    ///
781    /// let data = Document {
782    ///     content: "Content with <markup> & entities".to_string(),
783    /// };
784    ///
785    /// data.serialize(ser).unwrap();
786    /// assert_eq!(buffer, "<doc><![CDATA[Content with <markup> & entities]]></doc>");
787    /// ```
788    pub fn text_format(&mut self, format: TextFormat) -> &mut Self {
789        self.ser.text_format = format;
790        self
791    }
792
793    /// Configure indent for a serializer
794    pub fn indent(&mut self, indent_char: char, indent_size: usize) -> &mut Self {
795        self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size));
796        self
797    }
798
799    /// Set the level of quoting used when writing texts
800    ///
801    /// Default: [`QuoteLevel::Minimal`]
802    pub fn set_quote_level(&mut self, level: QuoteLevel) -> &mut Self {
803        self.ser.level = level;
804        self
805    }
806
807    /// Set the indent object for a serializer
808    pub(crate) fn set_indent(&mut self, indent: Indent<'r>) -> &mut Self {
809        self.ser.indent = indent;
810        self
811    }
812
813    /// Creates actual serializer or returns an error if root tag is not defined.
814    /// In that case `err` contains the name of type that cannot be serialized.
815    fn ser(self, err: &str) -> Result<ElementSerializer<'w, 'r, W>, SeError> {
816        if let Some(key) = self.root_tag {
817            Ok(ElementSerializer { ser: self.ser, key })
818        } else {
819            Err(SeError::Unsupported(
820                format!("cannot serialize {} without defined root tag", err).into(),
821            ))
822        }
823    }
824
825    /// Creates actual serializer using root tag or a specified `key` if root tag
826    /// is not defined. Returns an error if root tag is not defined and a `key`
827    /// does not conform [XML rules](XmlName::try_from) for names.
828    fn ser_name(self, key: &'static str) -> Result<ElementSerializer<'w, 'r, W>, SeError> {
829        Ok(ElementSerializer {
830            ser: self.ser,
831            key: match self.root_tag {
832                Some(key) => key,
833                None => XmlName::try_from(key)?,
834            },
835        })
836    }
837}
838
839impl<'w, 'r, W: Write> ser::Serializer for Serializer<'w, 'r, W> {
840    type Ok = WriteResult;
841    type Error = SeError;
842
843    type SerializeSeq = ElementSerializer<'w, 'r, W>;
844    type SerializeTuple = ElementSerializer<'w, 'r, W>;
845    type SerializeTupleStruct = ElementSerializer<'w, 'r, W>;
846    type SerializeTupleVariant = Tuple<'w, 'r, W>;
847    type SerializeMap = Map<'w, 'r, W>;
848    type SerializeStruct = Struct<'w, 'r, W>;
849    type SerializeStructVariant = Struct<'w, 'r, W>;
850
851    forward!(serialize_bool(bool));
852
853    forward!(serialize_i8(i8));
854    forward!(serialize_i16(i16));
855    forward!(serialize_i32(i32));
856    forward!(serialize_i64(i64));
857
858    forward!(serialize_u8(u8));
859    forward!(serialize_u16(u16));
860    forward!(serialize_u32(u32));
861    forward!(serialize_u64(u64));
862
863    forward!(serialize_i128(i128));
864    forward!(serialize_u128(u128));
865
866    forward!(serialize_f32(f32));
867    forward!(serialize_f64(f64));
868
869    forward!(serialize_char(char));
870    forward!(serialize_str(&str));
871    forward!(serialize_bytes(&[u8]));
872
873    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
874        // Do not write indent after `Option` field with `None` value, because
875        // this can be `Option<String>`. Unfortunately, we do not known what the
876        // type the option contains, so have no chance to adapt our behavior to it.
877        // The safe variant is not to write indent
878        Ok(WriteResult::SensitiveNothing)
879    }
880
881    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
882        value.serialize(self)
883    }
884
885    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
886        self.ser("`()`")?.serialize_unit()
887    }
888
889    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
890        self.ser_name(name)?.serialize_unit_struct(name)
891    }
892
893    fn serialize_unit_variant(
894        self,
895        name: &'static str,
896        _variant_index: u32,
897        variant: &'static str,
898    ) -> Result<Self::Ok, Self::Error> {
899        if variant == TEXT_KEY {
900            // We should write some text but we don't known what text to write
901            Err(SeError::Unsupported(
902                format!(
903                    "cannot serialize enum unit variant `{}::$text` as text content value",
904                    name
905                )
906                .into(),
907            ))
908        } else {
909            let name = XmlName::try_from(variant)?;
910            self.ser.write_empty(name)
911        }
912    }
913
914    fn serialize_newtype_struct<T: ?Sized + Serialize>(
915        self,
916        name: &'static str,
917        value: &T,
918    ) -> Result<Self::Ok, Self::Error> {
919        self.ser_name(name)?.serialize_newtype_struct(name, value)
920    }
921
922    fn serialize_newtype_variant<T: ?Sized + Serialize>(
923        self,
924        _name: &'static str,
925        _variant_index: u32,
926        variant: &'static str,
927        value: &T,
928    ) -> Result<Self::Ok, Self::Error> {
929        if variant == TEXT_KEY {
930            value.serialize(self.ser.into_simple_type_serializer()?)?;
931            // Do not write indent after `$text` variant because it may be interpreted as
932            // part of content when deserialize
933            Ok(WriteResult::SensitiveText)
934        } else {
935            let ser = ElementSerializer {
936                ser: self.ser,
937                key: XmlName::try_from(variant)?,
938            };
939            value.serialize(ser)
940        }
941    }
942
943    fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
944        self.ser("sequence")?.serialize_seq(len)
945    }
946
947    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
948        self.ser("unnamed tuple")?.serialize_tuple(len)
949    }
950
951    fn serialize_tuple_struct(
952        self,
953        name: &'static str,
954        len: usize,
955    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
956        self.ser_name(name)?.serialize_tuple_struct(name, len)
957    }
958
959    fn serialize_tuple_variant(
960        self,
961        name: &'static str,
962        _variant_index: u32,
963        variant: &'static str,
964        len: usize,
965    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
966        if variant == TEXT_KEY {
967            self.ser
968                .into_simple_type_serializer()?
969                .serialize_tuple_struct(name, len)
970                .map(Tuple::Text)
971        } else {
972            let ser = ElementSerializer {
973                ser: self.ser,
974                key: XmlName::try_from(variant)?,
975            };
976            ser.serialize_tuple_struct(name, len).map(Tuple::Element)
977        }
978    }
979
980    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
981        self.ser("map")?.serialize_map(len)
982    }
983
984    fn serialize_struct(
985        self,
986        name: &'static str,
987        len: usize,
988    ) -> Result<Self::SerializeStruct, Self::Error> {
989        self.ser_name(name)?.serialize_struct(name, len)
990    }
991
992    fn serialize_struct_variant(
993        self,
994        name: &'static str,
995        _variant_index: u32,
996        variant: &'static str,
997        len: usize,
998    ) -> Result<Self::SerializeStructVariant, Self::Error> {
999        if variant == TEXT_KEY {
1000            Err(SeError::Unsupported(
1001                format!(
1002                    "cannot serialize enum struct variant `{}::$text` as text content value",
1003                    name
1004                )
1005                .into(),
1006            ))
1007        } else {
1008            let ser = ElementSerializer {
1009                ser: self.ser,
1010                key: XmlName::try_from(variant)?,
1011            };
1012            ser.serialize_struct(name, len)
1013        }
1014    }
1015}
1016
1017#[cfg(test)]
1018mod quote_level {
1019    use super::*;
1020    use pretty_assertions::assert_eq;
1021    use serde::Serialize;
1022
1023    #[derive(Debug, PartialEq, Serialize)]
1024    struct Element(&'static str);
1025
1026    #[derive(Debug, PartialEq, Serialize)]
1027    struct Example {
1028        #[serde(rename = "@attribute")]
1029        attribute: &'static str,
1030        element: Element,
1031    }
1032
1033    #[test]
1034    fn default_() {
1035        let example = Example {
1036            attribute: "special chars: &, <, >, \", '",
1037            element: Element("special chars: &, <, >, \", '"),
1038        };
1039
1040        let mut buffer = String::new();
1041        let ser = Serializer::new(&mut buffer);
1042
1043        example.serialize(ser).unwrap();
1044        assert_eq!(
1045            buffer,
1046            "<Example attribute=\"special chars: &amp;, &lt;, &gt;, &quot;, '\">\
1047                <element>special chars: &amp;, &lt;, &gt;, \", '</element>\
1048            </Example>"
1049        );
1050    }
1051
1052    #[test]
1053    fn minimal() {
1054        let example = Example {
1055            attribute: "special chars: &, <, >, \", '",
1056            element: Element("special chars: &, <, >, \", '"),
1057        };
1058
1059        let mut buffer = String::new();
1060        let mut ser = Serializer::new(&mut buffer);
1061        ser.set_quote_level(QuoteLevel::Minimal);
1062
1063        example.serialize(ser).unwrap();
1064        assert_eq!(
1065            buffer,
1066            "<Example attribute=\"special chars: &amp;, &lt;, >, &quot;, '\">\
1067                <element>special chars: &amp;, &lt;, >, \", '</element>\
1068            </Example>"
1069        );
1070    }
1071
1072    #[test]
1073    fn partial() {
1074        let example = Example {
1075            attribute: "special chars: &, <, >, \", '",
1076            element: Element("special chars: &, <, >, \", '"),
1077        };
1078
1079        let mut buffer = String::new();
1080        let mut ser = Serializer::new(&mut buffer);
1081        ser.set_quote_level(QuoteLevel::Partial);
1082
1083        example.serialize(ser).unwrap();
1084        assert_eq!(
1085            buffer,
1086            "<Example attribute=\"special chars: &amp;, &lt;, &gt;, &quot;, '\">\
1087                <element>special chars: &amp;, &lt;, &gt;, \", '</element>\
1088            </Example>"
1089        );
1090    }
1091
1092    #[test]
1093    fn full() {
1094        let example = Example {
1095            attribute: "special chars: &, <, >, \", '",
1096            element: Element("special chars: &, <, >, \", '"),
1097        };
1098
1099        let mut buffer = String::new();
1100        let mut ser = Serializer::new(&mut buffer);
1101        ser.set_quote_level(QuoteLevel::Full);
1102
1103        example.serialize(ser).unwrap();
1104        assert_eq!(
1105            buffer,
1106            "<Example attribute=\"special chars: &amp;, &lt;, &gt;, &quot;, &apos;\">\
1107                <element>special chars: &amp;, &lt;, &gt;, &quot;, &apos;</element>\
1108            </Example>"
1109        );
1110    }
1111}