Skip to content

Commit 3973017

Browse files
committed
Add an example for deserializing wrapped lists
As promised in #369 (comment)
1 parent 9097be4 commit 3973017

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

src/de/mod.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
//! - [Primitives and sequences of primitives](#primitives-and-sequences-of-primitives)
2626
//! - [Structs and sequences of structs](#structs-and-sequences-of-structs)
2727
//! - [Enums and sequences of enums](#enums-and-sequences-of-enums)
28+
//! - [Frequently Used Patterns](#frequently-used-patterns)
29+
//! - [`<element>` lists](#element-lists)
2830
//!
2931
//!
3032
//!
@@ -895,6 +897,8 @@
895897
//! Currently not working. The bug is tracked in [#510].
896898
//! </div>
897899
//!
900+
//! See also [Frequently Used Patterns](#element-lists).
901+
//!
898902
//! [field]: https://serde.rs/field-attrs.html#default
899903
//! [struct]: https://serde.rs/container-attrs.html#default
900904
//! </td>
@@ -1579,7 +1583,109 @@
15791583
//! that is not enforced, so you can theoretically have both, but you should
15801584
//! avoid that.
15811585
//!
1586+
//!
1587+
//!
1588+
//! Frequently Used Patterns
1589+
//! ========================
1590+
//!
1591+
//! Some XML constructs used so frequent, that it is worth to document the recommended
1592+
//! way to represent them in the Rust. The sections below describes them.
1593+
//!
1594+
//! ## `<element>` lists
1595+
//! Many XML formats wrap lists of elements in the additional container,
1596+
//! although this is not required by the XML rules:
1597+
//!
1598+
//! ```xml
1599+
//! <root>
1600+
//! <field1/>
1601+
//! <field2/>
1602+
//! <list><!-- Container -->
1603+
//! <element/>
1604+
//! <element/>
1605+
//! <element/>
1606+
//! </list>
1607+
//! <field3/>
1608+
//! </root>
1609+
//! ```
1610+
//! In this case, there is a great desire to describe this XML in this way:
1611+
//! ```
1612+
//! /// Represents <element/>
1613+
//! type Element = ();
1614+
//!
1615+
//! /// Represents <root>...</root>
1616+
//! struct AnyName {
1617+
//! // Incorrect
1618+
//! list: Vec<Element>,
1619+
//! }
1620+
//! ```
1621+
//! This will not work, because potentially `<list>` element can have attributes
1622+
//! and other elements inside. You should define the struct for the `<list>`
1623+
//! explicitly, as you do that in the XSD for that XML:
1624+
//! ```
1625+
//! /// Represents <element/>
1626+
//! type Element = ();
1627+
//!
1628+
//! /// Represents <root>...</root>
1629+
//! struct AnyName {
1630+
//! // Correct
1631+
//! list: List,
1632+
//! }
1633+
//! /// Represents <list>...</list>
1634+
//! struct List {
1635+
//! element: Vec<Element>,
1636+
//! }
1637+
//! ```
1638+
//!
1639+
//! If you want to simplify your API, you could write a simple function for unwrapping
1640+
//! inner list and apply it via [`deserialize_with`]:
1641+
//!
1642+
//! ```
1643+
//! # use pretty_assertions::assert_eq;
1644+
//! use quick_xml::de::from_str;
1645+
//! use serde::{Deserialize, Deserializer};
1646+
//!
1647+
//! /// Represents <element/>
1648+
//! type Element = ();
1649+
//!
1650+
//! /// Represents <root>...</root>
1651+
//! #[derive(Deserialize, Debug, PartialEq)]
1652+
//! struct AnyName {
1653+
//! #[serde(deserialize_with = "unwrap_list")]
1654+
//! list: Vec<Element>,
1655+
//! }
1656+
//!
1657+
//! fn unwrap_list<'de, D>(deserializer: D) -> Result<Vec<Element>, D::Error>
1658+
//! where
1659+
//! D: Deserializer<'de>,
1660+
//! {
1661+
//! /// Represents <list>...</list>
1662+
//! #[derive(Deserialize)]
1663+
//! struct List {
1664+
//! // default allows empty list
1665+
//! #[serde(default)]
1666+
//! element: Vec<Element>,
1667+
//! }
1668+
//! Ok(List::deserialize(deserializer)?.element)
1669+
//! }
1670+
//!
1671+
//! assert_eq!(
1672+
//! AnyName { list: vec![(), (), ()] },
1673+
//! from_str("
1674+
//! <root>
1675+
//! <list>
1676+
//! <element/>
1677+
//! <element/>
1678+
//! <element/>
1679+
//! </list>
1680+
//! </root>
1681+
//! ").unwrap(),
1682+
//! );
1683+
//! ```
1684+
//!
1685+
//! Instead of writing such functions manually, you also could try <https://lib.rs/crates/serde-query>.
1686+
//!
15821687
//! [specification]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
1688+
//! [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with
15831689
//! [#474]: https://github.com/tafia/quick-xml/issues/474
15841690
//! [#497]: https://github.com/tafia/quick-xml/issues/497
15851691
//! [#510]: https://github.com/tafia/quick-xml/issues/510

0 commit comments

Comments
 (0)