|
20 | 20 | //! - [Choices (`xs:choice` XML Schema type)](#choices-xschoice-xml-schema-type) |
21 | 21 | //! - [Sequences (`xs:all` and `xs:sequence` XML Schema types)](#sequences-xsall-and-xssequence-xml-schema-types) |
22 | 22 | //! - [Composition Rules](#composition-rules) |
| 23 | +//! - [Enum Representations](#enum-representations) |
| 24 | +//! - [Normal enum variant](#normal-enum-variant) |
| 25 | +//! - [`$text` enum variant](#text-enum-variant) |
23 | 26 | //! - [Difference between `$text` and `$value` special names](#difference-between-text-and-value-special-names) |
24 | 27 | //! - [`$text`](#text) |
25 | 28 | //! - [`$value`](#value) |
|
29 | 32 | //! - [Frequently Used Patterns](#frequently-used-patterns) |
30 | 33 | //! - [`<element>` lists](#element-lists) |
31 | 34 | //! - [Overlapped (Out-of-Order) Elements](#overlapped-out-of-order-elements) |
32 | | -//! - [Enum::Unit Variants As a Text](#enumunit-variants-as-a-text) |
33 | 35 | //! - [Internally Tagged Enums](#internally-tagged-enums) |
34 | 36 | //! |
35 | 37 | //! |
|
1351 | 1353 | //! |
1352 | 1354 | //! |
1353 | 1355 | //! |
| 1356 | +//! Enum Representations |
| 1357 | +//! ==================== |
| 1358 | +//! |
| 1359 | +//! `quick-xml` represents enums differently in normal fields, `$text` fields and |
| 1360 | +//! `$value` fields. A normal representation is compatible with serde's adjacent |
| 1361 | +//! and internal tags feature -- tag for adjacently and internally tagged enums |
| 1362 | +//! are serialized using [`Serializer::serialize_unit_variant`] and deserialized |
| 1363 | +//! using [`Deserializer::deserialize_enum`]. |
| 1364 | +//! |
| 1365 | +//! Use those simple rules to remember, how enum would be represented in XML: |
| 1366 | +//! - In `$value` field the representation is always the same as top-level representation; |
| 1367 | +//! - In `$text` field the representation is always the same as in normal field, |
| 1368 | +//! but surrounding tags with field name are removed; |
| 1369 | +//! - In normal field the representation is always contains a tag with a field name. |
| 1370 | +//! |
| 1371 | +//! Normal enum variant |
| 1372 | +//! ------------------- |
| 1373 | +//! |
| 1374 | +//! To model an `xs:choice` XML construct use `$value` field. |
| 1375 | +//! To model a top-level `xs:choice` just use the enum type. |
| 1376 | +//! |
| 1377 | +//! |Kind |Top-level and in `$value` field |In normal field |In `$text` field | |
| 1378 | +//! |-------|-----------------------------------------|---------------------|---------------------| |
| 1379 | +//! |Unit |`<Unit/>` |`<field>Unit</field>`|`Unit` | |
| 1380 | +//! |Newtype|`<Newtype>42</Newtype>` |Err(Unsupported) |Err(Unsupported) | |
| 1381 | +//! |Tuple |`<Tuple>42</Tuple><Tuple>answer</Tuple>` |Err(Unsupported) |Err(Unsupported) | |
| 1382 | +//! |Struct |`<Struct><q>42</q><a>answer</a></Struct>`|Err(Unsupported) |Err(Unsupported) | |
| 1383 | +//! |
| 1384 | +//! `$text` enum variant |
| 1385 | +//! -------------------- |
| 1386 | +//! |
| 1387 | +//! |Kind |Top-level and in `$value` field |In normal field |In `$text` field | |
| 1388 | +//! |-------|-----------------------------------------|---------------------|---------------------| |
| 1389 | +//! |Unit |_(empty)_ |`<field/>` |_(empty)_ | |
| 1390 | +//! |Newtype|`42` |Err(Unsupported) [^1]|Err(Unsupported) [^2]| |
| 1391 | +//! |Tuple |`42 answer` |Err(Unsupported) [^3]|Err(Unsupported) [^4]| |
| 1392 | +//! |Struct |Err(Unsupported) |Err(Unsupported) |Err(Unsupported) | |
| 1393 | +//! |
| 1394 | +//! [^1]: If this serialize as `<field>42</field>` then it will be ambiguity during deserialization, |
| 1395 | +//! because it clash with `Unit` representation in normal field. |
| 1396 | +//! |
| 1397 | +//! [^2]: If this serialize as `42` then it will be ambiguity during deserialization, |
| 1398 | +//! because it clash with `Unit` representation in `$text` field. |
| 1399 | +//! |
| 1400 | +//! [^3]: If this serialize as `<field>42 answer</field>` then it will be ambiguity during deserialization, |
| 1401 | +//! because it clash with `Unit` representation in normal field. |
| 1402 | +//! |
| 1403 | +//! [^4]: If this serialize as `42 answer` then it will be ambiguity during deserialization, |
| 1404 | +//! because it clash with `Unit` representation in `$text` field. |
| 1405 | +//! |
| 1406 | +//! |
| 1407 | +//! |
1354 | 1408 | //! Difference between `$text` and `$value` special names |
1355 | 1409 | //! ===================================================== |
1356 | 1410 | //! |
|
1733 | 1787 | //! } |
1734 | 1788 | //! ``` |
1735 | 1789 | //! |
1736 | | -//! Enum::Unit Variants As a Text |
1737 | | -//! ----------------------------- |
1738 | | -//! One frequent task and a typical mistake is to creation of mapping a text |
1739 | | -//! content of some tag to a Rust `enum`. For example, for the XML: |
1740 | | -//! |
1741 | | -//! ```xml |
1742 | | -//! <some-container> |
1743 | | -//! <field>EnumValue</field> |
1744 | | -//! </some-container> |
1745 | | -//! ``` |
1746 | | -//! one could create an _incorrect_ mapping |
1747 | | -//! |
1748 | | -//! ``` |
1749 | | -//! # use serde::{Deserialize, Serialize}; |
1750 | | -//! # |
1751 | | -//! #[derive(Serialize, Deserialize)] |
1752 | | -//! enum SomeEnum { |
1753 | | -//! EnumValue, |
1754 | | -//! # /* |
1755 | | -//! ... |
1756 | | -//! # */ |
1757 | | -//! } |
1758 | | -//! |
1759 | | -//! #[derive(Serialize, Deserialize)] |
1760 | | -//! #[serde(rename = "some-container")] |
1761 | | -//! struct SomeContainer { |
1762 | | -//! field: SomeEnum, |
1763 | | -//! } |
1764 | | -//! ``` |
1765 | | -//! |
1766 | | -//! Actually, those types will be serialized into: |
1767 | | -//! ```xml |
1768 | | -//! <some-container> |
1769 | | -//! <EnumValue/> |
1770 | | -//! </some-container> |
1771 | | -//! ``` |
1772 | | -//! and will not be able to be deserialized. |
1773 | | -//! |
1774 | | -//! You can easily see what's wrong if you think about attributes, which could |
1775 | | -//! be defined in the `<field>` tag: |
1776 | | -//! ```xml |
1777 | | -//! <some-container> |
1778 | | -//! <field some="attribute">EnumValue</field> |
1779 | | -//! </some-container> |
1780 | | -//! ``` |
1781 | | -//! |
1782 | | -//! After that you can find the correct solution, using the principles explained |
1783 | | -//! above. You should wrap `SomeEnum` into wrapper struct under the [`$text`](#text) |
1784 | | -//! name: |
1785 | | -//! ``` |
1786 | | -//! # use serde::{Serialize, Deserialize}; |
1787 | | -//! # type SomeEnum = (); |
1788 | | -//! #[derive(Serialize, Deserialize)] |
1789 | | -//! struct Field { |
1790 | | -//! // Use a special name `$text` to map field to the text content |
1791 | | -//! #[serde(rename = "$text")] |
1792 | | -//! content: SomeEnum, |
1793 | | -//! } |
1794 | | -//! |
1795 | | -//! #[derive(Serialize, Deserialize)] |
1796 | | -//! #[serde(rename = "some-container")] |
1797 | | -//! struct SomeContainer { |
1798 | | -//! field: Field, |
1799 | | -//! } |
1800 | | -//! ``` |
1801 | | -//! |
1802 | | -//! If you still want to keep your struct untouched, you can instead use the |
1803 | | -//! helper module [`text_content`]. |
1804 | | -//! |
1805 | 1790 | //! |
1806 | 1791 | //! Internally Tagged Enums |
1807 | 1792 | //! ----------------------- |
|
1819 | 1804 | //! [specification]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition |
1820 | 1805 | //! [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with |
1821 | 1806 | //! [#497]: https://github.com/tafia/quick-xml/issues/497 |
1822 | | -//! [`text_content`]: crate::serde_helpers::text_content |
| 1807 | +//! [`Serializer::serialize_unit_variant`]: serde::Serializer::serialize_unit_variant |
| 1808 | +//! [`Deserializer::deserialize_enum`]: serde::Deserializer::deserialize_enum |
1823 | 1809 | //! [Tagged enums]: https://serde.rs/enum-representations.html#internally-tagged |
1824 | 1810 | //! [serde#1183]: https://github.com/serde-rs/serde/issues/1183 |
1825 | 1811 | //! [serde#1495]: https://github.com/serde-rs/serde/issues/1495 |
|
0 commit comments