serde_xml_rs/
lib.rs

1//! # Serde XML
2//!
3//! XML is a flexible markup language that is still used for sharing data between applications or
4//! for writing configuration files.
5//!
6//! Serde XML provides a way to convert between text and strongly-typed Rust data structures.
7//!
8//! ## Caveats
9//!
10//! The Serde framework was mainly designed with formats such as JSON or YAML in mind.
11//! As opposed to XML, these formats have the advantage of a stricter syntax which makes it
12//! possible to know what type a field is without relying on an accompanying schema,
13//! and disallows repeating the same tag multiple times in the same object.
14//!
15//! For example, encoding the following document in YAML is not trivial.
16//!
17//! ```xml
18//! <document>
19//!   <header>A header</header>
20//!   <section>First section</section>
21//!   <section>Second section</section>
22//!   <sidenote>A sidenote</sidenote>
23//!   <section>Third section</section>
24//!   <sidenote>Another sidenote</sidenote>
25//!   <section>Fourth section</section>
26//!   <footer>The footer</footer>
27//! </document>
28//! ```
29//!
30//! One possibility is the following YAML document.
31//!
32//! ```yaml
33//! - header: A header
34//! - section: First section
35//! - section: Second section
36//! - sidenote: A sidenote
37//! - section: Third section
38//! - sidenote: Another sidenote
39//! - section: Fourth section
40//! - footer: The footer
41//! ```
42//!
43//! Other notable differences:
44//! - XML requires a named root node.
45//! - XML has a namespace system.
46//! - XML distinguishes between attributes, child tags and contents.
47//! - In XML, the order of nodes is sometimes important.
48//!
49//! ## Basic example
50//!
51//! ```rust
52//! use serde::{Deserialize, Serialize};
53//! use serde_xml_rs::{from_str, to_string};
54//!
55//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
56//! struct Item {
57//!     name: String,
58//!     source: String,
59//! }
60//!
61//! fn main() {
62//!     let src = r#"<?xml version="1.0" encoding="UTF-8"?><Item><name>Banana</name><source>Store</source></Item>"#;
63//!     let should_be = Item {
64//!         name: "Banana".to_string(),
65//!         source: "Store".to_string(),
66//!     };
67//!
68//!     let item: Item = from_str(src).unwrap();
69//!     assert_eq!(item, should_be);
70//!
71//!     let reserialized_item = to_string(&item).unwrap();
72//!     assert_eq!(src, reserialized_item);
73//! }
74//! ```
75//!
76//! ## Tag contents
77//!
78//! ```rust
79//! # use serde::{Deserialize, Serialize};
80//! # use serde_xml_rs::{from_str, to_string};
81//!
82//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
83//! struct Document {
84//!     content: Content
85//! }
86//!
87//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
88//! struct Content {
89//!     #[serde(rename = "$value")]
90//!     value: String
91//! }
92//!
93//! fn main() {
94//!     let src = r#"<document><content>Lorem ipsum</content></document>"#;
95//!     let document: Document = from_str(src).unwrap();
96//!     assert_eq!(document.content.value, "Lorem ipsum");
97//! }
98//! ```
99//!
100//! ## Repeated tags
101//!
102//! ```rust
103//! # use serde::{Deserialize, Serialize};
104//! # use serde_xml_rs::{from_str, to_string};
105//!
106//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
107//! struct PlateAppearance {
108//!     #[serde(rename = "$value")]
109//!     events: Vec<Event>
110//! }
111//!
112//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
113//! #[serde(rename_all = "kebab-case")]
114//! enum Event {
115//!     Pitch(Pitch),
116//!     Runner(Runner),
117//! }
118//!
119//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
120//! struct Pitch {
121//!     speed: u32,
122//!     r#type: PitchType,
123//!     outcome: PitchOutcome,
124//! }
125//!
126//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
127//! enum PitchType { FourSeam, TwoSeam, Changeup, Cutter, Curve, Slider, Knuckle, Pitchout }
128//!
129//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
130//! enum PitchOutcome { Ball, Strike, Hit }
131//!
132//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
133//! struct Runner {
134//!     from: Base, to: Option<Base>, outcome: RunnerOutcome,
135//! }
136//!
137//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
138//! enum Base { First, Second, Third, Home }
139//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
140//! enum RunnerOutcome { Steal, Caught, PickOff }
141//!
142//! fn main() {
143//!     let document = r#"
144//!         <plate-appearance>
145//!           <pitch speed="95" type="FourSeam" outcome="Ball" />
146//!           <pitch speed="91" type="FourSeam" outcome="Strike" />
147//!           <pitch speed="85" type="Changeup" outcome="Ball" />
148//!           <runner from="First" to="Second" outcome="Steal" />
149//!           <pitch speed="89" type="Slider" outcome="Strike" />
150//!           <pitch speed="88" type="Curve" outcome="Hit" />
151//!         </plate-appearance>"#;
152//!     let plate_appearance: PlateAppearance = from_str(document).unwrap();
153//!     assert_eq!(plate_appearance.events[0], Event::Pitch(Pitch { speed: 95, r#type: PitchType::FourSeam, outcome: PitchOutcome::Ball }));
154//! }
155//! ```
156//!
157//! ## Custom EventReader
158//!
159//! ```rust
160//! use serde::{Deserialize, Serialize};
161//! use serde_xml_rs::{from_str, to_string, de::Deserializer};
162//! use xml::reader::{EventReader, ParserConfig};
163//!
164//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
165//! struct Item {
166//!     name: String,
167//!     source: String,
168//! }
169//!
170//! fn main() {
171//!     let src = r#"<Item><name>  Banana  </name><source>Store</source></Item>"#;
172//!     let should_be = Item {
173//!         name: "  Banana  ".to_string(),
174//!         source: "Store".to_string(),
175//!     };
176//!
177//!     let config = ParserConfig::new()
178//!         .trim_whitespace(false)
179//!         .whitespace_to_characters(true);
180//!     let event_reader = EventReader::new_with_config(src.as_bytes(), config);
181//!     let item = Item::deserialize(&mut Deserializer::new(event_reader)).unwrap();
182//!     assert_eq!(item, should_be);
183//! }
184//! ```
185//!
186
187pub mod de;
188mod error;
189pub mod ser;
190
191pub use crate::de::{from_reader, from_str, Deserializer};
192pub use crate::error::Error;
193pub use crate::ser::{to_string, to_writer, Serializer};
194pub use xml::reader::{EventReader, ParserConfig};