Excel to XML Converter

Send a spreadsheet to a system that only speaks XML. Rows become elements, you name the tags, and a header with a space in it does not produce a file the recipient cannot open.

To convert Excel to XML, drop your .xlsx above. Each row of the chosen sheet becomes a row element inside a root element, both of which you name, and each column becomes a child element or an attribute. Headers that are not legal XML element names are corrected, with the original spelling kept in a name attribute so nothing is lost.

Need to rename headers before you export? Open the app

Spreadsheet in, message out

This conversion has one dominant use and it is unglamorous: an organisation maintains something in Excel because that is where the people are, and an external system consumes XML because that is where the specification is. Customs declarations, insurance bordereaux, payroll submissions, product feeds, regulatory returns.

The feedback loop is slow and unforgiving. You submit, and the next morning you get a rejection that says the document was not well formed, with a byte offset. So the only quality that matters here is that the file parses on the first attempt.

Which is why the output is deliberately plain: a declaration, one root, one element per row, escaped text, nothing invented.

Worked example

Two rows of a product sheet, with the headers a spreadsheet actually has:

Product ID   Product Name          Unit Price   2024 Target   In Stock
SKU-101      Wireless Mouse        23.07        4000          161
SKU-108      27in Monitor          140.33       2200          0

With the root named products and the row element named product:

<?xml version="1.0" encoding="UTF-8"?>
<products>
  <product>
    <Product_ID name="Product ID">SKU-101</Product_ID>
    <Product_Name name="Product Name">Wireless Mouse</Product_Name>
    <Unit_Price name="Unit Price">23.07</Unit_Price>
    <_2024_Target name="2024 Target">4000</_2024_Target>
    <In_Stock name="In Stock">161</In_Stock>
  </product>
</products>

Every header in that sheet was illegal as an element name, four of them for containing a space and one for starting with a digit. All five are corrected and all five keep their original spelling in a name attribute, so the document parses and a human reading it can still see what the column was called.

Why spreadsheet headers and XML names disagree so completely

A spreadsheet header is a label for a person. It has spaces, capital letters, units in brackets, sometimes a percentage sign, occasionally a line break. All of that is fine in a cell and none of it is fine in an element name.

XML's rules are narrow: no spaces, no leading digit, no leading hyphen or dot, and nothing beginning with the letters x, m, l in that order. So essentially every real spreadsheet needs its headers rewritten, which is why most converters either produce broken documents or make you rename the columns first.

The rewriting here is mechanical and predictable: illegal characters become underscores, and a name that cannot start where it starts gains a leading one. It is deterministic, so the same sheet always produces the same element names, which matters when the recipient has written a stylesheet against them.

Values, blanks and merged cells

  • Blank cells become empty elements, not missing ones. A document whose shape changes row by row is the first thing a validator objects to.
  • Numbers come through as their underlying value. A cell displaying 1,840.50 writes 1840.5, because the comma and the trailing zero were the number format rather than the number.
  • Dates come through as ISO strings, which is the one date format every XML consumer agrees on.
  • Formulas come through as computed values, which is what the sheet shows.
  • Merged cells put their value in the top-left position and leave the rest blank, which is what the file itself records. Merged headers are the usual cause of a column called column_4.

Elements or attributes, and what neither of them does

Child elements are the default. Attribute mode writes <row Product_ID="SKU-101"/>, one self-closing element per row, which is smaller and matches a lot of older schemas. It cannot carry a line break in a value, so a notes column with wrapped text wants the element mode.

Neither mode emits a schema, a namespace or a processing instruction. Those belong to the specification you were sent, and generating one here would produce something that looks official and does not match. What this guarantees is a well-formed document with the element names you chose.

Frequently Asked Questions

My headers have spaces and one starts with a digit. Will the XML parse?

Yes. Spaces become underscores and a name starting with a digit gains a leading underscore, so Product Name becomes Product_Name and 2024 Target becomes _2024_Target. Each element carries the original spelling in a name attribute, and a note says how many were rewritten.

Can I set the root and row element names?

Both, in the options. The defaults are rows and row. Whatever you type is checked against XML's naming rules and corrected if it needs to be, rather than written out to fail at the recipient's end.

Why does a cell showing 1,840.50 come out as 1840.5?

Because Excel stores the number and paints the format. The comma and the trailing zero are display, not data. Format the column as text in Excel first if the exact display string is the thing you need to send.

What happens to blank cells?

They become empty self-closing elements, so the document has the same shape on every row. Omitting the element instead makes the structure vary row by row, which is exactly what a schema validator rejects.

Does it generate a DTD or an XSD?

No. A schema belongs to the specification you were given, and an invented one would look authoritative while disagreeing with it. The guarantee here is a well-formed document with the element names you asked for.

Which sheet does it use?

The first with data, converted immediately, with every sheet name listed underneath so you can switch. If the first sheet is empty the next one with data is used and a note tells you that happened.

Make the submission that parses first time

Well formed, legal element names, originals kept. Name the root and download.

Back to the converter