|
25 | 25 | //! - [Primitives and sequences of primitives](#primitives-and-sequences-of-primitives)
|
26 | 26 | //! - [Structs and sequences of structs](#structs-and-sequences-of-structs)
|
27 | 27 | //! - [Enums and sequences of enums](#enums-and-sequences-of-enums)
|
| 28 | +//! - [Frequently Used Patterns](#frequently-used-patterns) |
| 29 | +//! - [`<element>` lists](#element-lists) |
28 | 30 | //!
|
29 | 31 | //!
|
30 | 32 | //!
|
|
895 | 897 | //! Currently not working. The bug is tracked in [#510].
|
896 | 898 | //! </div>
|
897 | 899 | //!
|
| 900 | +//! See also [Frequently Used Patterns](#element-lists). |
| 901 | +//! |
898 | 902 | //! [field]: https://serde.rs/field-attrs.html#default
|
899 | 903 | //! [struct]: https://serde.rs/container-attrs.html#default
|
900 | 904 | //! </td>
|
|
1579 | 1583 | //! that is not enforced, so you can theoretically have both, but you should
|
1580 | 1584 | //! avoid that.
|
1581 | 1585 | //!
|
| 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 | +//! |
1582 | 1687 | //! [specification]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
|
| 1688 | +//! [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with |
1583 | 1689 | //! [#474]: https://github.com/tafia/quick-xml/issues/474
|
1584 | 1690 | //! [#497]: https://github.com/tafia/quick-xml/issues/497
|
1585 | 1691 | //! [#510]: https://github.com/tafia/quick-xml/issues/510
|
|
0 commit comments