| 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
|
| 5 | macro_rules! write_primitive {
|
| 6 | ($method:ident ( $ty:ty )) => {
|
| 7 | fn $method(mut self, value: $ty) -> Result<Self::Ok, Self::Error> {
|
| 8 | self.write_str(&value.to_string())?;
|
| 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 | serde_if_integer128! {
|
| 29 | write_primitive!(serialize_i128(i128));
|
| 30 | write_primitive!(serialize_u128(u128));
|
| 31 | }
|
| 32 |
|
| 33 | write_primitive!(serialize_f32(f32));
|
| 34 | write_primitive!(serialize_f64(f64));
|
| 35 |
|
| 36 | fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
|
| 37 | self.serialize_str(&value.to_string())
|
| 38 | }
|
| 39 |
|
| 40 | fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
|
| 41 | //TODO: customization point - allow user to decide how to encode bytes
|
| 42 | Err(DeError::Unsupported(
|
| 43 | "`serialize_bytes` not supported yet" .into(),
|
| 44 | ))
|
| 45 | }
|
| 46 |
|
| 47 | fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
| 48 | Ok(self.writer)
|
| 49 | }
|
| 50 |
|
| 51 | fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
|
| 52 | value.serialize(self)
|
| 53 | }
|
| 54 |
|
| 55 | fn serialize_unit_variant(
|
| 56 | self,
|
| 57 | _name: &'static str,
|
| 58 | _variant_index: u32,
|
| 59 | variant: &'static str,
|
| 60 | ) -> Result<Self::Ok, Self::Error> {
|
| 61 | self.serialize_str(variant)
|
| 62 | }
|
| 63 |
|
| 64 | fn serialize_newtype_struct<T: ?Sized + Serialize>(
|
| 65 | self,
|
| 66 | _name: &'static str,
|
| 67 | value: &T,
|
| 68 | ) -> Result<Self::Ok, Self::Error> {
|
| 69 | value.serialize(self)
|
| 70 | }
|
| 71 | };
|
| 72 | }
|
| 73 |
|
| 74 | ////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 75 |
|
| 76 | mod content;
|
| 77 | mod element;
|
| 78 | pub(crate) mod key;
|
| 79 | pub(crate) mod simple_type;
|
| 80 |
|
| 81 | use self::content::ContentSerializer;
|
| 82 | use self::element::ElementSerializer;
|
| 83 | use crate::errors::serialize::DeError;
|
| 84 | use crate::writer::Indentation;
|
| 85 | use serde::ser::{self, Serialize};
|
| 86 | use serde::serde_if_integer128;
|
| 87 | use std::fmt::Write;
|
| 88 | use std::str::from_utf8;
|
| 89 |
|
| 90 | /// Serialize struct into a `Write`r.
|
| 91 | ///
|
| 92 | /// # Examples
|
| 93 | ///
|
| 94 | /// ```
|
| 95 | /// # use quick_xml::se::to_writer;
|
| 96 | /// # use serde::Serialize;
|
| 97 | /// # use pretty_assertions::assert_eq;
|
| 98 | /// #[derive(Serialize)]
|
| 99 | /// struct Root<'a> {
|
| 100 | /// #[serde(rename = "@attribute" )]
|
| 101 | /// attribute: &'a str,
|
| 102 | /// element: &'a str,
|
| 103 | /// #[serde(rename = "$text" )]
|
| 104 | /// text: &'a str,
|
| 105 | /// }
|
| 106 | ///
|
| 107 | /// let data = Root {
|
| 108 | /// attribute: "attribute content" ,
|
| 109 | /// element: "element content" ,
|
| 110 | /// text: "text content" ,
|
| 111 | /// };
|
| 112 | ///
|
| 113 | /// let mut buffer = String::new();
|
| 114 | /// to_writer(&mut buffer, &data).unwrap();
|
| 115 | /// assert_eq!(
|
| 116 | /// buffer,
|
| 117 | /// // The root tag name is automatically deduced from the struct name
|
| 118 | /// // This will not work for other types or struct with #[serde(flatten)] fields
|
| 119 | /// "<Root attribute= \"attribute content \"> \
|
| 120 | /// <element>element content</element> \
|
| 121 | /// text content \
|
| 122 | /// </Root>"
|
| 123 | /// );
|
| 124 | /// ```
|
| 125 | pub fn to_writer<W, T>(mut writer: W, value: &T) -> Result<(), DeError>
|
| 126 | where
|
| 127 | W: Write,
|
| 128 | T: ?Sized + Serialize,
|
| 129 | {
|
| 130 | value.serialize(Serializer::new(&mut writer))
|
| 131 | }
|
| 132 |
|
| 133 | /// Serialize struct into a `String`.
|
| 134 | ///
|
| 135 | /// # Examples
|
| 136 | ///
|
| 137 | /// ```
|
| 138 | /// # use quick_xml::se::to_string;
|
| 139 | /// # use serde::Serialize;
|
| 140 | /// # use pretty_assertions::assert_eq;
|
| 141 | /// #[derive(Serialize)]
|
| 142 | /// struct Root<'a> {
|
| 143 | /// #[serde(rename = "@attribute" )]
|
| 144 | /// attribute: &'a str,
|
| 145 | /// element: &'a str,
|
| 146 | /// #[serde(rename = "$text" )]
|
| 147 | /// text: &'a str,
|
| 148 | /// }
|
| 149 | ///
|
| 150 | /// let data = Root {
|
| 151 | /// attribute: "attribute content" ,
|
| 152 | /// element: "element content" ,
|
| 153 | /// text: "text content" ,
|
| 154 | /// };
|
| 155 | ///
|
| 156 | /// assert_eq!(
|
| 157 | /// to_string(&data).unwrap(),
|
| 158 | /// // The root tag name is automatically deduced from the struct name
|
| 159 | /// // This will not work for other types or struct with #[serde(flatten)] fields
|
| 160 | /// "<Root attribute= \"attribute content \"> \
|
| 161 | /// <element>element content</element> \
|
| 162 | /// text content \
|
| 163 | /// </Root>"
|
| 164 | /// );
|
| 165 | /// ```
|
| 166 | pub fn to_string<T>(value: &T) -> Result<String, DeError>
|
| 167 | where
|
| 168 | T: ?Sized + Serialize,
|
| 169 | {
|
| 170 | let mut buffer: String = String::new();
|
| 171 | to_writer(&mut buffer, value)?;
|
| 172 | Ok(buffer)
|
| 173 | }
|
| 174 |
|
| 175 | /// Serialize struct into a `Write`r using specified root tag name.
|
| 176 | /// `root_tag` should be valid [XML name], otherwise error is returned.
|
| 177 | ///
|
| 178 | /// # Examples
|
| 179 | ///
|
| 180 | /// ```
|
| 181 | /// # use quick_xml::se::to_writer_with_root;
|
| 182 | /// # use serde::Serialize;
|
| 183 | /// # use pretty_assertions::assert_eq;
|
| 184 | /// #[derive(Serialize)]
|
| 185 | /// struct Root<'a> {
|
| 186 | /// #[serde(rename = "@attribute" )]
|
| 187 | /// attribute: &'a str,
|
| 188 | /// element: &'a str,
|
| 189 | /// #[serde(rename = "$text" )]
|
| 190 | /// text: &'a str,
|
| 191 | /// }
|
| 192 | ///
|
| 193 | /// let data = Root {
|
| 194 | /// attribute: "attribute content" ,
|
| 195 | /// element: "element content" ,
|
| 196 | /// text: "text content" ,
|
| 197 | /// };
|
| 198 | ///
|
| 199 | /// let mut buffer = String::new();
|
| 200 | /// to_writer_with_root(&mut buffer, "top-level" , &data).unwrap();
|
| 201 | /// assert_eq!(
|
| 202 | /// buffer,
|
| 203 | /// "<top-level attribute= \"attribute content \"> \
|
| 204 | /// <element>element content</element> \
|
| 205 | /// text content \
|
| 206 | /// </top-level>"
|
| 207 | /// );
|
| 208 | /// ```
|
| 209 | ///
|
| 210 | /// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
|
| 211 | pub fn to_writer_with_root<W, T>(mut writer: W, root_tag: &str, value: &T) -> Result<(), DeError>
|
| 212 | where
|
| 213 | W: Write,
|
| 214 | T: ?Sized + Serialize,
|
| 215 | {
|
| 216 | value.serialize(Serializer::with_root(&mut writer, root_tag:Some(root_tag))?)
|
| 217 | }
|
| 218 |
|
| 219 | /// Serialize struct into a `String` using specified root tag name.
|
| 220 | /// `root_tag` should be valid [XML name], otherwise error is returned.
|
| 221 | ///
|
| 222 | /// # Examples
|
| 223 | ///
|
| 224 | /// ```
|
| 225 | /// # use quick_xml::se::to_string_with_root;
|
| 226 | /// # use serde::Serialize;
|
| 227 | /// # use pretty_assertions::assert_eq;
|
| 228 | /// #[derive(Serialize)]
|
| 229 | /// struct Root<'a> {
|
| 230 | /// #[serde(rename = "@attribute" )]
|
| 231 | /// attribute: &'a str,
|
| 232 | /// element: &'a str,
|
| 233 | /// #[serde(rename = "$text" )]
|
| 234 | /// text: &'a str,
|
| 235 | /// }
|
| 236 | ///
|
| 237 | /// let data = Root {
|
| 238 | /// attribute: "attribute content" ,
|
| 239 | /// element: "element content" ,
|
| 240 | /// text: "text content" ,
|
| 241 | /// };
|
| 242 | ///
|
| 243 | /// assert_eq!(
|
| 244 | /// to_string_with_root("top-level" , &data).unwrap(),
|
| 245 | /// "<top-level attribute= \"attribute content \"> \
|
| 246 | /// <element>element content</element> \
|
| 247 | /// text content \
|
| 248 | /// </top-level>"
|
| 249 | /// );
|
| 250 | /// ```
|
| 251 | ///
|
| 252 | /// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
|
| 253 | pub fn to_string_with_root<T>(root_tag: &str, value: &T) -> Result<String, DeError>
|
| 254 | where
|
| 255 | T: ?Sized + Serialize,
|
| 256 | {
|
| 257 | let mut buffer: String = String::new();
|
| 258 | to_writer_with_root(&mut buffer, root_tag, value)?;
|
| 259 | Ok(buffer)
|
| 260 | }
|
| 261 |
|
| 262 | ////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 263 |
|
| 264 | /// Defines which characters would be escaped in [`Text`] events and attribute
|
| 265 | /// values.
|
| 266 | ///
|
| 267 | /// [`Text`]: crate::events::Event::Text
|
| 268 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
| 269 | pub enum QuoteLevel {
|
| 270 | /// Performs escaping, escape all characters that could have special meaning
|
| 271 | /// in the XML. This mode is compatible with SGML specification.
|
| 272 | ///
|
| 273 | /// Characters that will be replaced:
|
| 274 | ///
|
| 275 | /// Original | Replacement
|
| 276 | /// ---------|------------
|
| 277 | /// `<` | `<`
|
| 278 | /// `>` | `>`
|
| 279 | /// `&` | `&`
|
| 280 | /// `"` | `"`
|
| 281 | /// `'` | `'`
|
| 282 | Full,
|
| 283 | /// Performs escaping that is compatible with SGML specification.
|
| 284 | ///
|
| 285 | /// This level adds escaping of `>` to the `Minimal` level, which is [required]
|
| 286 | /// for compatibility with SGML.
|
| 287 | ///
|
| 288 | /// Characters that will be replaced:
|
| 289 | ///
|
| 290 | /// Original | Replacement
|
| 291 | /// ---------|------------
|
| 292 | /// `<` | `<`
|
| 293 | /// `>` | `>`
|
| 294 | /// `&` | `&`
|
| 295 | ///
|
| 296 | /// [required]: https://www.w3.org/TR/xml11/#syntax
|
| 297 | Partial,
|
| 298 | /// Performs the minimal possible escaping, escape only strictly necessary
|
| 299 | /// characters.
|
| 300 | ///
|
| 301 | /// Characters that will be replaced:
|
| 302 | ///
|
| 303 | /// Original | Replacement
|
| 304 | /// ---------|------------
|
| 305 | /// `<` | `<`
|
| 306 | /// `&` | `&`
|
| 307 | Minimal,
|
| 308 | }
|
| 309 |
|
| 310 | ////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 311 |
|
| 312 | /// Implements serialization method by forwarding it to the serializer created by
|
| 313 | /// the helper method [`Serializer::ser`].
|
| 314 | macro_rules! forward {
|
| 315 | ($name:ident($ty:ty)) => {
|
| 316 | fn $name(self, value: $ty) -> Result<Self::Ok, Self::Error> {
|
| 317 | self.ser(&concat!("`" , stringify!($ty), "`" ))?.$name(value)
|
| 318 | }
|
| 319 | };
|
| 320 | }
|
| 321 |
|
| 322 | ////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 323 |
|
| 324 | /// Almost all characters can form a name. Citation from <https://www.w3.org/TR/xml11/#sec-xml11>:
|
| 325 | ///
|
| 326 | /// > The overall philosophy of names has changed since XML 1.0. Whereas XML 1.0
|
| 327 | /// > provided a rigid definition of names, wherein everything that was not permitted
|
| 328 | /// > was forbidden, XML 1.1 names are designed so that everything that is not
|
| 329 | /// > forbidden (for a specific reason) is permitted. Since Unicode will continue
|
| 330 | /// > to grow past version 4.0, further changes to XML can be avoided by allowing
|
| 331 | /// > almost any character, including those not yet assigned, in names.
|
| 332 | ///
|
| 333 | /// <https://www.w3.org/TR/xml11/#NT-NameStartChar>
|
| 334 | const fn is_xml11_name_start_char(ch: char) -> bool {
|
| 335 | match ch {
|
| 336 | ':'
|
| 337 | | 'A' ..='Z'
|
| 338 | | '_'
|
| 339 | | 'a' ..='z'
|
| 340 | | ' \u{00C0}' ..=' \u{00D6}'
|
| 341 | | ' \u{00D8}' ..=' \u{00F6}'
|
| 342 | | ' \u{00F8}' ..=' \u{02FF}'
|
| 343 | | ' \u{0370}' ..=' \u{037D}'
|
| 344 | | ' \u{037F}' ..=' \u{1FFF}'
|
| 345 | | ' \u{200C}' ..=' \u{200D}'
|
| 346 | | ' \u{2070}' ..=' \u{218F}'
|
| 347 | | ' \u{2C00}' ..=' \u{2FEF}'
|
| 348 | | ' \u{3001}' ..=' \u{D7FF}'
|
| 349 | | ' \u{F900}' ..=' \u{FDCF}'
|
| 350 | | ' \u{FDF0}' ..=' \u{FFFD}'
|
| 351 | | ' \u{10000}' ..=' \u{EFFFF}' => true,
|
| 352 | _ => false,
|
| 353 | }
|
| 354 | }
|
| 355 | /// <https://www.w3.org/TR/xml11/#NT-NameChar>
|
| 356 | const fn is_xml11_name_char(ch: char) -> bool {
|
| 357 | match ch {
|
| 358 | '-' | '.' | '0' ..='9' | ' \u{00B7}' | ' \u{0300}' ..=' \u{036F}' | ' \u{203F}' ..=' \u{2040}' => {
|
| 359 | true
|
| 360 | }
|
| 361 | _ => is_xml11_name_start_char(ch),
|
| 362 | }
|
| 363 | }
|
| 364 |
|
| 365 | /// Helper struct to self-defense from errors
|
| 366 | #[derive (Clone, Copy, Debug, PartialEq)]
|
| 367 | pub(self) struct XmlName<'n>(&'n str);
|
| 368 |
|
| 369 | impl<'n> XmlName<'n> {
|
| 370 | /// Checks correctness of the XML name according to [XML 1.1 specification]
|
| 371 | ///
|
| 372 | /// [XML 1.1 specification]: https://www.w3.org/TR/xml11/#NT-Name
|
| 373 | pub fn try_from(name: &'n str) -> Result<XmlName<'n>, DeError> {
|
| 374 | //TODO: Customization point: allow user to decide if he want to reject or encode the name
|
| 375 | match name.chars().next() {
|
| 376 | Some(ch: char) if !is_xml11_name_start_char(ch) => Err(DeError::Unsupported(
|
| 377 | formatString!("character ` {ch}` is not allowed at the start of an XML name ` {name}`" )
|
| 378 | .into(),
|
| 379 | )),
|
| 380 | _ => match name.matches(|ch: char| !is_xml11_name_char(ch)).next() {
|
| 381 | Some(s: &str) => Err(DeError::Unsupported(
|
| 382 | format!("character ` {s}` is not allowed in an XML name ` {name}`" ).into(),
|
| 383 | )),
|
| 384 | None => Ok(XmlName(name)),
|
| 385 | },
|
| 386 | }
|
| 387 | }
|
| 388 | }
|
| 389 |
|
| 390 | ////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 391 |
|
| 392 | pub(crate) enum Indent<'i> {
|
| 393 | None,
|
| 394 | Owned(Indentation),
|
| 395 | Borrow(&'i mut Indentation),
|
| 396 | }
|
| 397 |
|
| 398 | impl<'i> Indent<'i> {
|
| 399 | pub fn borrow(&mut self) -> Indent {
|
| 400 | match self {
|
| 401 | Self::None => Indent::None,
|
| 402 | Self::Owned(ref mut i) => Indent::Borrow(i),
|
| 403 | Self::Borrow(i) => Indent::Borrow(i),
|
| 404 | }
|
| 405 | }
|
| 406 |
|
| 407 | pub fn increase(&mut self) {
|
| 408 | match self {
|
| 409 | Self::None => {}
|
| 410 | Self::Owned(i) => i.grow(),
|
| 411 | Self::Borrow(i) => i.grow(),
|
| 412 | }
|
| 413 | }
|
| 414 |
|
| 415 | pub fn decrease(&mut self) {
|
| 416 | match self {
|
| 417 | Self::None => {}
|
| 418 | Self::Owned(i) => i.shrink(),
|
| 419 | Self::Borrow(i) => i.shrink(),
|
| 420 | }
|
| 421 | }
|
| 422 |
|
| 423 | pub fn write_indent<W: std::fmt::Write>(&mut self, mut writer: W) -> Result<(), DeError> {
|
| 424 | match self {
|
| 425 | Self::None => {}
|
| 426 | Self::Owned(i) => {
|
| 427 | writer.write_char(' \n' )?;
|
| 428 | writer.write_str(from_utf8(i.current())?)?;
|
| 429 | }
|
| 430 | Self::Borrow(i) => {
|
| 431 | writer.write_char(' \n' )?;
|
| 432 | writer.write_str(from_utf8(i.current())?)?;
|
| 433 | }
|
| 434 | }
|
| 435 | Ok(())
|
| 436 | }
|
| 437 | }
|
| 438 |
|
| 439 | ////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 440 |
|
| 441 | /// A Serializer
|
| 442 | pub struct Serializer<'w, 'r, W: Write> {
|
| 443 | ser: ContentSerializer<'w, 'r, W>,
|
| 444 | /// Name of the root tag. If not specified, deduced from the structure name
|
| 445 | root_tag: Option<XmlName<'r>>,
|
| 446 | }
|
| 447 |
|
| 448 | impl<'w, 'r, W: Write> Serializer<'w, 'r, W> {
|
| 449 | /// Creates a new `Serializer` that uses struct name as a root tag name.
|
| 450 | ///
|
| 451 | /// Note, that attempt to serialize a non-struct (including unit structs
|
| 452 | /// and newtype structs) will end up to an error. Use `with_root` to create
|
| 453 | /// serializer with explicitly defined root element name
|
| 454 | pub fn new(writer: &'w mut W) -> Self {
|
| 455 | Self {
|
| 456 | ser: ContentSerializer {
|
| 457 | writer,
|
| 458 | level: QuoteLevel::Full,
|
| 459 | indent: Indent::None,
|
| 460 | write_indent: false,
|
| 461 | expand_empty_elements: false,
|
| 462 | },
|
| 463 | root_tag: None,
|
| 464 | }
|
| 465 | }
|
| 466 |
|
| 467 | /// Creates a new `Serializer` that uses specified root tag name. `name` should
|
| 468 | /// be valid [XML name], otherwise error is returned.
|
| 469 | ///
|
| 470 | /// # Examples
|
| 471 | ///
|
| 472 | /// When serializing a primitive type, only its representation will be written:
|
| 473 | ///
|
| 474 | /// ```
|
| 475 | /// # use pretty_assertions::assert_eq;
|
| 476 | /// # use serde::Serialize;
|
| 477 | /// # use quick_xml::se::Serializer;
|
| 478 | ///
|
| 479 | /// let mut buffer = String::new();
|
| 480 | /// let ser = Serializer::with_root(&mut buffer, Some("root" )).unwrap();
|
| 481 | ///
|
| 482 | /// "node" .serialize(ser).unwrap();
|
| 483 | /// assert_eq!(buffer, "<root>node</root>" );
|
| 484 | /// ```
|
| 485 | ///
|
| 486 | /// When serializing a struct, newtype struct, unit struct or tuple `root_tag`
|
| 487 | /// is used as tag name of root(s) element(s):
|
| 488 | ///
|
| 489 | /// ```
|
| 490 | /// # use pretty_assertions::assert_eq;
|
| 491 | /// # use serde::Serialize;
|
| 492 | /// # use quick_xml::se::Serializer;
|
| 493 | ///
|
| 494 | /// #[derive(Debug, PartialEq, Serialize)]
|
| 495 | /// struct Struct {
|
| 496 | /// question: String,
|
| 497 | /// answer: u32,
|
| 498 | /// }
|
| 499 | ///
|
| 500 | /// let mut buffer = String::new();
|
| 501 | /// let ser = Serializer::with_root(&mut buffer, Some("root" )).unwrap();
|
| 502 | ///
|
| 503 | /// let data = Struct {
|
| 504 | /// question: "The Ultimate Question of Life, the Universe, and Everything" .into(),
|
| 505 | /// answer: 42,
|
| 506 | /// };
|
| 507 | ///
|
| 508 | /// data.serialize(ser).unwrap();
|
| 509 | /// assert_eq!(
|
| 510 | /// buffer,
|
| 511 | /// "<root> \
|
| 512 | /// <question>The Ultimate Question of Life, the Universe, and Everything</question> \
|
| 513 | /// <answer>42</answer> \
|
| 514 | /// </root>"
|
| 515 | /// );
|
| 516 | /// ```
|
| 517 | ///
|
| 518 | /// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
|
| 519 | pub fn with_root(writer: &'w mut W, root_tag: Option<&'r str>) -> Result<Self, DeError> {
|
| 520 | Ok(Self {
|
| 521 | ser: ContentSerializer {
|
| 522 | writer,
|
| 523 | level: QuoteLevel::Full,
|
| 524 | indent: Indent::None,
|
| 525 | write_indent: false,
|
| 526 | expand_empty_elements: false,
|
| 527 | },
|
| 528 | root_tag: root_tag.map(|tag| XmlName::try_from(tag)).transpose()?,
|
| 529 | })
|
| 530 | }
|
| 531 |
|
| 532 | /// Enable or disable expansion of empty elements. Defaults to `false`.
|
| 533 | ///
|
| 534 | /// # Examples
|
| 535 | ///
|
| 536 | /// ```
|
| 537 | /// # use pretty_assertions::assert_eq;
|
| 538 | /// # use serde::Serialize;
|
| 539 | /// # use quick_xml::se::Serializer;
|
| 540 | ///
|
| 541 | /// #[derive(Debug, PartialEq, Serialize)]
|
| 542 | /// struct Struct {
|
| 543 | /// question: Option<String>,
|
| 544 | /// }
|
| 545 | ///
|
| 546 | /// let mut buffer = String::new();
|
| 547 | /// let mut ser = Serializer::new(&mut buffer);
|
| 548 | /// ser.expand_empty_elements(true);
|
| 549 | ///
|
| 550 | /// let data = Struct {
|
| 551 | /// question: None,
|
| 552 | /// };
|
| 553 | ///
|
| 554 | /// data.serialize(ser).unwrap();
|
| 555 | /// assert_eq!(
|
| 556 | /// buffer,
|
| 557 | /// "<Struct><question></question></Struct>"
|
| 558 | /// );
|
| 559 | /// ```
|
| 560 | pub fn expand_empty_elements(&mut self, expand: bool) -> &mut Self {
|
| 561 | self.ser.expand_empty_elements = expand;
|
| 562 | self
|
| 563 | }
|
| 564 |
|
| 565 | /// Configure indent for a serializer
|
| 566 | pub fn indent(&mut self, indent_char: char, indent_size: usize) -> &mut Self {
|
| 567 | self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size));
|
| 568 | self
|
| 569 | }
|
| 570 |
|
| 571 | /// Set the indent object for a serializer
|
| 572 | pub(crate) fn set_indent(&mut self, indent: Indent<'r>) -> &mut Self {
|
| 573 | self.ser.indent = indent;
|
| 574 | self
|
| 575 | }
|
| 576 |
|
| 577 | /// Creates actual serializer or returns an error if root tag is not defined.
|
| 578 | /// In that case `err` contains the name of type that cannot be serialized.
|
| 579 | fn ser(self, err: &str) -> Result<ElementSerializer<'w, 'r, W>, DeError> {
|
| 580 | if let Some(key) = self.root_tag {
|
| 581 | Ok(ElementSerializer { ser: self.ser, key })
|
| 582 | } else {
|
| 583 | Err(DeError::Unsupported(
|
| 584 | format!("cannot serialize {} without defined root tag" , err).into(),
|
| 585 | ))
|
| 586 | }
|
| 587 | }
|
| 588 |
|
| 589 | /// Creates actual serializer using root tag or a specified `key` if root tag
|
| 590 | /// is not defined. Returns an error if root tag is not defined and a `key`
|
| 591 | /// does not conform [XML rules](XmlName::try_from) for names.
|
| 592 | fn ser_name(self, key: &'static str) -> Result<ElementSerializer<'w, 'r, W>, DeError> {
|
| 593 | Ok(ElementSerializer {
|
| 594 | ser: self.ser,
|
| 595 | key: match self.root_tag {
|
| 596 | Some(key) => key,
|
| 597 | None => XmlName::try_from(key)?,
|
| 598 | },
|
| 599 | })
|
| 600 | }
|
| 601 | }
|
| 602 |
|
| 603 | impl<'w, 'r, W: Write> ser::Serializer for Serializer<'w, 'r, W> {
|
| 604 | type Ok = ();
|
| 605 | type Error = DeError;
|
| 606 |
|
| 607 | type SerializeSeq = <ElementSerializer<'w, 'r, W> as ser::Serializer>::SerializeSeq;
|
| 608 | type SerializeTuple = <ElementSerializer<'w, 'r, W> as ser::Serializer>::SerializeTuple;
|
| 609 | type SerializeTupleStruct =
|
| 610 | <ElementSerializer<'w, 'r, W> as ser::Serializer>::SerializeTupleStruct;
|
| 611 | type SerializeTupleVariant =
|
| 612 | <ElementSerializer<'w, 'r, W> as ser::Serializer>::SerializeTupleVariant;
|
| 613 | type SerializeMap = <ElementSerializer<'w, 'r, W> as ser::Serializer>::SerializeMap;
|
| 614 | type SerializeStruct = <ElementSerializer<'w, 'r, W> as ser::Serializer>::SerializeStruct;
|
| 615 | type SerializeStructVariant =
|
| 616 | <ElementSerializer<'w, 'r, W> as ser::Serializer>::SerializeStructVariant;
|
| 617 |
|
| 618 | forward!(serialize_bool(bool));
|
| 619 |
|
| 620 | forward!(serialize_i8(i8));
|
| 621 | forward!(serialize_i16(i16));
|
| 622 | forward!(serialize_i32(i32));
|
| 623 | forward!(serialize_i64(i64));
|
| 624 |
|
| 625 | forward!(serialize_u8(u8));
|
| 626 | forward!(serialize_u16(u16));
|
| 627 | forward!(serialize_u32(u32));
|
| 628 | forward!(serialize_u64(u64));
|
| 629 |
|
| 630 | serde_if_integer128! {
|
| 631 | forward!(serialize_i128(i128));
|
| 632 | forward!(serialize_u128(u128));
|
| 633 | }
|
| 634 |
|
| 635 | forward!(serialize_f32(f32));
|
| 636 | forward!(serialize_f64(f64));
|
| 637 |
|
| 638 | forward!(serialize_char(char));
|
| 639 | forward!(serialize_str(&str));
|
| 640 | forward!(serialize_bytes(&[u8]));
|
| 641 |
|
| 642 | fn serialize_none(self) -> Result<Self::Ok, DeError> {
|
| 643 | Ok(())
|
| 644 | }
|
| 645 |
|
| 646 | fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, DeError> {
|
| 647 | value.serialize(self)
|
| 648 | }
|
| 649 |
|
| 650 | fn serialize_unit(self) -> Result<Self::Ok, DeError> {
|
| 651 | self.ser("`()`" )?.serialize_unit()
|
| 652 | }
|
| 653 |
|
| 654 | fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, DeError> {
|
| 655 | self.ser_name(name)?.serialize_unit_struct(name)
|
| 656 | }
|
| 657 |
|
| 658 | fn serialize_unit_variant(
|
| 659 | self,
|
| 660 | name: &'static str,
|
| 661 | variant_index: u32,
|
| 662 | variant: &'static str,
|
| 663 | ) -> Result<Self::Ok, DeError> {
|
| 664 | self.ser_name(name)?
|
| 665 | .serialize_unit_variant(name, variant_index, variant)
|
| 666 | }
|
| 667 |
|
| 668 | fn serialize_newtype_struct<T: ?Sized + Serialize>(
|
| 669 | self,
|
| 670 | name: &'static str,
|
| 671 | value: &T,
|
| 672 | ) -> Result<Self::Ok, DeError> {
|
| 673 | self.ser_name(name)?.serialize_newtype_struct(name, value)
|
| 674 | }
|
| 675 |
|
| 676 | fn serialize_newtype_variant<T: ?Sized + Serialize>(
|
| 677 | self,
|
| 678 | name: &'static str,
|
| 679 | variant_index: u32,
|
| 680 | variant: &'static str,
|
| 681 | value: &T,
|
| 682 | ) -> Result<Self::Ok, DeError> {
|
| 683 | self.ser_name(name)?
|
| 684 | .serialize_newtype_variant(name, variant_index, variant, value)
|
| 685 | }
|
| 686 |
|
| 687 | fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, DeError> {
|
| 688 | self.ser("sequence" )?.serialize_seq(len)
|
| 689 | }
|
| 690 |
|
| 691 | fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, DeError> {
|
| 692 | self.ser("unnamed tuple" )?.serialize_tuple(len)
|
| 693 | }
|
| 694 |
|
| 695 | fn serialize_tuple_struct(
|
| 696 | self,
|
| 697 | name: &'static str,
|
| 698 | len: usize,
|
| 699 | ) -> Result<Self::SerializeTupleStruct, DeError> {
|
| 700 | self.ser_name(name)?.serialize_tuple_struct(name, len)
|
| 701 | }
|
| 702 |
|
| 703 | fn serialize_tuple_variant(
|
| 704 | self,
|
| 705 | name: &'static str,
|
| 706 | variant_index: u32,
|
| 707 | variant: &'static str,
|
| 708 | len: usize,
|
| 709 | ) -> Result<Self::SerializeTupleVariant, DeError> {
|
| 710 | self.ser_name(name)?
|
| 711 | .serialize_tuple_variant(name, variant_index, variant, len)
|
| 712 | }
|
| 713 |
|
| 714 | fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, DeError> {
|
| 715 | self.ser("map" )?.serialize_map(len)
|
| 716 | }
|
| 717 |
|
| 718 | fn serialize_struct(
|
| 719 | self,
|
| 720 | name: &'static str,
|
| 721 | len: usize,
|
| 722 | ) -> Result<Self::SerializeStruct, DeError> {
|
| 723 | self.ser_name(name)?.serialize_struct(name, len)
|
| 724 | }
|
| 725 |
|
| 726 | fn serialize_struct_variant(
|
| 727 | self,
|
| 728 | name: &'static str,
|
| 729 | variant_index: u32,
|
| 730 | variant: &'static str,
|
| 731 | len: usize,
|
| 732 | ) -> Result<Self::SerializeStructVariant, DeError> {
|
| 733 | self.ser_name(name)?
|
| 734 | .serialize_struct_variant(name, variant_index, variant, len)
|
| 735 | }
|
| 736 | }
|
| 737 | |