|
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 | //!
|
|
892 | 894 | //! Currently not working. The bug is tracked in [#510].
|
893 | 895 | //! </div>
|
894 | 896 | //!
|
| 897 | +//! See also [Frequently Used Patterns](#element-lists). |
| 898 | +//! |
895 | 899 | //! [field]: https://serde.rs/field-attrs.html#default
|
896 | 900 | //! [struct]: https://serde.rs/container-attrs.html#default
|
897 | 901 | //! </td>
|
|
1571 | 1575 | //! that is not enforced, so you can theoretically have both, but you should
|
1572 | 1576 | //! avoid that.
|
1573 | 1577 | //!
|
| 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 | +//! |
1574 | 1677 | //! [text]: Event::Text
|
1575 | 1678 | //! [CDATA]: Event::CData
|
1576 | 1679 | //! [buggy]: https://github.com/serde-rs/serde/issues/1183
|
1577 | 1680 | //! [do not support]: https://github.com/serde-rs/serde/issues/1905
|
1578 | 1681 | //! [specification]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
|
| 1682 | +//! [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with |
1579 | 1683 | //! [#474]: https://github.com/tafia/quick-xml/issues/474
|
1580 | 1684 | //! [#497]: https://github.com/tafia/quick-xml/issues/497
|
1581 | 1685 | //! [#510]: https://github.com/tafia/quick-xml/issues/510
|
|
0 commit comments