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 /// `<` | `<`
343 /// `>` | `>`
344 /// `&` | `&`
345 /// `"` | `"`
346 /// `'` | `'`
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 /// `<` | `<`
358 /// `>` | `>`
359 /// `&` | `&`
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 /// `<` | `<`
371 /// `&` | `&`
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: &, <, >, ", '\">\
1072 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
1092 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
1112 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
1132 <element>special chars: &, <, >, ", '</element>\
1133 </Example>"
1134 );
1135 }
1136}