XML에서 JSON으로의 변환은 현대 소프트웨어 개발에서 가장 일반적인 데이터 변환 작업 중 하나입니다. 구성 파일, RSS 피드 또는 SOAP API 응답을 처리하든, 효율적인 XML-JSON 변환기는 수작업 시간을 절약합니다. 이 포괄적인 가이드는 파싱 메커니즘부터 JavaScript, Python, Java, Bash의 코드 예제까지 모든 것을 다룹니다.
무료 온라인 XML-JSON 변환 도구를 사용해 보세요.
XML에서 JSON 변환이란?
XML과 JSON은 가장 널리 사용되는 두 가지 데이터 교환 형식입니다. XML은 수십 년간 엔터프라이즈 컴퓨팅을 지배했습니다. JSON은 웹 개발자가 선호하는 경량 대안으로 등장했습니다.
XML-JSON 변환기는 올바른 형식의 XML 문서를 받아 요소, 속성, 네임스페이스, CDATA 섹션을 처리하면서 동등한 JSON 표현으로 변환합니다.
역방향인 JSON에서 XML 변환은 기존 XML 시스템과 통합할 때 똑같이 중요합니다.
XML vs JSON: 상세 비교
변환 기술에 들어가기 전에 XML과 JSON의 구조적 차이를 이해하는 것이 중요합니다:
| 특성 | XML | JSON |
|---|---|---|
| 구문 | 태그 기반 마크업 | 키-값 쌍 |
| 속성 | 네이티브 지원 | 속성 개념 없음 |
| 네임스페이스 | 완전 지원 | 네이티브 지원 없음 |
| 크기 | 더 큼 | 30-50% 작음 |
XML에서 JSON 변환 작동 방식
변환 프로세스에는 여러 핵심 단계가 있습니다:
- XML 문서 파싱: DOM 트리 구축 또는 SAX 이벤트.
- 요소를 객체에 매핑: 각 요소가 JSON 속성이 됩니다.
- 속성 처리:
@등의 접두사 사용. - 텍스트 노드 처리: 문자열 값으로 직접 매핑.
- 반복 요소를 배열로 변환.
- 네임스페이스 처리.
여러 확립된 규칙이 XML에서 JSON으로의 매핑을 정의합니다:
- Badgerfish 규칙: 모든 XML 정보를 보존.
- Parker 규칙: 가장 컴팩트한 JSON.
- GData 규칙: Google이 사용하는 중간 접근법.
XML에서 JSON 코드 예제
JavaScript: XML에서 JSON
JavaScript에서 fast-xml-parser와 xml2js가 견고한 변환을 제공합니다:
// ===== Using fast-xml-parser (recommended) =====
// npm install fast-xml-parser
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1" category="fiction">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<price currency="USD">10.99</price>
<year>1925</year>
</book>
<book id="2" category="non-fiction">
<title lang="en">Sapiens</title>
<author>Yuval Noah Harari</author>
<price currency="USD">14.99</price>
<year>2011</year>
</book>
</bookstore>`;
// Configure parser with attribute handling
const parser = new XMLParser({
ignoreAttributes: false, // preserve attributes
attributeNamePrefix: '@_', // prefix for attributes
textNodeName: '#text', // key for text content
isArray: (name, jpath) => { // force arrays for known collections
return ['bookstore.book'].includes(jpath);
},
});
const json = parser.parse(xml);
console.log(JSON.stringify(json, null, 2));
// Output:
// {
// "bookstore": {
// "book": [
// {
// "@_id": "1",
// "@_category": "fiction",
// "title": { "@_lang": "en", "#text": "The Great Gatsby" },
// "author": "F. Scott Fitzgerald",
// "price": { "@_currency": "USD", "#text": 10.99 },
// "year": 1925
// },
// ...
// ]
// }
// }
// ===== Using DOMParser (browser built-in) =====
function xmlToJson(xmlString) {
const parser = new DOMParser();
const doc = parser.parseFromString(xmlString, 'text/xml');
function nodeToJson(node) {
const obj = {};
// Handle attributes
if (node.attributes && node.attributes.length > 0) {
for (let i = 0; i < node.attributes.length; i++) {
const attr = node.attributes[i];
obj['@' + attr.nodeName] = attr.nodeValue;
}
}
// Handle child nodes
if (node.childNodes && node.childNodes.length > 0) {
for (let i = 0; i < node.childNodes.length; i++) {
const child = node.childNodes[i];
if (child.nodeType === 1) { // Element node
const childObj = nodeToJson(child);
if (obj[child.nodeName]) {
// Convert to array if duplicate element names
if (!Array.isArray(obj[child.nodeName])) {
obj[child.nodeName] = [obj[child.nodeName]];
}
obj[child.nodeName].push(childObj);
} else {
obj[child.nodeName] = childObj;
}
} else if (child.nodeType === 3) { // Text node
const text = child.nodeValue.trim();
if (text) {
if (Object.keys(obj).length === 0) return text;
obj['#text'] = text;
}
} else if (child.nodeType === 4) { // CDATA section
obj['#cdata'] = child.nodeValue;
}
}
}
return obj;
}
const root = doc.documentElement;
const result = {};
result[root.nodeName] = nodeToJson(root);
return result;
}
// ===== Using xml2js (Node.js) =====
// npm install xml2js
import { parseString } from 'xml2js';
parseString(xml, {
explicitArray: false,
mergeAttrs: true,
trim: true,
}, (err, result) => {
if (err) throw err;
console.log(JSON.stringify(result, null, 2));
});
// ===== Streaming large XML with sax (Node.js) =====
// npm install sax
import sax from 'sax';
const saxParser = sax.createStream(true, { trim: true });
const stack = [];
let current = {};
saxParser.on('opentag', (node) => {
const obj = {};
if (node.attributes) {
for (const [key, value] of Object.entries(node.attributes)) {
obj['@' + key] = value;
}
}
stack.push(current);
current[node.name] = obj;
current = obj;
});
saxParser.on('text', (text) => {
if (text.trim()) current['#text'] = text.trim();
});
saxParser.on('closetag', () => {
current = stack.pop();
});Python: XML에서 JSON
Python에서 xmltodict가 가장 인기 있는 선택입니다:
# ===== Using xmltodict (most popular) =====
# pip install xmltodict
import xmltodict
import json
xml_string = """<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<product id="101" category="electronics">
<name>Wireless Mouse</name>
<price currency="USD">29.99</price>
<specs>
<weight unit="g">85</weight>
<battery>AA</battery>
<connectivity>Bluetooth 5.0</connectivity>
</specs>
<tags>
<tag>wireless</tag>
<tag>mouse</tag>
<tag>bluetooth</tag>
</tags>
</product>
</catalog>
"""
# Convert XML to Python dict (then to JSON)
data = xmltodict.parse(xml_string)
json_output = json.dumps(data, indent=2, ensure_ascii=False)
print(json_output)
# Output:
# {
# "catalog": {
# "product": {
# "@id": "101",
# "@category": "electronics",
# "name": "Wireless Mouse",
# "price": { "@currency": "USD", "#text": "29.99" },
# "specs": {
# "weight": { "@unit": "g", "#text": "85" },
# "battery": "AA",
# "connectivity": "Bluetooth 5.0"
# },
# "tags": { "tag": ["wireless", "mouse", "bluetooth"] }
# }
# }
# }
# Force specific elements to always be lists
data = xmltodict.parse(xml_string, force_list=('product', 'tag'))
# ===== Using defusedxml for security =====
# pip install defusedxml
import defusedxml.ElementTree as ET
# Safe parsing - blocks XXE, entity expansion, etc.
tree = ET.fromstring(xml_string)
def element_to_dict(element):
result = {}
# Handle attributes
if element.attrib:
for key, value in element.attrib.items():
result[f'@{key}'] = value
# Handle child elements
children = list(element)
if children:
for child in children:
child_data = element_to_dict(child)
if child.tag in result:
# Convert to list for repeated elements
if not isinstance(result[child.tag], list):
result[child.tag] = [result[child.tag]]
result[child.tag].append(child_data)
else:
result[child.tag] = child_data
elif element.text and element.text.strip():
if result: # Has attributes
result['#text'] = element.text.strip()
else:
return element.text.strip()
return result
root = tree
json_data = {root.tag: element_to_dict(root)}
print(json.dumps(json_data, indent=2))
# ===== Using lxml with XPath =====
# pip install lxml
from lxml import etree
tree = etree.fromstring(xml_string.encode())
# Extract specific data with XPath, output as JSON
products = []
for product in tree.xpath('//product'):
products.append({
'id': product.get('id'),
'name': product.xpath('name/text()')[0],
'price': float(product.xpath('price/text()')[0]),
'currency': product.xpath('price/@currency')[0],
})
print(json.dumps(products, indent=2))Bash / CLI: XML에서 JSON
xq(yq에서)와 xmlstarlet으로 명령줄 변환이 가능합니다:
# ===== Using xq (part of yq, recommended) =====
# Install: pip install yq OR brew install yq
# Basic XML to JSON conversion
cat data.xml | xq .
# Or directly from a file
xq . data.xml
# Pretty-print with specific fields
xq '.catalog.product[] | {name: .name, price: .price}' data.xml
# Convert and save to file
xq . input.xml > output.json
# Extract specific values
xq -r '.catalog.product.name' data.xml
# ===== Using xmlstarlet =====
# Install: brew install xmlstarlet OR apt install xmlstarlet
# Select specific elements
xmlstarlet sel -t -v "//product/name" data.xml
# Convert to a flat key-value format
xmlstarlet sel -t \
-m "//product" \
-v "@id" -o "," \
-v "name" -o "," \
-v "price" -n data.xml
# ===== Python one-liners =====
# Quick XML to JSON from command line
python3 -c "
import xmltodict, json, sys
print(json.dumps(xmltodict.parse(sys.stdin.read()), indent=2))
" < data.xml
# Using built-in xml.etree (no pip install needed)
python3 -c "
import xml.etree.ElementTree as ET, json, sys
root = ET.parse(sys.stdin).getroot()
def to_dict(el):
d = dict(el.attrib)
children = list(el)
if children:
for c in children:
cd = to_dict(c)
if c.tag in d:
if not isinstance(d[c.tag], list): d[c.tag] = [d[c.tag]]
d[c.tag].append(cd)
else: d[c.tag] = cd
elif el.text and el.text.strip():
if d: d['#text'] = el.text.strip()
else: return el.text.strip()
return d
print(json.dumps({root.tag: to_dict(root)}, indent=2))
" < data.xml
# ===== Using curl + xq for API responses =====
# Fetch XML API and convert to JSON
curl -s "https://api.example.com/data.xml" | xq .
# SOAP response to JSON
curl -s -X POST "https://api.example.com/soap" \
-H "Content-Type: text/xml" \
-d @request.xml | xq '.Envelope.Body'Java: XML에서 JSON
Java에서 Jackson XML과 org.json이 주요 도구입니다:
// ===== Using org.json (simple conversion) =====
// Maven: org.json:json:20231013
import org.json.JSONObject;
import org.json.XML;
public class XmlToJsonExample {
public static void main(String[] args) {
String xml = """
<bookstore>
<book id="1">
<title>Clean Code</title>
<author>Robert C. Martin</author>
<price>32.99</price>
</book>
</bookstore>
""";
// Simple one-line conversion
JSONObject json = XML.toJSONObject(xml);
System.out.println(json.toString(2));
// With configuration
JSONObject jsonKeepStrings = XML.toJSONObject(xml, true);
// true = keep all values as strings (no type coercion)
}
}
// ===== Using Jackson XML (more control) =====
// Maven: com.fasterxml.jackson.dataformat:jackson-dataformat-xml
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class JacksonXmlExample {
public static void main(String[] args) throws Exception {
String xml = "<book id=\"1\"><title>Clean Code</title></book>";
XmlMapper xmlMapper = new XmlMapper();
JsonNode node = xmlMapper.readTree(xml.getBytes());
ObjectMapper jsonMapper = new ObjectMapper();
String json = jsonMapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(node);
System.out.println(json);
}
}
// ===== Secure XML parsing in Java =====
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.XMLConstants;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// Prevent XXE attacks
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
dbf.setFeature(
"http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature(
"http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature(
"http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);JSON에서 XML 변환
역방향에는 고유한 과제가 있습니다:
주요 과제: JSON 배열에는 XML의 직접적인 등가물이 없습니다. null 값에는 표현이 필요합니다. 속성 이름이 XML에서 유효하지 않을 수 있습니다.
JavaScript와 Python에서의 JSON-XML 변환 예제:
// ===== JavaScript: JSON to XML =====
import { XMLBuilder } from 'fast-xml-parser';
const jsonData = {
catalog: {
product: [
{
'@_id': '101',
name: 'Wireless Mouse',
price: { '@_currency': 'USD', '#text': '29.99' },
tags: { tag: ['wireless', 'mouse'] },
},
{
'@_id': '102',
name: 'Keyboard',
price: { '@_currency': 'USD', '#text': '49.99' },
tags: { tag: ['keyboard', 'mechanical'] },
},
],
},
};
const builder = new XMLBuilder({
ignoreAttributes: false,
attributeNamePrefix: '@_',
textNodeName: '#text',
format: true, // pretty print
indentBy: ' ',
suppressEmptyNode: true,
});
const xml = builder.build(jsonData);
console.log(xml);
# ===== Python: JSON to XML =====
import xmltodict
json_data = {
'catalog': {
'product': {
'@id': '101',
'name': 'Wireless Mouse',
'price': {'@currency': 'USD', '#text': '29.99'},
}
}
}
xml_output = xmltodict.unparse(json_data, pretty=True)
print(xml_output)
# Output:
# <?xml version="1.0" encoding="utf-8"?>
# <catalog>
# <product id="101">
# <name>Wireless Mouse</name>
# <price currency="USD">29.99</price>
# </product>
# </catalog>엣지 케이스 처리
프로덕션 품질의 변환기는 수많은 엣지 케이스를 처리해야 합니다:
XML 속성: 접두사 규칙이 필요한 가장 일반적인 엣지 케이스.
CDATA 섹션: 파싱되지 않은 콘텐츠를 일반 텍스트로 처리.
네임스페이스: 매핑 복잡성 증가.
혼합 콘텐츠: 텍스트와 자식 요소를 포함하는 요소.
빈 요소: null, 빈 문자열 또는 빈 객체로 변환 가능.
배열 감지: JSON 배열 사용 시기 결정.
공백 처리: 유의미한 공백 구분.
XML 선언과 DTD: JSON에 매핑되지 않는 메타데이터.
// Edge case examples: XML to JSON
// 1. Attributes + text content
// XML: <price currency="USD">29.99</price>
// JSON: { "price": { "@currency": "USD", "#text": "29.99" } }
// 2. CDATA section
// XML: <script><![CDATA[if (a < b) { alert("hello"); }]]></script>
// JSON: { "script": "if (a < b) { alert(\"hello\"); }" }
// 3. Namespaces
// XML: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
// <soap:Body><GetPrice><Item>Apple</Item></GetPrice></soap:Body>
// </soap:Envelope>
// JSON: { "soap:Envelope": { "soap:Body": { "GetPrice": { "Item": "Apple" } } } }
// 4. Mixed content
// XML: <p>Hello <b>world</b> today</p>
// JSON: { "p": { "#text": ["Hello ", " today"], "b": "world" } }
// 5. Self-closing / empty elements
// XML: <br/> OR <item></item>
// JSON: { "br": null } OR { "item": "" }
// 6. Single vs multiple children (array detection)
// XML (one child): <items><item>A</item></items>
// JSON (no array): { "items": { "item": "A" } }
// XML (two children):<items><item>A</item><item>B</item></items>
// JSON (array): { "items": { "item": ["A", "B"] } }
// Solution: use isArray option in fast-xml-parser or force_list in xmltodict
// 7. Whitespace preservation
// XML: <code xml:space="preserve"> hello world </code>
// JSON: { "code": " hello world " }
// 8. XML declaration (dropped in JSON)
// XML: <?xml version="1.0" encoding="UTF-8"?>
// JSON: (not included in output)XML 보안 모범 사례
XML 파서를 다룰 때 보안은 가장 중요합니다:
XXE 공격: 외부 엔티티 처리를 비활성화하세요.
Billion Laughs 공격: 엔티티 확장을 제한하세요.
DTD 기반 인젝션: 외부 DTD 로딩을 비활성화.
보안 구성: 각 프로그래밍 언어에서 XML 파서의 명시적 보안 구성이 필요합니다.
// ===== Secure XML parsing examples =====
// --- Python: Use defusedxml ---
# UNSAFE: xml.etree.ElementTree (vulnerable to XXE)
import xml.etree.ElementTree as ET # DO NOT use with untrusted XML
# SAFE: defusedxml blocks all known XML attacks
import defusedxml.ElementTree as SafeET
tree = SafeET.fromstring(untrusted_xml) # Safe!
# defusedxml blocks:
# - XML External Entity (XXE) attacks
# - Billion Laughs (entity expansion) attacks
# - External DTD retrieval
# - Decompression bombs
# --- Java: Secure DocumentBuilderFactory ---
import javax.xml.parsers.DocumentBuilderFactory;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// Disable all dangerous features
dbf.setFeature(
"http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature(
"http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature(
"http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature(
"http://apache.org/xml/features/nonvalidating/load-external-dtd",
false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
// --- JavaScript (Node.js): fast-xml-parser ---
import { XMLParser } from 'fast-xml-parser';
const secureParser = new XMLParser({
// fast-xml-parser does NOT process entities by default (safe)
processEntities: false, // explicitly disable
htmlEntities: false, // don't process HTML entities
allowBooleanAttributes: false,
});
// --- .NET: Secure XmlReaderSettings ---
// XmlReaderSettings settings = new XmlReaderSettings();
// settings.DtdProcessing = DtdProcessing.Prohibit;
// settings.XmlResolver = null;
// === Example: XXE attack payload (for awareness) ===
// This malicious XML attempts to read /etc/passwd:
//
// <?xml version="1.0"?>
// <!DOCTYPE data [
// <!ENTITY xxe SYSTEM "file:///etc/passwd">
// ]>
// <data>&xxe;</data>
//
// A vulnerable parser would include file contents in output.
// A secure parser rejects the DOCTYPE declaration entirely.
// === Example: Billion Laughs payload ===
// This XML expands to ~3 GB of text from a few hundred bytes:
//
// <?xml version="1.0"?>
// <!DOCTYPE lolz [
// <!ENTITY lol "lol">
// <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
// <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
// ...
// ]>
// <data>&lol9;</data>자주 묻는 질문
XML을 JSON으로 변환하는 가장 좋은 방법은?
언어에 따라 다릅니다. JavaScript: fast-xml-parser. Python: xmltodict. CLI: xq. 빠른 변환에는 온라인 도구를 이용하세요.
XML 속성은 JSON 변환에서 어떻게 처리되나요?
속성은 @ 같은 접두사로 매핑됩니다. 속성과 텍스트가 공존할 때 텍스트는 #text 키에 저장됩니다.
XML에서 JSON 변환은 안전한가요?
적절한 설정 없이는 XML 파싱이 위험할 수 있습니다. 외부 엔티티를 비활성화하고 Python에서는 defusedxml을 사용하며 파서를 안전하게 설정하세요.
XML에서 JSON 변환은 현대 개발자에게 필수적인 기술입니다. 무료 온라인 도구로 빠르게 변환을 수행하세요.
무료 온라인 도구로 XML을 JSON으로 즉시 변환하세요. | XML Formatter | JSON Formatter