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:

  1. Create a Plant instance
  2. Serialize it to XML with indentation
  3. Add an XML header
  4. Deserialize XML back into a Plant instance
  5. 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.