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 
187 pub mod de;
188 mod error;
189 pub mod ser;
190 
191 pub use crate::de::{from_reader, from_str, Deserializer};
192 pub use crate::error::Error;
193 pub use crate::ser::{to_string, to_writer, Serializer};
194 pub use xml::reader::{EventReader, ParserConfig};
195