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 /// `<` | `<`
344 /// `>` | `>`
345 /// `&` | `&`
346 /// `"` | `"`
347 /// `'` | `'`
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 /// `<` | `<`
359 /// `>` | `>`
360 /// `&` | `&`
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 /// `<` | `<`
372 /// `&` | `&`
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: &, <, >, ", '\">\
1047 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
1067 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
1087 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
1107 <element>special chars: &, <, >, ", '</element>\
1108 </Example>"
1109 );
1110 }
1111}