FormatterHQ

XML to Rust Struct Generator

Generate Rust structs with serde derives from an XML sample. Attributes and child elements become fields, repeated elements become Vec.

Input XML
Output RUST
Ready.

How to use the XML to Rust

  1. Paste your XML document into the Input editor, or use Sample, Upload file or Load URL, or press Sample to see an example.
  2. Leave Top-level class name empty to name the root type after the root element, or type your own name.
  3. The Types only option does not change Rust output; structs always derive Serialize and Deserialize.
  4. Press Generate (it also updates as you edit), then use Copy or Download.

XML to Rust: serde structs from a sample

In Rust, the usual way to read XML into typed data is serde together with an XML backend such as quick-xml (with its serialize feature) or serde-xml-rs. Both need structs that match the document. This XML to Rust generator writes those structs from a sample, with Serialize/Deserialize derives, snake_case fields and Rust types inferred from the element and attribute text.

Example

<crate name="serde" downloads="512000000">
  <version num="1.0.210" yanked="false"/>
  <version num="1.0.209" yanked="true"/>
  <license>MIT OR Apache-2.0</license>
</crate>
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Crate {
    pub version: Vec<Version>,
    pub license: String,
    pub name: String,
    pub downloads: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Version {
    pub num: String,
    pub yanked: bool,
}

The version string 1.0.210 stays a String (it is not a valid number), yanked became bool, and the repeated <version> elements became Vec<Version>.

Marking attributes for quick-xml

The generator does not know which fields were attributes. With quick-xml's serde support, attribute fields are renamed with an @ prefix and element text uses the special name $text:

#[derive(Debug, Deserialize)]
pub struct Crate {
    #[serde(rename = "@name")]
    pub name: String,
    #[serde(rename = "@downloads")]
    pub downloads: i64,
    pub license: String,
    #[serde(rename = "version", default)]
    pub version: Vec<Version>,
}

let krate: Crate = quick_xml::de::from_str(&xml)?;

#[serde(default)] on the Vec lets documents without any <version> element still parse. For an element with attributes and text, add a field with #[serde(rename = "$text")]; the generator calls that field value.

How the sample is mapped

The root element name becomes the top-level struct (Crate), unless you enter your own. Attributes and child elements become fields of the same struct, element text beside attributes becomes a value field, and namespace prefixes are removed. Text is typed by content: 512000000 is an i64, false a bool, and anything else a String. Elements missing from some records become Option<T>, which quick-xml fills with None when they are absent.

Notes

  • Rename conventions differ between XML crates; serde-xml-rs, for example, does not use the @ prefix. Check the documentation of the crate you choose.
  • Numeric text with leading zeros loses them when typed as a number; use String.
  • Namespace prefixes are removed from field names.

For JSON data use JSON to Rust, and validate the XML with the XML Validator. Generation runs in your browser.

Writing XML back out

Because the structs derive Serialize as well, the same types can produce XML. With quick-xml, quick_xml::se::to_string(&krate)? writes the document, using the struct name as the root element. Two details usually need attention:

  • The root name. The struct is called Crate, but the document uses <crate>. Add #[serde(rename = "crate")] to the struct so the output matches the input.
  • Attributes versus elements. Fields without the @ rename are written as child elements, so name would become <name>serde</name>. Apply the renames from the section above before serializing if the receiver expects attributes.

Round-tripping a sample document, parse then serialize, is a quick test that the struct annotations are complete.

Frequently asked questions

Which crate should I use to parse XML with these structs?
quick-xml with the serialize feature is a common choice; serde-xml-rs is another. Both use serde derives like the generated structs, but have different conventions for attributes.
How do I mark a field as an XML attribute with quick-xml?
Rename it with an @ prefix, for example #[serde(rename = "@name")]. Element text uses #[serde(rename = "$text")].
Why is the version field a String?
A value like 1.0.210 is not a valid number, so it is typed as a string. Values that look like numbers are typed as i64 or f64.
Does Types only change the Rust output?
No. Rust output always consists of serde-derived structs.

Last updated September 26, 2026

Related tools

JSON to Rust Generate Rust structs with Serde derives from a JSON sample instantly, with nested types detected automatically. XML to Scala Generate Scala case classes from a XML sample instantly, with nested types detected automatically. XML to Swift Generate Swift Codable structs from a XML sample instantly, with nested types detected automatically. XML to TypeScript Generate TypeScript interfaces from a XML sample instantly, with nested types detected automatically. GraphQL to TypeScript Generate TypeScript interfaces, enums and union types from a GraphQL schema (SDL), with nullability and argument types. JSON Schema to TypeScript Turn JSON Schema into TypeScript interfaces and types with optional properties, enums, $ref definitions and JSDoc comments. JSON to C++ Generate C++ classes with nlohmann::json helpers from a JSON sample instantly, with nested types detected automatically. JSON to Crystal Generate Crystal classes with JSON mapping from a JSON sample instantly, with nested types detected automatically. JSON to C# Generate C# classes with JsonProperty attributes from a JSON sample instantly, with nested types detected automatically. JSON to Dart Generate Dart classes with fromJson and toJson from a JSON sample instantly, with nested types detected automatically. JSON to Elm Generate Elm type aliases with decoders from a JSON sample instantly, with nested types detected automatically. JSON to Flow Generate Flow Flow type definitions from a JSON sample instantly, with nested types detected automatically.