What is CSV to XML Conversion?
CSV to XML conversion transforms comma-separated values into Extensible Markup Language (XML) documents. Each row of the CSV becomes an XML element, and each column header maps to a child element tag name. The result is a hierarchical, self-describing document that systems can validate against a schema (XSD or DTD) and process with standard XML tooling such as XSLT, XPath, and SAX/DOM parsers.
XML has been a data interchange standard since the W3C published the XML 1.0 specification in 1998. While JSON has replaced XML in many web APIs, XML remains the required format for SOAP web services, RSS/Atom feeds, SVG graphics, Office Open XML documents (.docx, .xlsx), Android resource files, Maven/Gradle build configs, and regulated industries like healthcare (HL7 CDA), finance (FpML, XBRL), and government (NIEM). When your source data is a spreadsheet or database export, CSV-to-XML conversion is how you get it into these systems.
A correct CSV to XML converter must handle RFC 4180 edge cases: quoted fields containing commas or newlines, escaped double quotes, and varying delimiters. On the XML side, it must escape the five predefined XML entities (& < > " '), generate valid element names from headers (replacing spaces and special characters), and produce well-formed output with a proper XML declaration and consistent encoding.
Why Use a CSV to XML Converter?
Writing XML by hand from spreadsheet data is slow and error-prone. Missing a closing tag or forgetting to escape an ampersand produces invalid XML that breaks downstream parsers. This converter handles parsing, escaping, and element generation in a single step.
CSV to XML Use Cases
CSV to XML Mapping Reference
Understanding how each part of a CSV file maps to XML structure helps you predict the output format and adjust your data before conversion.
| CSV Concept | XML Equivalent | Details |
|---|---|---|
| CSV file | XML document | The entire file maps to a root element containing all records |
| Header row | Element tag names | Each column header becomes the tag name for child elements |
| Data row | <row> element | Each row becomes a repeating child element of the root |
| Cell value | Text node | Cell content becomes the text inside the corresponding tag |
| Empty cell | Empty element or omitted | Can be rendered as <field/> or excluded from output |
| Comma delimiter | XML structure | Delimiters are replaced by element nesting and closing tags |
CSV vs XML
CSV is a flat, delimiter-based format with no built-in schema or data types. XML is a hierarchical, self-describing markup language that supports schemas, namespaces, and complex nesting. Choosing between them depends on your downstream system requirements.
Code Examples
Below are working examples of CSV to XML conversion in different languages. Each example parses the CSV header row as element tag names, wraps each data row in a container element, and escapes XML entities in cell content.
// CSV string → XML with proper escaping
const csv = `name,age,city
Alice,30,Berlin
Bob,25,Tokyo`
function csvToXml(csv, rootTag = 'data', rowTag = 'row') {
const rows = csv.trim().split('\n').map(r => r.split(','))
const [headers, ...data] = rows
const xmlRows = data.map(row => {
const fields = headers.map((h, i) => {
const val = (row[i] || '').replace(/&/g, '&')
.replace(/</g, '<').replace(/>/g, '>')
return ` <${h}>${val}</${h}>`
}).join('\n')
return ` <${rowTag}>\n${fields}\n </${rowTag}>`
}).join('\n')
return `<?xml version="1.0" encoding="UTF-8"?>\n<${rootTag}>\n${xmlRows}\n</${rootTag}>`
}
console.log(csvToXml(csv))
// → <?xml version="1.0" encoding="UTF-8"?>
// → <data><row><name>Alice</name><age>30</age>...</row>...</data>import csv, io
from xml.etree.ElementTree import Element, SubElement, tostring
from xml.dom.minidom import parseString
csv_string = """name,age,city
Alice,30,Berlin
Bob,25,Tokyo"""
reader = csv.DictReader(io.StringIO(csv_string))
root = Element('data')
for row in reader:
row_el = SubElement(root, 'row')
for key, value in row.items():
child = SubElement(row_el, key)
child.text = value
# Pretty-print with declaration
raw = tostring(root, encoding='unicode')
pretty = parseString(raw).toprettyxml(indent=' ')
print(pretty)
# → <?xml version="1.0" ?>
# → <data>
# → <row>
# → <name>Alice</name>
# → <age>30</age>
# → <city>Berlin</city>
# → </row>
# → ...
# → </data>package main
import (
"encoding/csv"
"encoding/xml"
"fmt"
"os"
"strings"
)
type Field struct {
XMLName xml.Name
Value string `xml:",chardata"`
}
type Row struct {
XMLName xml.Name `xml:"row"`
Fields []Field
}
type Data struct {
XMLName xml.Name `xml:"data"`
Rows []Row
}
func main() {
input := "name,age,city\nAlice,30,Berlin\nBob,25,Tokyo"
r := csv.NewReader(strings.NewReader(input))
records, _ := r.ReadAll()
headers := records[0]
var data Data
for _, rec := range records[1:] {
row := Row{}
for i, h := range headers {
row.Fields = append(row.Fields, Field{
XMLName: xml.Name{Local: h},
Value: rec[i],
})
}
data.Rows = append(data.Rows, row)
}
out, _ := xml.MarshalIndent(data, "", " ")
fmt.Println(xml.Header + string(out))
// → <?xml version="1.0" encoding="UTF-8"?>
// → <data><row><name>Alice</name>...</row>...</data>
}# Using Python's csv and xml modules via one-liner
python3 -c "
import csv, sys
from xml.etree.ElementTree import Element, SubElement, tostring
from xml.dom.minidom import parseString
reader = csv.DictReader(sys.stdin)
root = Element('data')
for row in reader:
r = SubElement(root, 'row')
for k, v in row.items():
SubElement(r, k).text = v
print(parseString(tostring(root, encoding='unicode')).toprettyxml(indent=' '))
" < data.csv
# Using Miller (mlr) — a dedicated CSV/JSON/XML tool
mlr --icsv --oxml cat data.csv