Rust to XML Converter
Paste Rust structs or a struct literal. Get clean XML back.
What this tool does
If you have ever had to hand-craft XML that mirrors a Rust struct — for a SOAP client in an integration service, a system config file, or a test fixture — you know how much copying and pasting that involves. Paste the Rust here and you get back well-formed XML in one pass. A single struct, a file with several structs and enums, or a populated let order = Order { ... }; literal — same result: a complete XML document with every field preserved.
It is not dumb string-replacement. The converter knows how Rust actually serialises through serde — roughly the way serde-xml-rs or quick-xml would emit it. f64 and f32 come out as plain numeric text, String values are XML-escaped, Option<T> with a None value becomes an empty element (or is skipped when #[serde(skip_serializing_if = "Option::is_none")] is set), and Vec<T> follows a consistent container shape — each Vec becomes a wrapper element with one child per item, named after the element type.
Serde attributes are honoured. #[serde(rename = "x")] on a field renames the element in the output, #[serde(rename = "x")] on the struct renames the wrapping root, #[serde(skip)] drops the field, and #[serde(flatten)] pulls a nested struct up a level. Enums are emitted with the standard serde tagging rules — externally tagged by default, adjacently or internally tagged if you set #[serde(tag = "...")]. If you want the deep version, The Rust Book is a solid jumping-off point for the ownership and type-system pieces underneath.
How to use it
Three steps. Works the same whether you paste a five-line struct or a full module.
Paste your Rust (or try the sample)
Drop your Rust into the left editor as-is. A struct, an enum, a populated struct literal, or a file with multiple types — all fine. Click Load Sample if you want to see a realistic example first.
You do not need to strip use statements, remove derive macros, or clean up lifetime annotations. Leave the code the way rustfmt left it. Just paste.
Hit Convert
Click the green Convert button. The tool reads the Rust, preserves every struct and field, and builds the XML in one pass. You will see a short loading indicator while it runs.
Copy the XML
The right panel fills with indented, well-formed XML that a standards-compliant XML parser will accept. Copy it straight into your SOAP request, config file, or test fixture.
When this actually comes in handy
Systems-level SOAP integration
Rust services often sit next to legacy systems that still speak SOAP. Paste your request struct, grab the XML body, test it in SoapUI before wiring the HTTP client — faster than writing the envelope by hand. Pair with a crate from <a href="https://crates.io/" target="_blank" rel="noopener">crates.io</a> like <code>reqwest</code> for the transport.
Config files for services and daemons
A settings struct with 30+ fields becomes a ready-to-edit XML template. No handwritten boilerplate, no missed fields when the struct grows.
Seeding test fixtures
Turn a populated <code>let order = Order { ... };</code> from a unit test into an XML seed file for integration tests, mock servers, or legacy systems you do not own.
Keeping docs in sync
Generate XML examples for a README, crate docs, or XSD-backed schema documentation directly from your actual structs, so docs match the code instead of drifting.
Common questions
Can I paste multiple structs at once?
Yes — paste a whole module. Each top-level struct or enum comes through with nested types expanded and default values filled in. Nothing is dropped silently.
Does it honour #[serde(rename)] and #[serde(skip)]?
Yes. #[serde(rename = "x")] on a field renames the XML element, #[serde(rename = "x")] on the struct renames the wrapping root, #[serde(skip)] drops the field entirely, and #[serde(flatten)] pulls a nested struct up a level. #[serde(rename_all = "PascalCase")] is applied to every field in the struct. That matches what serde actually does at runtime.
How does it handle Option<T> and skip_serializing_if?
A None value becomes an empty element by default — so the shape stays consistent and XSDs keep validating. If the field has #[serde(skip_serializing_if = "Option::is_none")], None values are dropped entirely. Some(x) is always serialised as x itself.
What about enums, Vec, and HashMap?
Enums default to externally-tagged (<VariantName>...</VariantName>); add #[serde(tag = "type")] to switch to internally-tagged. Vec<T> becomes a container element with one child per item, named after the element type — a Vec<OrderItem> items turns into <items><OrderItem/><OrderItem/></items>. HashMap<K,V> becomes a container of <Entry><Key/><Value/></Entry>.
Is my code stored?
Your code is sent to the backend for conversion and is not persisted — we do not log the payload. As always with online tools, if the code is genuinely sensitive, look it over before pasting.
What if the Rust has lifetimes, traits, or unsafe blocks?
Lifetime annotations are stripped for XML purposes — they do not affect the runtime value. Trait definitions describe shape, not content, so they do not produce XML directly; implementing structs do. Unsafe blocks are ignored because they are execution-time constructs. If the code has syntax errors, fix the obvious ones first — the parser is forgiving but not psychic.
Other tools you may need
Rust to XML is one piece of the puzzle. These tools pair well with it: