XML to Rust Converter Online — Generate Struct (serde-xml-rs)

Paste any XML and generate #[derive(Serialize, Deserialize)] Rust structs ready for serde-xml-rs and quick-xml. Attributes map to rename = "@name", text content to rename = "$text" — all in your browser.

What is an XML to Rust converter?

An XML to Rust converter takes a real XML document and emits Rust struct definitions decorated with #[derive(Serialize, Deserialize)] and serde rename tags ready for serde-xml-rs or quick-xml. The OpenFormatter generator inspects every element and attribute, infers Rust types, and produces a complete struct hierarchy with @-prefixed renames for attributes and $text for inner text — saving the tedious step of writing them by hand.

XML differs from JSON in two ways your Rust model has to honour. First, XML has attributes on elements (<book id="bk101">) — these need #[serde(rename = "@id")] so quick-xml reads them from the attribute table. Second, XML has namespaces; the basic generator strips them, but you can re-add them as a ns:localname rename. Both aspects are handled by the sample below.

Sample XML and the Rust struct it generates

Input XML

<book id="bk101" lang="en">
  <title>Programming Rust</title>
  <year>2021</year>
  <price currency="USD">54.99</price>
</book>

Generated Rust

#[derive(Debug, Serialize, Deserialize)]
pub struct Book {
    #[serde(rename = "@id")]
    pub id: String,
    #[serde(rename = "@lang")]
    pub lang: String,
    pub title: String,
    pub year: i64,
    pub price: Price,
}

Notice id and lang use rename = "@id", while title and year have no rename. The nested <price currency="USD">54.99</price> generates a Price struct with one @-prefixed field and one $text field for the text content — exactly what quick-xml expects.

How to convert XML to Rust — 4 steps

  1. Paste your XML. A SOAP envelope body, an RSS feed entry, an OPC document — anything well-formed.
  2. Click Convert. The browser parses the XML and generates serde-derive Rust structs for the full element tree.
  3. Review attribute mapping. Confirm @-prefixed renames appear on every field that should be an XML attribute; tweak field names if needed.
  4. Drop into your crate. Copy the output into a .rs file and decode real XML with quick_xml::de::from_str(&xml).

Serde Derive Ready

Generates #[derive(Debug, Serialize, Deserialize)] on every struct so quick-xml or serde-xml-rs can decode the document with a single from_str call.

Attribute vs Element

XML attributes get rename = "@name"; child elements get no rename or rename = "name". The distinction is preserved exactly so round-tripping is lossless.

Client-Side Only

Your XML — including SOAP responses with credentials — is parsed in JavaScript on your machine. Verify in DevTools: zero network requests on Convert.

Common use cases

  • check_circleGenerate Rust structs for a SOAP service response
  • check_circleBuild serde-derive models for an RSS or Atom feed reader
  • check_circleParse OPC / Office Open XML documents in a Rust pipeline
  • check_circleGenerate Rust types from an XSD-described XML file
  • check_circleCreate deserialization models for legacy enterprise XML
  • check_circleBuild typed structs for a SAML or WS-Security XML payload
  • check_circleGenerate Rust models for AWS XML responses (S3, SQS, SNS)
  • check_circleCreate structs for sitemaps.xml or robots.xml in a Rust crawler

Why client-side conversion matters

SOAP responses and enterprise XML often contain customer PII, API tokens, internal endpoint names, and database identifiers. Pasting them into a server-hosted converter is a compliance violation in most regulated industries. OpenFormatter parses the XML and generates Rust code entirely in JavaScript on your device — no upload, no logs, no cookies. Open DevTools → Network and confirm no requests fire when you click Convert.

More XML tooling

Validate, format, or convert XML to other languages — every tool runs locally in your browser.

Frequently Asked Questions

Is the output compatible with serde-xml-rs or quick-xml?

Both. The generator emits #[derive(Debug, Serialize, Deserialize)] structs with serde rename tags using the quick-xml convention: "@name" for attributes and "$text" for inner text. quick-xml with the serialize feature reads these directly. serde-xml-rs uses a slightly different attribute syntax (no @ prefix); switch the rename strings to migrate.

How are XML attributes mapped to Rust struct fields?

XML attributes (e.g. <book id="bk101">) become pub fields annotated with #[serde(rename = "@id")]. The leading @ is the quick-xml convention that tells the deserializer to read from the attribute table on the parent element instead of looking for a child element of the same name.

How are repeated elements like <tag> in <tags> represented?

Repeated child elements become Vec<TagType> fields on the parent struct. quick-xml with serde collects each occurrence into the vector. For wrapped lists (<tags><tag/><tag/></tags>) you may also wrap with #[serde(rename = "tag")] inside an inner struct, depending on shape.

What about XML namespaces?

quick-xml accepts namespace-qualified names in its rename string: #[serde(rename = "ns:localname")]. The basic generator strips the namespace prefix; for namespace-aware deserialization rewrite the tag with the prefix or use quick-xml low-level reader to handle namespaces explicitly.

Can elements with both attributes and text content be modeled?

Yes. <price currency="USD">54.99</price> generates a Price struct with two fields — currency annotated with #[serde(rename = "@currency")] and a text field annotated with #[serde(rename = "$text")]. quick-xml decodes the text body into the $text field while reading the attribute separately.

Does the output use Option<T> for nullable fields?

Fields whose source value is null become Option<String>. For other types you can change to Option<T> manually if the element is optional in your schema. Without Option, missing elements cause a deserialization error — a feature, not a bug, when you want strict parsing.

Is the XML I paste sent to your servers?

No. XML is parsed by the browser DOMParser and the Rust code is generated entirely in JavaScript on your machine. Open DevTools → Network and you will see no requests when you click Convert. Safe for SOAP responses and configuration files containing API keys or credentials.

How do I deserialize XML into the generated struct?

With quick-xml: use quick_xml::de::from_str; let book: Book = from_str(&xml_string)?; — the renamed fields are populated automatically. Add quick-xml = { version = "0.31", features = ["serialize"] } and serde = { version = "1", features = ["derive"] } to Cargo.toml.

XML to Rust Converter — Generate Struct (serde-xml-rs)