xmlserde/lib.rs
1//! `xmlserde` is another tool for serializing and deserializing XML. It is designed
2//! for easy and clear use.
3//!
4//! Please add these dependencies in your `Cargo.toml`.
5//! ```toml
6//! xmlserde = "0.10"
7//! xmlserde_derives = "0.10"
8//! ```
9//!
10//! # Deserialize
11//! Suppose that XML struct is to be deserialized as below:
12//! ```xml
13//! <person age="8">
14//! <name>Jeremy</name>
15//! <pet t="cat">Tom</pet>
16//! <pet t="dog">Spike</pet>
17//! </person>
18//! ```
19//! You can create a struct and derive the `XmlDeserialize` from `xmlserde_derives`, like:
20//! ```ignore
21//! use xmlserde_derives::XmlDeserialize;
22//! #[derive(XmlDeserialize)]
23//! pub struct Person {
24//! #[xmlserde(name = b"age", ty = "attr")]
25//! pub age: u16,
26//! #[xmlserde(name = b"pet", ty = "child")]
27//! pub pets: Vec<Pet>,
28//! }
29//!
30//! #[derive(XmlDeserialize)]
31//! pub struct Pet {
32//! #[xmlserde(name = b"t", ty = "attr")]
33//! pub t: String,
34//! #[xmlserde(ty = "text")]
35//! pub name: String,
36//! }
37//! ```
38//! In `xmlserde`, you need to declare clearly that which tag and which type you are going to `serde`.
39//! Notice that it is a binary string for the `name`.
40//!
41//! # Serialize
42//! As for serializing, you need to derive the `XmlSerialize`.
43//!
44//! # Enum
45//! ## For attribute value
46//! Please check in `xml_serde_enum` section.
47//!
48//! ## For children element
49//! You can define an enum like this.
50//! ```ignore
51//! #[derive(XmlSerialize, Deserialize)]
52//! pub enum Pet{
53//! #[xmlserde(name = b"dog")]
54//! Dog(Dog),
55//! #[xmlserde(name = b"cat")]
56//! Cat(Cat),
57//! }
58//! pub struct Dog{}
59//! pub struct Cat{}
60//! ```
61//! In a field whose type is an `enum`, we can use `ty = untag`:
62//! ```ignore
63//! #[derive(XmlSerialize, Deserialize)]
64//! pub struct Person {
65//! #[xmlserde(ty="untag")]
66//! pub pet: Pet,
67//! }
68//! ```
69//! In this case, `Person` can be serialized as
70//! ```xml
71//! <person>
72//! <dog>
73//! ...
74//! </dog>
75//! </person>
76//! ```
77//! or
78//! ```xml
79//! <person>
80//! <cat>
81//! ...
82//! </cat>
83//! </person>
84//! ```
85//!
86//! # Attributes
87//! - name: the tag of the XML element.
88//! - vec_size: creating a vector with the given capacity before deserilizing a element lists. `vec_size=4` or if your initial capacity is defined in an attr, you can use like this `vec_size="cnt"`.
89//! - default: assigning a parameter-free function to create a default value for a certain field. Notice that it requires the type of this value impls `Eq` and it will skip serializing when the value equals to the default one.
90//! - untag: see the `Enum` above.
91//!
92//! # Examples
93//! Please see [LogiSheets](https://github.com/proclml/LogiSheets/tree/master/crates/workbook) for examples.
94
95/// A macro to help you create mappings between string values in XML and Rust enums.
96///
97/// For example, we can define a mapping like this:
98/// ```
99/// use xmlserde::xml_serde_enum;
100/// xml_serde_enum!{
101/// #[derive(Debug, Clone)]
102/// Gender{
103/// Male => "male",
104/// Female => "female",
105/// }
106/// }
107/// ```
108/// After expansion, you can find an enum is defined like this:
109/// ```
110/// #[derive(Debug, Clone)]
111/// pub enum Gender {
112/// Male,
113/// Female,
114/// }
115/// ```
116/// And string value of `male` will be deserialized as `Gender::Male` while `female` will be as `Gender::Female`.
117/// In the same way, `Gender` will be serialized as `male` of `female`.
118///
119/// Panic if the given string is out of `male` and `female`.
120#[macro_export]
121macro_rules! xml_serde_enum {
122 (
123 $(#[$outer:meta])*
124 $name:ident {
125 $($f:ident => $s:literal,)*
126 }
127 ) => {
128 #[warn(dead_code)]
129 $(#[$outer])*
130 pub enum $name {
131 $($f,)*
132 }
133
134 impl xmlserde::XmlValue for $name {
135 fn serialize(&self) -> String {
136 match &self {
137 $(Self::$f => String::from($s),)*
138 }
139 }
140 fn deserialize(s: &str) -> Result<Self, String> {
141 match s {
142 $($s => Ok(Self::$f),)*
143 _ => Err(String::from("")),
144 }
145 }
146 }
147 };
148}
149
150use std::{
151 fmt::Debug,
152 io::{BufRead, Write},
153};
154
155// We republic the `quick_xml` here is for helping the `derives` crate import
156// it easily. In this way users don't need to import the `quick-xml` on
157// their own.
158pub use quick_xml;
159
160use quick_xml::events::Event;
161
162pub trait XmlSerialize {
163 fn serialize<W: Write>(&self, tag: &[u8], writer: &mut quick_xml::Writer<W>);
164 fn ser_root() -> Option<&'static [u8]> {
165 None
166 }
167}
168
169impl<T: XmlSerialize> XmlSerialize for Option<T> {
170 fn serialize<W: Write>(&self, tag: &[u8], writer: &mut quick_xml::Writer<W>) {
171 match self {
172 Some(t) => t.serialize(tag, writer),
173 None => {}
174 }
175 }
176}
177
178impl<T: XmlSerialize> XmlSerialize for Vec<T> {
179 fn serialize<W: Write>(&self, _tag_: &[u8], _writer_: &mut quick_xml::Writer<W>) {
180 self.iter().for_each(|c| {
181 let _ = c.serialize(_tag_, _writer_);
182 });
183 }
184}
185
186pub trait XmlDeserialize: Sized {
187 fn deserialize<B: BufRead>(
188 tag: &[u8],
189 reader: &mut quick_xml::Reader<B>,
190 attrs: quick_xml::events::attributes::Attributes,
191 is_empty: bool,
192 ) -> Self;
193
194 fn de_root() -> Option<&'static [u8]> {
195 None
196 }
197
198 /// A helper function used when ty = `untag`. It could help
199 /// us to find out the children tags when deserializing
200 fn __get_children_tags() -> Vec<&'static [u8]> {
201 vec![]
202 }
203
204 /// A helper function used when handling the untag types.
205 ///
206 /// For a outside struct, it doesn't
207 /// know how to deal with an untag type. The current solution is to treat them as `Unparsed`
208 /// types first, and then pass them into this function to deserialize. Since the type is untagged,
209 /// it doesn't require the attributes.
210 fn __deserialize_from_unparsed_array(_array: Vec<(&'static [u8], Unparsed)>) -> Self {
211 unreachable!("untagged types require having `child` types only")
212 }
213
214 /// A helper function for handling the untagged types.
215 ///
216 /// For efficiency, deserializing enums has no need to handle the untagged types by `__deserialize_from_unparsed_array` method.
217 /// But we have no idea of whether this field is not enum or not, we make a helper function to discern it
218 /// in the runtime.
219 fn __is_enum() -> bool {
220 false
221 }
222
223 fn __deserialize_from_text(_: &str) -> Option<Self>
224 where
225 Self: Sized,
226 {
227 None
228 }
229}
230
231/// `Unparsed` keeps the XML struct and will be serialized to XML with nothing change.
232/// It is helpful when you are debugging on deserializeing certain element.
233///
234/// ```ignore
235/// use xmlserde::Unparsed;
236/// use xmlserde_derive::{XmlSerialize, XmlDeserialize};
237///
238/// #[derive(XmlSerialize, Deserialize)]
239/// pub struct Person {
240/// #[xmlserde(name=b"gender", ty = "attr")]
241/// pub gender: Gender,
242/// #[xmlserde(name=b"hobbies", ty = "child")]
243/// pub hobbies: Unparsed
244/// }
245/// ```
246/// In the example above, `<hobbies>` element keeps unchange after serializing and deserializing.
247/// You can easily make a diff the former and latter version to check if other elments work well.
248#[derive(Debug, Clone)]
249pub struct Unparsed {
250 data: Vec<Event<'static>>,
251 attrs: Vec<(String, String)>,
252}
253
254impl XmlSerialize for Unparsed {
255 fn serialize<W: Write>(&self, _tag_: &[u8], _writer_: &mut quick_xml::Writer<W>) {
256 use quick_xml::events::*;
257 let mut start = BytesStart::new(String::from_utf8_lossy(_tag_));
258 self.attrs.iter().for_each(|(k, v)| {
259 let k = k as &str;
260 let v = v as &str;
261 start.push_attribute((k, v));
262 });
263 if self.data.len() > 0 {
264 let _ = _writer_.write_event(Event::Start(start));
265 self.data.iter().for_each(|e| {
266 let _ = _writer_.write_event(e.clone());
267 });
268 let _ = _writer_.write_event(Event::End(BytesEnd::new(String::from_utf8_lossy(_tag_))));
269 } else {
270 let _ = _writer_.write_event(Event::Empty(start));
271 }
272 }
273}
274
275impl XmlDeserialize for Unparsed {
276 fn deserialize<B: BufRead>(
277 _tag_: &[u8],
278 _reader_: &mut quick_xml::Reader<B>,
279 _attrs_: quick_xml::events::attributes::Attributes,
280 _is_empty_: bool,
281 ) -> Self {
282 use quick_xml::events::*;
283 let mut attrs_vec = Vec::<(String, String)>::new();
284 let mut data = Vec::<Event<'static>>::new();
285 let mut buf = Vec::<u8>::new();
286 _attrs_.into_iter().for_each(|a| {
287 if let Ok(attr) = a {
288 let key =
289 String::from_utf8(attr.key.into_inner().to_vec()).unwrap_or(String::from(""));
290 let value = String::from_utf8(attr.value.to_vec()).unwrap_or(String::from(""));
291 attrs_vec.push((key, value))
292 }
293 });
294 if _is_empty_ {
295 return Unparsed {
296 data,
297 attrs: attrs_vec,
298 };
299 }
300 loop {
301 match _reader_.read_event_into(&mut buf) {
302 Ok(Event::End(e)) if e.name().into_inner() == _tag_ => break,
303 Ok(Event::Eof) => break,
304 Err(_) => break,
305 Ok(e) => data.push(e.into_owned()),
306 }
307 }
308 Unparsed {
309 data,
310 attrs: attrs_vec,
311 }
312 }
313
314 fn __deserialize_from_unparsed_array(_array: Vec<(&'static [u8], Unparsed)>) -> Self {
315 unreachable!(
316 r#"seems you are using a struct having `attrs` or `text` as an UntaggedStruct"#
317 )
318 }
319}
320
321impl Unparsed {
322 pub fn deserialize_to<T>(self) -> Result<T, String>
323 where
324 T: XmlDeserialize + Sized,
325 {
326 // TODO: Find a more efficient way
327 let mut writer = quick_xml::Writer::new(Vec::new());
328 let t = b"tmptag";
329 self.serialize(t, &mut writer);
330 let result = writer.into_inner();
331
332 xml_deserialize_from_reader_with_root::<T, _>(result.as_slice(), t)
333 }
334}
335
336/// The entry for serializing. `T` should have declared the `root` by `#[xmlserde(root=b"")]`
337/// to tell the serializer the tag name of the root. This function will add the header needed for
338/// a XML file.
339pub fn xml_serialize_with_decl<T>(obj: T) -> String
340where
341 T: XmlSerialize,
342{
343 use quick_xml::events::BytesDecl;
344 let mut writer = quick_xml::Writer::new(Vec::new());
345 let decl = BytesDecl::new("1.0", Some("UTF-8"), Some("yes"));
346 let _ = writer.write_event(Event::Decl(decl));
347 obj.serialize(
348 T::ser_root().expect(r#"Expect a root element to serialize: #[xmlserde(root=b"tag")]"#),
349 &mut writer,
350 );
351 String::from_utf8(writer.into_inner()).unwrap()
352}
353
354/// The entry for serializing. `T` should have declared the `root` by `#[xmlserde(root=b"")]`
355/// to tell the serializer the tag name of the root.
356pub fn xml_serialize<T>(obj: T) -> String
357where
358 T: XmlSerialize,
359{
360 let mut writer = quick_xml::Writer::new(Vec::new());
361 obj.serialize(T::ser_root().expect("Expect root"), &mut writer);
362 String::from_utf8(writer.into_inner()).expect("decode error")
363}
364
365/// The entry for deserializing. `T` should have declared the `root` by `#[xmlserde(root=b"")]`
366/// to tell the deserializer which tag is the start for deserializing.
367/// ```ignore
368/// use xmlserde_derives::XmlDeserialize;
369/// #[derive(XmlDeserialize)]
370/// #[xmlserde(root=b"person")]
371/// pub struct Person {
372/// #[xmlserde(name = b"age", ty = "attr")]
373/// pub age: u16,
374/// #[xmlserde(name = b"pet", ty = "child")]
375/// pub pets: Vec<Pet>,
376/// }
377/// ```
378pub fn xml_deserialize_from_reader<T, R>(reader: R) -> Result<T, String>
379where
380 T: XmlDeserialize,
381 R: BufRead,
382{
383 let root = T::de_root().expect(r#"#[xmlserde(root = b"tag")]"#);
384 xml_deserialize_from_reader_with_root(reader, root)
385}
386
387pub(crate) fn xml_deserialize_from_reader_with_root<T, R>(
388 reader: R,
389 root: &[u8],
390) -> Result<T, String>
391where
392 T: XmlDeserialize,
393 R: BufRead,
394{
395 let mut reader = quick_xml::Reader::from_reader(reader);
396 let mut buf = Vec::<u8>::new();
397 loop {
398 match reader.read_event_into(&mut buf) {
399 Ok(Event::Start(start)) => {
400 if start.name().into_inner() == root {
401 let result = T::deserialize(root, &mut reader, start.attributes(), false);
402 return Ok(result);
403 }
404 }
405 Ok(Event::Empty(start)) => {
406 if start.name().into_inner() == root {
407 let result = T::deserialize(root, &mut reader, start.attributes(), true);
408 return Ok(result);
409 }
410 }
411 Ok(Event::Eof) => {
412 return Err(format!(
413 "Cannot find the element: {}",
414 String::from_utf8(root.to_vec()).unwrap()
415 ))
416 }
417 Err(e) => return Err(e.to_string()),
418 _ => {}
419 }
420 }
421}
422
423/// The entry for deserializing. `T` should have declared the `root` by `#[xmlserde(root=b"")]`
424/// to tell the deserializer which tag is the start for deserializing.
425/// ```ignore
426/// use xmlserde_derives::XmlDeserialize;
427/// #[derive(XmlDeserialize)]
428/// #[xmlserde(root=b"person")]
429/// pub struct Person {
430/// #[xmlserde(name = b"age", ty = "attr")]
431/// pub age: u16,
432/// #[xmlserde(name = b"pet", ty = "child")]
433/// pub pets: Vec<Pet>,
434/// }
435/// ```
436pub fn xml_deserialize_from_str<T>(xml_str: &str) -> Result<T, String>
437where
438 T: XmlDeserialize,
439{
440 xml_deserialize_from_reader(xml_str.as_bytes())
441}
442
443pub trait XmlValue: Sized {
444 fn serialize(&self) -> String;
445 fn deserialize(s: &str) -> Result<Self, String>;
446}
447
448impl XmlValue for bool {
449 fn serialize(&self) -> String {
450 if *self {
451 String::from("1")
452 } else {
453 String::from("0")
454 }
455 }
456
457 fn deserialize(s: &str) -> Result<Self, String> {
458 let s = s.to_ascii_lowercase();
459 if s == "1" || s == "true" {
460 Ok(true)
461 } else if s == "0" || s == "false" {
462 Ok(false)
463 } else {
464 Err(format!("Cannot parse {} into a boolean", s))
465 }
466 }
467}
468
469impl XmlValue for String {
470 fn serialize(&self) -> String {
471 self.to_owned()
472 }
473
474 fn deserialize(s: &str) -> Result<Self, String> {
475 Ok(s.to_owned())
476 }
477}
478
479macro_rules! impl_xml_value_for_num {
480 ($num:ty) => {
481 impl XmlValue for $num {
482 fn serialize(&self) -> String {
483 self.to_string()
484 }
485
486 fn deserialize(s: &str) -> Result<Self, String> {
487 let r = s.parse::<$num>();
488 match r {
489 Ok(f) => Ok(f),
490 Err(e) => Err(e.to_string()),
491 }
492 }
493 }
494 };
495}
496
497impl_xml_value_for_num!(i8);
498impl_xml_value_for_num!(u8);
499impl_xml_value_for_num!(i16);
500impl_xml_value_for_num!(u16);
501impl_xml_value_for_num!(i32);
502impl_xml_value_for_num!(u32);
503impl_xml_value_for_num!(i64);
504impl_xml_value_for_num!(u64);
505impl_xml_value_for_num!(i128);
506impl_xml_value_for_num!(u128);
507impl_xml_value_for_num!(isize);
508impl_xml_value_for_num!(usize);
509impl_xml_value_for_num!(f32);
510impl_xml_value_for_num!(f64);
511impl_xml_value_for_num!(std::num::NonZeroI8);
512impl_xml_value_for_num!(std::num::NonZeroU8);
513impl_xml_value_for_num!(std::num::NonZeroI16);
514impl_xml_value_for_num!(std::num::NonZeroU16);
515impl_xml_value_for_num!(std::num::NonZeroI32);
516impl_xml_value_for_num!(std::num::NonZeroU32);
517impl_xml_value_for_num!(std::num::NonZeroI64);
518impl_xml_value_for_num!(std::num::NonZeroU64);
519impl_xml_value_for_num!(std::num::NonZeroI128);
520impl_xml_value_for_num!(std::num::NonZeroU128);
521impl_xml_value_for_num!(std::num::NonZeroIsize);
522impl_xml_value_for_num!(std::num::NonZeroUsize);