SQL to XML Converter

Feed a legacy integration from a dump file. Rows become elements, the root and row tags are yours to name, and a column called 2024 does not produce a document no parser will open.

To convert SQL to XML, paste your INSERT statements above. Each row becomes a row element inside a root element, both of which you can name, and each column becomes a child element or an attribute. Column names that are not legal XML element names are rewritten and the original spelling is kept in a name attribute, so nothing about your data is lost.

Need to rename columns before you export? Open the app

XML is where data goes when the other end is old

Nobody chooses XML for a new project. You need it because a bank, a government portal, a logistics provider or an internal system written in 2006 will accept nothing else, and the specification you were sent is a PDF with an element diagram in it.

Which means the bar is different from every other target on this site. Pretty does not matter. What matters is that the document parses on the first attempt, because the feedback loop on the other end is a rejection email the next morning.

So the output is deliberately boring: a declaration, one root, one element per row, escaped text, no namespaces you did not ask for and no processing instructions.

Worked example

Two rows out of a dump:

INSERT INTO orders (order_id, region_code, customer, revenue, note) VALUES
  (4101, '01', 'Ada Lovelace', 1840.50, NULL),
  (4102, '02', 'O''Hara Supplies', 275.00, 'PO 8841');

With the root named orders and the row element named order:

<?xml version="1.0" encoding="UTF-8"?>
<orders>
  <order>
    <order_id>4101</order_id>
    <region_code>01</region_code>
    <customer>Ada Lovelace</customer>
    <revenue>1840.50</revenue>
    <note/>
  </order>
  <order>
    <order_id>4102</order_id>
    <region_code>02</region_code>
    <customer>O&#39;Hara Supplies</customer>
    <revenue>275.00</revenue>
    <note>PO 8841</note>
  </order>
</orders>

The NULL note became <note/>, an empty element rather than a missing one. That is the distinction most schemas want: the field exists and has no value, which is different from the field not being in the document at all.

Column names XML will not accept

XML element names cannot start with a digit, cannot contain a space, and cannot begin with the letters x, m, l in that order, which the specification reserves. Databases have none of those restrictions, so a column called 2024 or Order Total is completely ordinary and completely illegal as an element name.

Writing <2024> produces a file that no parser will open, and the error the recipient sees says nothing useful about where it came from. So names are corrected: illegal characters become underscores, and a name that cannot start where it starts gains a leading underscore. Order Total becomes Order_Total and 2024 becomes _2024.

The original spelling is not thrown away. Each rewritten element carries name="Order Total", so the document is both parseable and lossless, and a note under the result tells you how many columns were affected. Most converters either emit the broken document or silently drop the column.

Elements or attributes

The default puts each value in a child element, which is readable, handles arbitrary length and lets a value contain markup-significant characters without ceremony.

The attribute mode writes <row order_id="4101" customer="Ada Lovelace"/> instead, one self-closing element per row. It is far more compact, and it is what a lot of older schemas were written against, particularly the ones that treat elements as structure and attributes as data.

One thing to know before switching: an attribute value cannot contain a raw line break in any meaningful way. If your data has multi-line notes, the element mode is the right choice and the attribute mode will make them hard to read.

What it does not do

  • No schema. No DTD, no XSD, no namespace declarations. If the recipient needs those, they are specific to their specification and belong in a wrapper you control.
  • No nesting from column names. A column called customer.name becomes an element spelled customer.name, not a customer element with a name inside it. Building structure out of punctuation is guesswork and it mangles every column whose name legitimately has a dot in it.
  • No CDATA. Values are escaped rather than wrapped, which is equivalent for a parser and easier to read in a diff.
  • One table per document. A dump with several tables gives you a picker, not a document with everything in it, because the shape of that document would be an invention.

Frequently Asked Questions

What happens to a column name XML does not allow?

It is rewritten to something legal and the original spelling is kept in a name attribute on every element, so nothing is lost. A column called 2024 becomes _2024 and Order Total becomes Order_Total. A note under the result says how many columns were affected.

Can I choose the root and row element names?

Yes, both. The defaults are rows and row. Whatever you type is checked against the XML naming rules and corrected if it has to be, rather than being written out to fail at the other end.

How is a NULL represented?

As an empty element, so note with a NULL in it becomes a self-closing note element. That keeps the field present with no value, which is what most schemas mean by null, rather than omitting the element and changing the document's shape row by row.

Can I get attributes instead of child elements?

Yes, one switch. Attribute mode writes one self-closing element per row with every value as an attribute. It is much more compact and it suits older schemas, but an attribute cannot carry a line break usefully, so multi-line values want the element mode.

Does it emit a schema or a DTD?

No. A schema is specific to the specification you were sent, and a generated one would almost certainly not match it. The document is well formed and the elements are named the way you asked, which is the part a converter can get right.

Does a dotted column name become nested elements?

No. A column named customer.name produces an element spelled customer.name. Inferring structure from punctuation is a guess, and it breaks every column whose name genuinely contains a dot, which is common after a flattening step upstream.

Make the document that parses first time

Well formed, legal element names, nothing invented. Name the root and download it.

Back to the converter