|
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 | //! |
|
1431 | 1485 | //! get their names from the field name. It cannot be deserialized, because `Enum` |
1432 | 1486 | //! expects elements `<A/>`, `<B/>` or `<C/>`, but `AnyName` looked only for `<field/>`: |
1433 | 1487 | //! |
1434 | | -//! ```no_run |
| 1488 | +//! ``` |
1435 | 1489 | //! # use serde::{Deserialize, Serialize}; |
| 1490 | +//! # use pretty_assertions::assert_eq; |
| 1491 | +//! # #[derive(PartialEq, Debug)] |
1436 | 1492 | //! #[derive(Deserialize, Serialize)] |
1437 | 1493 | //! enum Enum { A, B, C } |
1438 | 1494 | //! |
| 1495 | +//! # #[derive(PartialEq, Debug)] |
1439 | 1496 | //! #[derive(Deserialize, Serialize)] |
1440 | 1497 | //! struct AnyName { |
1441 | | -//! // <field/> |
| 1498 | +//! // <field>A</field>, <field>B</field>, or <field>C</field> |
1442 | 1499 | //! field: Enum, |
1443 | 1500 | //! } |
| 1501 | +//! # assert_eq!( |
| 1502 | +//! # quick_xml::se::to_string(&AnyName { field: Enum::A }).unwrap(), |
| 1503 | +//! # "<AnyName><field>A</field></AnyName>", |
| 1504 | +//! # ); |
| 1505 | +//! # assert_eq!( |
| 1506 | +//! # AnyName { field: Enum::B }, |
| 1507 | +//! # quick_xml::de::from_str("<root><field>B</field></root>").unwrap(), |
| 1508 | +//! # ); |
1444 | 1509 | //! ``` |
1445 | 1510 | //! |
1446 | 1511 | //! If you rename field to `$value`, then `field` would be serialized as `<A/>`, |
1447 | 1512 | //! `<B/>` or `<C/>`, depending on the its content. It is also possible to |
1448 | 1513 | //! deserialize it from the same elements: |
1449 | 1514 | //! |
1450 | | -//! ```no_run |
| 1515 | +//! ``` |
1451 | 1516 | //! # use serde::{Deserialize, Serialize}; |
1452 | | -//! # #[derive(Deserialize, Serialize)] |
| 1517 | +//! # use pretty_assertions::assert_eq; |
| 1518 | +//! # #[derive(Deserialize, Serialize, PartialEq, Debug)] |
1453 | 1519 | //! # enum Enum { A, B, C } |
1454 | 1520 | //! # |
| 1521 | +//! # #[derive(PartialEq, Debug)] |
1455 | 1522 | //! #[derive(Deserialize, Serialize)] |
1456 | 1523 | //! struct AnyName { |
1457 | 1524 | //! // <A/>, <B/> or <C/> |
1458 | 1525 | //! #[serde(rename = "$value")] |
1459 | 1526 | //! field: Enum, |
1460 | 1527 | //! } |
| 1528 | +//! # assert_eq!( |
| 1529 | +//! # quick_xml::se::to_string(&AnyName { field: Enum::A }).unwrap(), |
| 1530 | +//! # "<AnyName><A/></AnyName>", |
| 1531 | +//! # ); |
| 1532 | +//! # assert_eq!( |
| 1533 | +//! # AnyName { field: Enum::B }, |
| 1534 | +//! # quick_xml::de::from_str("<root><B/></root>").unwrap(), |
| 1535 | +//! # ); |
1461 | 1536 | //! ``` |
1462 | 1537 | //! |
1463 | 1538 | //! ### Primitives and sequences of primitives |
|
1467 | 1542 | //! |
1468 | 1543 | //! ``` |
1469 | 1544 | //! # use serde::{Deserialize, Serialize}; |
| 1545 | +//! # use pretty_assertions::assert_eq; |
1470 | 1546 | //! # use quick_xml::de::from_str; |
1471 | 1547 | //! # use quick_xml::se::to_string; |
1472 | 1548 | //! #[derive(Deserialize, Serialize, PartialEq, Debug)] |
|
1493 | 1569 | //! |
1494 | 1570 | //! ``` |
1495 | 1571 | //! # use serde::{Deserialize, Serialize}; |
| 1572 | +//! # use pretty_assertions::assert_eq; |
1496 | 1573 | //! # use quick_xml::de::from_str; |
1497 | 1574 | //! # use quick_xml::se::to_string; |
1498 | 1575 | //! #[derive(Deserialize, Serialize, PartialEq, Debug)] |
|
1516 | 1593 | //! |
1517 | 1594 | //! ``` |
1518 | 1595 | //! # use serde::{Deserialize, Serialize}; |
| 1596 | +//! # use pretty_assertions::assert_eq; |
1519 | 1597 | //! # use quick_xml::de::from_str; |
1520 | 1598 | //! # use quick_xml::se::to_string; |
1521 | 1599 | //! #[derive(Deserialize, Serialize, PartialEq, Debug)] |
|
1549 | 1627 | //! |
1550 | 1628 | //! ``` |
1551 | 1629 | //! # use serde::{Deserialize, Serialize}; |
| 1630 | +//! # use pretty_assertions::assert_eq; |
1552 | 1631 | //! # use quick_xml::de::from_str; |
1553 | 1632 | //! # use quick_xml::se::to_string; |
1554 | 1633 | //! #[derive(Deserialize, Serialize, PartialEq, Debug)] |
|
1708 | 1787 | //! } |
1709 | 1788 | //! ``` |
1710 | 1789 | //! |
1711 | | -//! Enum::Unit Variants As a Text |
1712 | | -//! ----------------------------- |
1713 | | -//! One frequent task and a typical mistake is to creation of mapping a text |
1714 | | -//! content of some tag to a Rust `enum`. For example, for the XML: |
1715 | | -//! |
1716 | | -//! ```xml |
1717 | | -//! <some-container> |
1718 | | -//! <field>EnumValue</field> |
1719 | | -//! </some-container> |
1720 | | -//! ``` |
1721 | | -//! one could create an _incorrect_ mapping |
1722 | | -//! |
1723 | | -//! ``` |
1724 | | -//! # use serde::{Deserialize, Serialize}; |
1725 | | -//! # |
1726 | | -//! #[derive(Serialize, Deserialize)] |
1727 | | -//! enum SomeEnum { |
1728 | | -//! EnumValue, |
1729 | | -//! # /* |
1730 | | -//! ... |
1731 | | -//! # */ |
1732 | | -//! } |
1733 | | -//! |
1734 | | -//! #[derive(Serialize, Deserialize)] |
1735 | | -//! #[serde(rename = "some-container")] |
1736 | | -//! struct SomeContainer { |
1737 | | -//! field: SomeEnum, |
1738 | | -//! } |
1739 | | -//! ``` |
1740 | | -//! |
1741 | | -//! Actually, those types will be serialized into: |
1742 | | -//! ```xml |
1743 | | -//! <some-container> |
1744 | | -//! <EnumValue/> |
1745 | | -//! </some-container> |
1746 | | -//! ``` |
1747 | | -//! and will not be able to be deserialized. |
1748 | | -//! |
1749 | | -//! You can easily see what's wrong if you think about attributes, which could |
1750 | | -//! be defined in the `<field>` tag: |
1751 | | -//! ```xml |
1752 | | -//! <some-container> |
1753 | | -//! <field some="attribute">EnumValue</field> |
1754 | | -//! </some-container> |
1755 | | -//! ``` |
1756 | | -//! |
1757 | | -//! After that you can find the correct solution, using the principles explained |
1758 | | -//! above. You should wrap `SomeEnum` into wrapper struct under the [`$text`](#text) |
1759 | | -//! name: |
1760 | | -//! ``` |
1761 | | -//! # use serde::{Serialize, Deserialize}; |
1762 | | -//! # type SomeEnum = (); |
1763 | | -//! #[derive(Serialize, Deserialize)] |
1764 | | -//! struct Field { |
1765 | | -//! // Use a special name `$text` to map field to the text content |
1766 | | -//! #[serde(rename = "$text")] |
1767 | | -//! content: SomeEnum, |
1768 | | -//! } |
1769 | | -//! |
1770 | | -//! #[derive(Serialize, Deserialize)] |
1771 | | -//! #[serde(rename = "some-container")] |
1772 | | -//! struct SomeContainer { |
1773 | | -//! field: Field, |
1774 | | -//! } |
1775 | | -//! ``` |
1776 | | -//! |
1777 | | -//! If you still want to keep your struct untouched, you can instead use the |
1778 | | -//! helper module [`text_content`]. |
1779 | | -//! |
1780 | 1790 | //! |
1781 | 1791 | //! Internally Tagged Enums |
1782 | 1792 | //! ----------------------- |
|
1794 | 1804 | //! [specification]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition |
1795 | 1805 | //! [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with |
1796 | 1806 | //! [#497]: https://github.com/tafia/quick-xml/issues/497 |
1797 | | -//! [`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 |
1798 | 1809 | //! [Tagged enums]: https://serde.rs/enum-representations.html#internally-tagged |
1799 | 1810 | //! [serde#1183]: https://github.com/serde-rs/serde/issues/1183 |
1800 | 1811 | //! [serde#1495]: https://github.com/serde-rs/serde/issues/1495 |
|
0 commit comments