CSV to XML 변환이란?
CSV to XML 변환은 쉼표로 구분된 값을 XML(Extensible Markup Language) 문서로 변환하는 작업입니다. CSV의 각 행은 XML 요소가 되고, 각 열 헤더는 자식 요소 태그 이름으로 매핑됩니다. 결과물은 계층적이고 자기 설명적인 문서로, 시스템이 스키마(XSD 또는 DTD)에 대해 검증하고 XSLT, XPath, SAX/DOM 파서 같은 표준 XML 도구로 처리할 수 있습니다.
XML은 W3C가 1998년 XML 1.0 명세를 발표한 이후 데이터 교환 표준으로 사용되어 왔습니다. 많은 웹 API에서 JSON이 XML을 대체했지만, XML은 SOAP 웹 서비스, RSS/Atom 피드, SVG 그래픽, Office Open XML 문서(.docx, .xlsx), Android 리소스 파일, Maven/Gradle 빌드 설정, 그리고 의료(HL7 CDA), 금융(FpML, XBRL), 정부(NIEM) 같은 규제 산업에서 여전히 필수 형식입니다. 원본 데이터가 스프레드시트나 데이터베이스 내보내기인 경우, CSV to XML 변환을 통해 이러한 시스템에 데이터를 공급할 수 있습니다.
올바른 CSV to XML 변환기는 RFC 4180 엣지 케이스를 처리해야 합니다. 쉼표나 줄바꿈이 포함된 따옴표 필드, 이스케이프된 큰따옴표, 다양한 구분자가 여기에 해당합니다. XML 측면에서는 다섯 가지 미리 정의된 XML 엔티티(& < > " ')를 이스케이프하고, 헤더에서 유효한 요소 이름을 생성하며(공백과 특수 문자 교체), 적절한 XML 선언과 일관된 인코딩으로 올바른 형식의 출력을 생성해야 합니다.
CSV to XML 변환기를 사용하는 이유
스프레드시트 데이터에서 XML을 직접 작성하는 것은 느리고 오류가 발생하기 쉽습니다. 닫는 태그를 빠뜨리거나 앰퍼샌드 이스케이프를 잊으면 유효하지 않은 XML이 생성되어 하위 파서가 중단됩니다. 이 변환기는 파싱, 이스케이프, 요소 생성을 한 번에 처리합니다.
CSV to XML 활용 사례
CSV to 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 vs XML
CSV는 기본 스키마나 데이터 타입이 없는 평면적인 구분자 기반 형식입니다. XML은 스키마, 네임스페이스, 복잡한 중첩을 지원하는 계층적이고 자기 설명적인 마크업 언어입니다. 어느 형식을 선택할지는 하위 시스템 요구 사항에 따라 결정됩니다.
코드 예제
다양한 언어에서 CSV to 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