Xml in Rust
Here’s the translation of the XML example from Go to Rust:
use serde::{Serialize, Deserialize};
use quick_xml::se::to_string_with_config;
use quick_xml::de::from_str;
use quick_xml::se::Config;
// Plant will be mapped to XML. Field attributes contain directives for the
// serializer and deserializer. Here we use some special features
// of the quick-xml crate: the `rename` attribute dictates
// the name of the XML element representing this struct;
// `attribute` means that the `id` field is an XML
// *attribute* rather than a nested element.
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename = "plant")]
struct Plant {
#[serde(rename = "@id")]
id: i32,
name: String,
origin: Vec<String>,
}
impl std::fmt::Display for Plant {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Plant id={}, name={}, origin={:?}",
self.id, self.name, self.origin)
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut coffee = Plant {
id: 27,
name: "Coffee".to_string(),
origin: vec!["Ethiopia".to_string(), "Brazil".to_string()],
};
// Emit XML representing our plant; using
// to_string_with_config to produce a more
// human-readable output.
let config = Config::new().indent(' ', 2);
let out = to_string_with_config(&coffee, config)?;
println!("{}", out);
// To add a generic XML header to the output, prepend
// it explicitly.
println!("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n{}", out);
// Use from_str to parse a string of XML
// into a data structure. If the XML is malformed or
// cannot be mapped onto Plant, a descriptive error
// will be returned.
let p: Plant = from_str(&out)?;
println!("{}", p);
let tomato = Plant {
id: 81,
name: "Tomato".to_string(),
origin: vec!["Mexico".to_string(), "California".to_string()],
};
// The `rename` attribute on Nesting tells the serializer
// to nest all `plant`s under `<parent><child>...</child></parent>`
#[derive(Serialize)]
#[serde(rename = "nesting")]
struct Nesting {
#[serde(rename = "parent")]
parent: Parent,
}
#[derive(Serialize)]
struct Parent {
#[serde(rename = "child")]
child: Child,
}
#[derive(Serialize)]
struct Child {
plant: Vec<Plant>,
}
let nesting = Nesting {
parent: Parent {
child: Child {
plant: vec![coffee, tomato],
},
},
};
let out = to_string_with_config(&nesting, config)?;
println!("{}", out);
Ok(())
}
This Rust code demonstrates XML serialization and deserialization using the quick-xml
and serde
crates. The Plant
struct is defined with attributes that control how it’s represented in XML. The main
function shows how to:
- Create a
Plant
instance - Serialize it to XML with indentation
- Add an XML header
- Deserialize XML back into a
Plant
instance - Create a nested structure and serialize it to XML
To run this program, you’ll need to add the following dependencies to your Cargo.toml
:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
quick-xml = { version = "0.22", features = ["serialize"] }
When you run this program, it will output the XML representations of the Plant
and Nesting
structs, demonstrating both simple and complex XML structures.
Note that Rust’s approach to XML handling is a bit different from Go’s. Instead of using struct tags, Rust uses derive macros and attributes from the serde
crate to control serialization and deserialization. The quick-xml
crate provides the XML-specific functionality.