手写XML转JSON:从结构解析到数据转换全指南
在数据交互和API开发中,XML和JSON是两种常见的数据格式,虽然JSON因其轻量和易读性更受青睐,但许多系统仍使用XML作为数据交换格式,本文将详细介绍如何手写代码将XML转换为JSON,帮助开发者理解两种格式之间的转换逻辑。
理解XML和JSON的基本结构
在开始转换之前,我们需要明确两种格式的核心差异:
- XML:使用标签嵌套表示层级关系,如
<root><child>value</child></root>
- JSON:使用键值对和数组表示数据结构,如
{"root": {"child": "value"}}
转换的关键在于:
- 将XML标签名转换为JSON的键名
- 将XML属性转换为JSON对象的属性
- 处理XML的文本内容和嵌套结构
- 处理命名空间等复杂情况
手写转换的核心步骤
解析XML文档
首先需要解析XML字符串,可以使用DOM或SAX方式,这里以DOM为例:
function parseXML(xmlString) { const parser = new DOMParser(); return parser.parseFromString(xmlString, "text/xml"); }
递归转换节点
XML的层级结构需要递归处理:
function xmlNodeToJson(node) { let result = {}; // 处理节点属性 if (node.attributes && node.attributes.length > 0) { result = {}; for (let i = 0; i < node.attributes.length; i++) { const attr = node.attributes[i]; result[`@${attr.name}`] = attr.value; } } // 处理子节点 if (node.childNodes && node.childNodes.length > 0) { for (let i = 0; i < node.childNodes.length; i++) { const child = node.childNodes[i]; if (child.nodeType === Node.TEXT_NODE) { // 处理文本节点 const text = child.textContent.trim(); if (text) { if (Object.keys(result).length === 0) { return text; } result['#text'] = text; } } else if (child.nodeType === Node.ELEMENT_NODE) { // 处理元素节点 const childJson = xmlNodeToJson(child); if (result[child.nodeName]) { // 处理同名节点数组 if (!Array.isArray(result[child.nodeName])) { result[child.nodeName] = [result[child.nodeName]]; } result[child.nodeName].push(childJson); } else { result[child.nodeName] = childJson; } } } } return result; }
处理特殊情况
需要考虑以下特殊情况:
- 空节点:
<empty/>
应转换为{"empty": ""}
或{"empty": null}
- :
<p>text<b>bold</b>more</p>
应保留文本和标签结构 - 命名空间:处理带命名空间的XML节点
function handleEmptyNode(node) { if (node.childNodes.length === 0 && !node.attributes.length) { return null; } return xmlNodeToJson(node); }
完整转换函数示例
function xmlToJson(xmlString) { const xmlDoc = parseXML(xmlString); const rootNode = xmlDoc.documentElement; return xmlNodeToJson(rootNode); }
测试用例
const xmlString = ` <root> <person id="1"> <name>John Doe</name> <age>30</age> <hobbies> <hobby>Reading</hobby> <hobby>Swimming</hobby> </hobbies> <address> <city>New York</city> <zip>10001</zip> </address> </person> <person id="2"> <name>Jane Smith</name> <age>25</age> </person> </root> `; console.log(JSON.stringify(xmlToJson(xmlString), null, 2));
高级处理技巧
-
处理命名空间:
function removeNamespace(node) { if (node.nodeType === Node.ELEMENT_NODE) { node.nodeName = node.localName || node.nodeName; } // 递归处理子节点 while (node.firstChild) { removeNamespace(node.firstChild); node.parentNode.appendChild(node.firstChild); } }
-
自定义转换规则:
function customConverter(node, json) { // 根据业务需求自定义转换逻辑 if (node.nodeName === 'date') { return new Date(node.textContent); } return json; }
性能优化建议
- 对于大型XML文件,考虑使用流式解析(SAX方式)
- 缓存已解析的节点,避免重复处理
- 使用对象池技术减少内存分配
常见问题与解决方案
- CDATA处理:需要特别识别
<![CDATA[ ]]>
部分 - 特殊字符转义:确保XML中的特殊字符在JSON中正确转义
- 循环引用:避免XML中的循环引用导致无限递归
通过以上步骤,我们可以实现一个健壮的XML到JSON的手写转换器,虽然已有成熟的库(如xml2js)可以完成这项工作,但手写转换过程能帮助我们更理解两种数据格式的本质差异,为处理复杂场景打下坚实基础,在实际开发中,可以根据具体需求调整转换逻辑,确保数据转换的准确性和完整性。
还没有评论,来说两句吧...