9 releases
new 0.5.5 | Sep 26, 2023 |
---|---|
0.5.4 | Aug 30, 2023 |
0.5.2 | Jun 21, 2023 |
0.5.1 | May 21, 2023 |
0.3.0 | Jun 2, 2022 |
#1500 in Parser implementations
159 downloads per month
Used in 5 crates
(via logisheets_workbook)
22KB
246 lines
xmlserde
xmlserde
is a tool for serializing or deserializing xml struct.
It is designed for LogiSheets, which is a spreadsheets application working on the browser.
You can check the detail of usage in the workbook
directory or here.
How to use xmlserde
xmlserde
provides macros for you and in the most of cases, they are enough. You should import these crates in yout Cargo.toml
:
xmlserde = 0.5.0
xmlserde_derives = 0.5.0
Deserialize
Start from deserializing would be easier to get closer to xmlserde
.
Given the xml struct as below,
<person age ="16">Tom</person>
We can deserialize with these code:
use xmlserde_derives: XmlDerserialize
#[derive(XmlDeserialize)]
#[xmlserde(root = b"person")]
pub struct Person {
#[xmlserde(name=b"age", ty="attr")]
pub age: u8,
#[xmlserde(ty ="text")]
pub name: String,
}
fn deserialize_person() {
use xmlserde::xml_deserialize_from_str;
let s = r#"<person age ="16">Tom</person>"#;
let p = xml_deserialize_from_str(s).unwrap();
assert_eq!(p.age, 16);
assert_eq!(p.name, "Tom");
}
You are supposed to declare that where the deserializer is to look for the values.
The common available types are attr, text and child. In the above example, we told program that diving into the tag named "person" (xml_deserialize_from_str), and looking for an attribute whose key is*"age"* and that the content of the text element is the value of the field name.
You should tell the program that which element name is the entry for serde by
doing something like #[xmlserde(root = b"person")]
.
Let's see an example of deserializing nested xml element.
#[derive(XmlDeserialize)]
#[xmlserde(root = b"person")]
pub struct Person {
#[xmlserde(name=b"age", ty="attr")]
pub age: u8,
#[xmlserde(name = b"lefty", ty ="attr", default = "default_lefty")]
pub lefty: bool,
#[xmlserde(name = b"name", ty ="child")]
pub name: Name,
}
#[derive(XmlDeserialize)]
pub struct Name {
#[xmlserde(name = b"zh", ty ="attr")]
pub zh: String,
#[xmlserde(name = b"en", ty ="attr")]
pub en: String,
}
fn deserialize_person() {
use xmlserde::xml_deserialize_from_str;
let s = r#"<person age ="16"><name zh="汤姆", en="Tom"/></person>"#;
let p = xml_deserialize_from_str(s).unwrap();
assert_eq!(p.age, 16);
assert_eq!(p.name.en, "Tom");
assert_eq!(p.lefty, false);
}
fn default_lefty() -> bool { false }
In the example above, it is declared that the value of name is from a child whose tag is "name".
So the program will dive into <name>
element and continue deserializing recursively.
Besides, we declare that if deserializer does not find the value of lefty and its default value of lefty is false.
Vec
We support deserialize the fields whose types are std::Vec<T: XmlDeserialize>
.
#[derive(XmlDeserialize)]
pub struct Pet {
// Fields
}
#[derive(XmlDeserialize)]
#[xmlserde(root = b"person")]
pub struct Person {
#[xmlserde(name = b"petCount", ty = "attr")]
pub pet_count: u8,
#[xmlserde(name = b"pet", ty = "child")]
pub pets: Vec<Pet>
}
When the deserializer find the pet element, and it will know that this is an element of pets. You can even assign the capacity of the Vec
with following:
#[xmlserde(name = b"pet", ty="child", vec_size=3)]
If the capacity is from an attr, you can:
#[xmlserde(name = b"pet", ty="child", vec_size="pet_count")]
Enum
We provide 2 patterns for deserializing Enum
.
#[derive(XmlSerialize, XmlDeserialize)]
enum TestEnum {
#[xmlserde(name = b"testA")]
TestA(TestA),
#[xmlserde(name = b"testB")]
TestB(TestB),
}
#[derive(XmlSerialize, XmlDeserialize)]
#[xmlserde(root = b"personA")]
pub struct PersonA {
#[xmlserde(name = b"e", ty = "child")]
pub e: TestEnum
// Other fields
}
#[derive(XmlSerialize, XmlDeserialize)]
#[xmlserde(root = b"personB")]
pub struct PersonB {
#[xmlserde(ty = "untag")]
pub dummy: TestEnum
// Other fields
}
PersonA can be used to deserialize the xml struct like below:
<personA><e><testA/></e></personA>
or
<personA><e><testB/></e></personA>
And PersonB can be used to deserialize the xml which looks like:
<personB><testA/></personB>
or
<personB><testB/></personB>
You can use untag to Option<T> or Vec<T> where T is an Enum.
It means that the example below is legal:
#[derive(XmlSerialize, XmlDeserialize)]
#[xmlserde(root = b"personB")]
pub struct PersonB {
#[xmlserde(ty = "untag")]
pub dummy1: Enum1,
#[xmlserde(ty = "untag")]
pub dummy2: Option<Enum2>,
#[xmlserde(ty = "untag")]
pub dummy3: Vec<Enum3>,
// Other fields
}
Unparsed
Sometimes we don't care about some xml element and we just want to keep them for future serializing.
We provide a struct Unparsed
to do this.
use xmlserde::Unparsed;
#[derive(XmlDeserialize)]
pub struct Person {
#[xmlserde(name = b"educationHistory", ty = "child")]
pub education_history: Unparsed,
}
Serialize
Serializing is almost the same as deserializing. But there are some features you should pay attention to.
-
default values will be skipped serializing. If it is a struct, it should be implemented
Eq
trait. -
If a struct has no child or text, the result of serializing will look like this:
<tag attr1="value1"/>
Custom xmlserde
xmlserde
provides the trait XmlSerialize
and XmlDeserialize
, you
can define a struct's behavior by implementing them.
Enum for string type
xmlserde
also provides a macro called xml_serde_enum
to serde enum
for string type.
xml_serde_enum
defines an enum
and specifies the behavior of serialization and deserialization.
use xmlserde::xml_serde_enum;
xml_serde_enum!{
#[derive(Debug)]
Gender {
Male => "male",
Female => "female",
}
}
Dependencies
~4.5–6.5MB
~119K SLoC