Skip to content

Commit 13a68b0

Browse files
committed
Add an example for deserializing wrapped lists
As promised in #369 (comment)
1 parent 99f408a commit 13a68b0

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

src/de/mod.rs

Lines changed: 104 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
//!
@@ -892,6 +894,8 @@
892894
//! Currently not working. The bug is tracked in [#510].
893895
//! </div>
894896
//!
897+
//! See also [Frequently Used Patterns](#element-lists).
898+
//!
895899
//! [field]: https://serde.rs/field-attrs.html#default
896900
//! [struct]: https://serde.rs/container-attrs.html#default
897901
//! </td>
@@ -1571,11 +1575,111 @@
15711575
//! that is not enforced, so you can theoretically have both, but you should
15721576
//! avoid that.
15731577
//!
1578+
//!
1579+
//!
1580+
//! Frequently Used Patterns
1581+
//! ========================
1582+
//!
1583+
//! Some XML constructs used so frequent, that it is worth to document the recommended
1584+
//! way to represent them in the Rust. The sections below describes them.
1585+
//!
1586+
//! ## `<element>` lists
1587+
//! Many XML formats wrap lists of elements in the additional container,
1588+
//! although this is not required by the XML rules:
1589+
//!
1590+
//! ```xml
1591+
//! <root>
1592+
//! <field1/>
1593+
//! <field2/>
1594+
//! <list><!-- Container -->
1595+
//! <element/>
1596+
//! <element/>
1597+
//! <element/>
1598+
//! </list>
1599+
//! <field3/>
1600+
//! </root>
1601+
//! ```
1602+
//! In this case, there is a great desire to describe this XML in this way:
1603+
//! ```
1604+
//! /// Represents <element/>
1605+
//! type Element = ();
1606+
//!
1607+
//! /// Represents <root>...</root>
1608+
//! struct AnyName {
1609+
//! // Incorrect
1610+
//! list: Vec<Element>,
1611+
//! }
1612+
//! ```
1613+
//! This will not work, because potentially `<list>` element can have attributes
1614+
//! and other elements inside. You should define the struct for the `<list>`
1615+
//! explicitly, as you do that in the XSD for that XML:
1616+
//! ```
1617+
//! /// Represents <element/>
1618+
//! type Element = ();
1619+
//!
1620+
//! /// Represents <root>...</root>
1621+
//! struct AnyName {
1622+
//! // Correct
1623+
//! list: List,
1624+
//! }
1625+
//! struct List {
1626+
//! element: Vec<Element>,
1627+
//! }
1628+
//! ```
1629+
//!
1630+
//! If you want to simplify your API, you could write a simple function for unwrapping
1631+
//! inner list and apply it via [`deserialize_with`]:
1632+
//!
1633+
//! ```
1634+
//! # use pretty_assertions::assert_eq;
1635+
//! use quick_xml::de::from_str;
1636+
//! use serde::{Deserialize, Deserializer};
1637+
//!
1638+
//! /// Represents <element/>
1639+
//! type Element = ();
1640+
//!
1641+
//! /// Represents <root>...</root>
1642+
//! #[derive(Deserialize, Debug, PartialEq)]
1643+
//! struct AnyName {
1644+
//! #[serde(deserialize_with = "unwrap_list")]
1645+
//! list: Vec<Element>,
1646+
//! }
1647+
//!
1648+
//! fn unwrap_list<'de, D>(deserializer: D) -> Result<Vec<Element>, D::Error>
1649+
//! where
1650+
//! D: Deserializer<'de>,
1651+
//! {
1652+
//! #[derive(Deserialize)]
1653+
//! struct List {
1654+
//! // default allows empty list
1655+
//! #[serde(default)]
1656+
//! element: Vec<Element>,
1657+
//! }
1658+
//! Ok(List::deserialize(deserializer)?.element)
1659+
//! }
1660+
//!
1661+
//! assert_eq!(
1662+
//! AnyName { list: vec![(), (), ()] },
1663+
//! from_str("
1664+
//! <root>
1665+
//! <list>
1666+
//! <element/>
1667+
//! <element/>
1668+
//! <element/>
1669+
//! </list>
1670+
//! </root>
1671+
//! ").unwrap(),
1672+
//! );
1673+
//! ```
1674+
//!
1675+
//! Instead of writing such functions manually, you also could try <https://lib.rs/crates/serde-query>.
1676+
//!
15741677
//! [text]: Event::Text
15751678
//! [CDATA]: Event::CData
15761679
//! [buggy]: https://github.com/serde-rs/serde/issues/1183
15771680
//! [do not support]: https://github.com/serde-rs/serde/issues/1905
15781681
//! [specification]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
1682+
//! [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with
15791683
//! [#474]: https://github.com/tafia/quick-xml/issues/474
15801684
//! [#497]: https://github.com/tafia/quick-xml/issues/497
15811685
//! [#510]: https://github.com/tafia/quick-xml/issues/510

0 commit comments

Comments
 (0)