XML to Rust
Paste XML and instantly get quicktype-style Rust struct definitions with inferred types and serde attributes.
Example
Input XML:
<book id="1" available="true">
<title>Programming Rust</title>
<pages>735</pages>
<price>49.99</price>
<author>Jim Blandy</author>
<author>Jason Orendorff</author>
</book>
Generated Rust:
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
#[serde(rename = "@id")]
pub id: i32,
#[serde(rename = "@available")]
pub available: bool,
pub title: String,
pub pages: i32,
pub price: f64,
pub author: Vec<String>,
}How it works
The tool parses your XML with the browser's DOMParser, walks the element tree to build a type model (merging repeated tags into Vec and scalars into i64/f64/bool/String), and emits Rust structs named from each element with serde rename attributes. Everything runs locally with no network calls.
Good to know
XML to Rust takes a raw XML document and turns it into ready-to-use Rust struct definitions, complete with #[derive(Debug, Clone, Serialize, Deserialize)] and the serde attributes you need to deserialize that exact XML. It is aimed at Rust developers who have to consume XML feeds, SOAP responses, config files, or legacy data exports and would rather not hand-write the boilerplate that quick-xml or serde-xml-rs expect.
Reach for it whenever you have a representative XML sample and want a typed model in seconds: scaffolding a parser for a third-party API, modeling an RSS or sitemap file, or migrating an XML config into a strongly typed Rust app. Because everything runs in your browser, you can safely paste internal or sensitive payloads without them leaving your machine.
To read the output, look at how each field is typed. The generator infers scalars as i32, i64, f64, bool, or String from the actual values; a child tag that appears more than once under the same parent becomes Vec<T>; a tag present in some records but missing in others becomes Option<T>; and XML attributes appear as fields renamed with the @name convention. Nested elements produce their own named structs, and the top-level element maps to a struct called Root.
One practical caveat: inference is only as good as the sample you give it. A single record can make a genuinely optional field look mandatory, or a repeated element look singular, so feed it a sample that includes the variations you expect in real data. Also double-check numeric guesses — an ID that happens to look like a number will be typed as an integer even if you'd prefer to keep it a String, and very large or zero-padded values may need manual adjustment after generation.
Frequently asked questions
How are XML attributes represented in the Rust output?
Each attribute becomes a struct field with a #[serde(rename = "@name")] attribute, matching the convention used by serde-xml-rs and quick-xml so the generated structs deserialize directly from your XML.
How does it decide between a single field and a Vec?
When the same child tag appears more than once under a parent, that field is emitted as Vec. Tags present in some occurrences but missing in others become Optionso partial documents still deserialize.
Is my data uploaded anywhere?
No — this tool runs entirely in your browser. Your input never leaves your device and it works offline once loaded.
Is it free?
Yes, completely free with no sign-up and no limits.
People also ask
What Rust XML libraries does the generated code work with?
The output uses serde's standard rename conventions (including the @-prefixed attribute naming), which match serde-xml-rs and quick-xml. With one of those crates plus serde added to your project, the structs deserialize directly from the XML.
How are XML text nodes handled when an element also has attributes?
For a simple element with no children or attributes, the text content is typed as a scalar field. When the root document is just a scalar value, the tool emits a Root struct with a value field renamed to "$text".
Does it generate separate structs for nested XML elements?
Yes. Each non-trivial element becomes its own named Rust struct, with the name derived from the tag, and parent structs reference the child struct as a field. The top-level element is always named Root.
How does the tool choose between i32 and i64 for numbers?
It inspects the actual integer value: numbers that fit within the 32-bit signed range are typed as i32, and anything larger becomes i64. If integer and decimal values are seen for the same field, it widens the type to f64.
Can it handle XML where the same field is sometimes missing?
Yes. When it merges multiple occurrences of an element and a child tag is present in some but absent in others, that field is emitted as Option<T> so partial or inconsistent documents still deserialize.
What happens if I paste invalid or malformed XML?
The tool parses with the browser's DOMParser and reports a parse error message instead of output. It also shows an error if there is no root element, so you can fix the markup before converting.
Does it sanitize XML tag names that aren't valid Rust identifiers?
Yes. Tag and attribute names are converted to snake_case field names, non-alphanumeric characters are replaced, names starting with a digit are prefixed, and Rust reserved keywords get a trailing underscore. The original name is preserved via a serde rename attribute when it differs.
Is XML to Rust free to use and does it require an account?
Yes, it is completely free with no sign-up, and no usage limits. It runs entirely client-side and works offline once the page has loaded.
Related tools