diff --git a/src/de/mod.rs b/src/de/mod.rs index 4d205242..744cd08e 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -25,6 +25,8 @@ //! - [Primitives and sequences of primitives](#primitives-and-sequences-of-primitives) //! - [Structs and sequences of structs](#structs-and-sequences-of-structs) //! - [Enums and sequences of enums](#enums-and-sequences-of-enums) +//! - [Frequently Used Patterns](#frequently-used-patterns) +//! - [`` lists](#element-lists) //! //! //! @@ -892,6 +894,8 @@ //! Currently not working. The bug is tracked in [#510]. //! //! +//! See also [Frequently Used Patterns](#element-lists). +//! //! [field]: https://serde.rs/field-attrs.html#default //! [struct]: https://serde.rs/container-attrs.html#default //! @@ -1571,11 +1575,111 @@ //! that is not enforced, so you can theoretically have both, but you should //! avoid that. //! +//! +//! +//! Frequently Used Patterns +//! ======================== +//! +//! Some XML constructs used so frequent, that it is worth to document the recommended +//! way to represent them in the Rust. The sections below describes them. +//! +//! ## `` lists +//! Many XML formats wrap lists of elements in the additional container, +//! although this is not required by the XML rules: +//! +//! ```xml +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! ``` +//! In this case, there is a great desire to describe this XML in this way: +//! ``` +//! /// Represents +//! type Element = (); +//! +//! /// Represents ... +//! struct AnyName { +//! // Incorrect +//! list: Vec, +//! } +//! ``` +//! This will not work, because potentially `` element can have attributes +//! and other elements inside. You should define the struct for the `` +//! explicitly, as you do that in the XSD for that XML: +//! ``` +//! /// Represents +//! type Element = (); +//! +//! /// Represents ... +//! struct AnyName { +//! // Correct +//! list: List, +//! } +//! struct List { +//! element: Vec, +//! } +//! ``` +//! +//! If you want to simplify your API, you could write a simple function for unwrapping +//! inner list and apply it via [`deserialize_with`]: +//! +//! ``` +//! # use pretty_assertions::assert_eq; +//! use quick_xml::de::from_str; +//! use serde::{Deserialize, Deserializer}; +//! +//! /// Represents +//! type Element = (); +//! +//! /// Represents ... +//! #[derive(Deserialize, Debug, PartialEq)] +//! struct AnyName { +//! #[serde(deserialize_with = "unwrap_list")] +//! list: Vec, +//! } +//! +//! fn unwrap_list<'de, D>(deserializer: D) -> Result, D::Error> +//! where +//! D: Deserializer<'de>, +//! { +//! #[derive(Deserialize)] +//! struct List { +//! // default allows empty list +//! #[serde(default)] +//! element: Vec, +//! } +//! Ok(List::deserialize(deserializer)?.element) +//! } +//! +//! assert_eq!( +//! AnyName { list: vec![(), (), ()] }, +//! from_str(" +//! +//! +//! +//! +//! +//! +//! +//! ").unwrap(), +//! ); +//! ``` +//! +//! Instead of writing such functions manually, you also could try . +//! //! [text]: Event::Text //! [CDATA]: Event::CData //! [buggy]: https://github.com/serde-rs/serde/issues/1183 //! [do not support]: https://github.com/serde-rs/serde/issues/1905 //! [specification]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition +//! [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with //! [#474]: https://github.com/tafia/quick-xml/issues/474 //! [#497]: https://github.com/tafia/quick-xml/issues/497 //! [#510]: https://github.com/tafia/quick-xml/issues/510