CSVからXMLへの変換とは?
CSVからXMLへの変換は、カンマ区切りの値を拡張マークアップ言語(XML)ドキュメントに変換する処理です。CSVの各行がXML要素になり、各カラムヘッダーが子要素のタグ名に対応します。結果は階層的な自己記述ドキュメントであり、スキーマ(XSDまたはDTD)に対して検証でき、XSLT、XPath、SAX/DOMパーサーといった標準的なXMLツールで処理できます。
XMLは、W3CがXML 1.0仕様を1998年に公開して以来、データ交換の標準形式として使われてきました。多くのWeb APIではJSONがXMLに取って代わっていますが、XMLはSOAP Webサービス、RSS/Atomフィード、SVGグラフィクス、Office Open XMLドキュメント(.docx、.xlsx)、Androidリソースファイル、Maven/Gradleビルド設定、そして医療(HL7 CDA)・金融(FpML、XBRL)・行政(NIEM)などの規制分野で依然として必須の形式です。スプレッドシートやデータベースのエクスポートがデータのソースである場合、CSVからXMLへの変換はそのデータをこれらのシステムに取り込む手段となります。
正確なCSVからXMLへのコンバーターは、RFC 4180のエッジケース——カンマや改行を含むクォートフィールド、エスケープされたダブルクォート、さまざまな区切り文字——を処理しなければなりません。XML側では、5つの定義済みXMLエンティティ(&、<、>、"、')をエスケープし、ヘッダーから有効な要素名を生成し(スペースや特殊文字を置換)、適切なXML宣言と一貫したエンコーディングを持つ整形式の出力を生成する必要があります。
CSVからXMLへの変換ツールを使う理由
スプレッドシートのデータからXMLを手書きするのは時間がかかり、エラーが発生しやすいです。閉じタグを忘れたり、アンパサンドのエスケープを失念すると、無効なXMLが生成されてダウンストリームのパーサーが壊れます。このコンバーターは、解析・エスケープ・要素生成を一度の処理で行います。
CSVからXML変換のユースケース
CSVからXMLへのマッピングリファレンス
CSVファイルの各部分がXML構造にどのように対応するかを理解することで、出力形式を予測し、変換前にデータを調整できます。
| CSVの概念 | XMLでの対応 | 詳細 |
|---|---|---|
| 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 と XML の比較
CSVは組み込みのスキーマやデータ型を持たない、フラットな区切り文字ベースの形式です。XMLはスキーマ・名前空間・複雑なネストをサポートする、階層的な自己記述マークアップ言語です。どちらを選ぶかは、ダウンストリームシステムの要件によって決まります。
コード例
以下は、異なる言語でCSVをXMLに変換する実際のコード例です。各例は、CSVヘッダー行を要素タグ名として解析し、各データ行をコンテナ要素でラップし、セル内容のXMLエンティティをエスケープします。
// 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