Skip to main content

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