
Why convert TOML to XML at all
The consumers that demand it are build and enterprise systems: a value maintained in a modern TOML config has to appear in a pom.xml fragment, a .csproj property group, a Tomcat or logging config, or a B2B interface that validates XML against a schema from 2009. The generation direction, modern format in, legacy format out, is the common one; teams keep their source of truth editable and generate what the old system reads.
The other use is quick: some tool or endpoint wants "the same data as XML" once, for an import or a test, and writing a serializer for that is out of proportion. The data model transfers without loss, TOML's tables, arrays and scalars all have direct XML spellings, so this direction never fails on valid input.
How to use this converter
- Paste or drop your TOML. Full TOML 1.0 parses: dotted keys, inline tables, arrays of tables, all date/time types. Errors show inline with the offending line.
- Check the structure on the right, especially the root element (see below) and any keys that were sanitized into legal tag names.
- Copy or download the
.xml.
--pretty
Two-space indentation. Off gives the single-line form for payloads and embedding.
--declaration
Prepends <?xml version="1.0" encoding="UTF-8"?>. The declaration is optional for parsers but expected by many older consumers, so it defaults to on.
How TOML constructs map to XML
| TOML | XML |
|---|---|
title = "Release feed" | <title>Release feed</title> |
[channel] table | <channel> element with children |
[[channel.item]] sections | repeated <item> siblings inside <channel> |
ports = [8001, 8002] | <ports>8001</ports><ports>8002</ports> |
"@_id" = "A-1042" | id="A-1042" attribute on the parent |
updated = 2024-05-14T09:00:00Z | <updated>2024-05-14T09:00:00.000Z</updated> |
stable = true | <stable>true</stable> |
Special characters in values are escaped on the way (& to &, < to <), so a description containing markup arrives as text, not as accidental structure. Comments do not survive; they live in the TOML text, and XML comments would be a guess about placement.

Root element and key names
XML requires exactly one root element, and a TOML file has no such thing, its top level is a table with any number of keys. When your file has a single top-level table, that table's name becomes the root. When it has several top-level keys, like a title next to a [channel], the converter wraps everything in a <root> element, because inventing a smarter name would be wrong more often than right. If the consumer needs a specific root, add one enclosing table in the TOML or rename the element after converting.
Key names become tag names, and XML's naming rules are stricter than TOML's: a quoted TOML key like "ssl port" or "2023" is legal, the equivalent tag is not. Such keys are sanitized, illegal characters to underscores, a leading underscore before digits: <ssl_port>, <_2023>. The mapping is visible immediately in the output; when exact names matter downstream, rename the keys in the source rather than relying on sanitization.
Dates and typed values become text
TOML values are typed, XML content is text, so every value is serialized to its text form: integers and floats as written, booleans as true/false, strings as their content. Nothing marks the former type in the output, which is normal for XML, schemas, not syntax, carry type information there.
Dates get one deliberate treatment: all four TOML date/time types are written as ISO 8601 text, so 2024-05-14T09:00:00Z arrives as a machine-readable timestamp rather than a locale-formatted string. ISO 8601 is what XML Schema's own date types (xs:date, xs:dateTime) expect, so the values validate unchanged against schemas that type them. A date-only TOML value stays date-only text; no midnight is invented.
Pitfalls to check after converting
- The
<root>wrapper. Multiple top-level keys force it. If the consumer expects<config>, put everything under one[config]table in the source. - Sanitized names. Quoted TOML keys with spaces or leading digits change spelling on the way. Grep the output for
_where you did not expect one. - One-element arrays. They serialize identically to a scalar, so array-ness of a single item is not visible in XML. Consumers must infer lists from repetition, as they always do with XML.
- Vocabulary, not syntax. The output is well-formed generic XML with your key names. Systems like Maven or SOAP endpoints validate names, order and namespaces on top; align the TOML key names with the target schema or transform after.
- Comments gone. As in every data-level conversion. If the XML will be hand-maintained from now on, move the explanatory comments over manually, XML comments (
<!-- -->) hold them fine.
If the destination is human eyes rather than an XML consumer, the readable tree view of TOML to YAML or the plain data view of TOML to JSON is usually the better target.
TOML to XML questions
How do I convert TOML to XML in Python?
Parse with the standard library, serialize with ElementTree: data = tomllib.load(open("config.toml", "rb")) on Python 3.11+, then walk the dict building SubElements, with lists emitting one element per item under the same name. There is no ready-made toml-to-xml package worth adding; the walk is a dozen lines, and the two decisions you must make (root element name, and str() for non-string values) are the same ones any converter makes. dicttoxml also works after tomllib if you accept its type-annotation attributes.
Is XML still used for configuration files?
Heavily, in specific ecosystems: Maven's pom.xml, .NET's .csproj and web.config, Android manifests and layouts, Tomcat's server.xml, logback and log4j2 configs. Those formats are not going anywhere, their toolchains are built on XML's validation and transformation stack. New tools almost never pick XML for config anymore, which is exactly why conversions like this one exist: values maintained in a modern TOML file sometimes have to feed a build system or server that only reads XML.
Can a TOML key become an XML attribute instead of an element?
Only by convention, because TOML has no attribute concept. The convention this tool understands is the @_ prefix: a key written "@_id" = "A-1042" in the TOML becomes an id attribute on the parent element instead of a child element. That is the same convention our XML parsers emit, so a file that came from XML round-trips with its attributes intact. For TOML written by hand, child elements are the default and attributes are opt-in via the prefix.
How do TOML arrays convert to XML elements?
Repetition: XML has no array syntax, a list is just the same element appearing multiple times. An array of tables ([[server]] sections) becomes sibling <server> elements, one per section, and a plain array like ports = [8001, 8002] becomes <ports>8001</ports><ports>8002</ports>. The consequence worth knowing: a one-element array and a plain scalar produce identical XML, so the array-ness of a single-item list is not recoverable from the output. Consumers that parse XML back into data infer lists from repetition, same as everywhere in XML.
What is the correct file extension and MIME type for XML?
.xml as the extension, and application/xml as the media type per RFC 7303, which folded the older text/xml into it as an alias; application/xml is the one to emit today. Specialized XML vocabularies use their own +xml suffixed types (image/svg+xml, application/rss+xml) so software can dispatch on the concrete format while still recognizing the XML envelope. For a generated config or data file, name it .xml and serve it as application/xml and every consumer is satisfied.
Why does my XML import reject the file my converter produced?
Almost always a vocabulary mismatch, not broken XML: the importer expects specific element names, nesting and sometimes a namespace, and generic conversion produces names taken from your TOML keys. Maven will not read a structurally perfect file whose root is not project in the right namespace. Compare one record of the generated file against one record of a known-good file for that system, then rename keys in the TOML source (or transform with a small XSLT) until the names match. Well-formedness gets you parsed; the schema gets you accepted.