XML 转 JSON 实战:老接口、SOAP、RSS 转成现代格式
讲清 XML 转 JSON 的真实用途,属性怎么映射,子元素和数组怎么处理,同名兄弟元素如何合并,附一段 SOAP 响应转出 JSON 的完整例子,以及直接在浏览器里解析的做法。
XML 转 JSON 实战:老接口、SOAP、RSS 转成现代格式
我维护过一个 2015 年的支付对接接口,对方至今只发 XML。每次联调,我都得把一段 SOAP 信封手动读成结构,再写成前端能用的对象。后来我把这件事交给工具做,省下的时间够我多喝两杯咖啡。这篇就讲清楚 XML 转 JSON 到底在解决什么,以及属性、子元素、数组这几个最容易翻车的点该怎么对待。
为什么还要把 XML 转成 JSON
现代前端和大部分 HTTP 服务默认说 JSON。但很多东西还在发 XML:银行和电信的 SOAP 接口、博客和播客的 RSS 与 Atom 源、Maven 的 POM 文件、Android 的 manifest。这些数据本身没问题,问题是格式不趁手。fetch 拿到 JSON 可以直接当对象用,拿到 XML 你还得自己遍历 DOM。把 XML 转成 JSON,等于给老系统接上一根能直接喂给现代代码的管子。
它不是为了取代 XML。SOAP 的服务端、RSS 的发布端短期内不会改。转换的意义是在你这一侧把数据变成顺手的形状,改完需要时再转回去。
属性和子元素到底怎么映射
XML 比 JSON 多一个概念:属性。<book id="1" lang="en"> 里的 id 和 lang 是属性,而书名可能是子元素或文本节点。JSON 没有"属性"这一层,所以必须约定一个放属性的地方。
常见做法是把属性收进一个专门的子对象。<book id="1" lang="en"/> 转成:
{ "book": { "@attrs": { "id": "1", "lang": "en" } } }
这样属性和子元素分得很清楚,不会撞名。如果你习惯 xml2js 那套内联前缀风格,把前缀切成 @,属性就平铺成 { "book": { "@id": "1", "@lang": "en" } }。两种风格都能反向还原成一模一样的 XML,选你下游代码读起来顺的那种就行。
文本节点同理。<title>购物车</title> 如果这个元素还带属性,文本会收进 #text 里,纯文本元素则直接是字符串值。
数组:最容易出 bug 的地方
XML 允许同名兄弟元素重复出现,JSON 没有这个语法,只能用数组表达。规则是这样:出现多次就合并成数组,只出现一次默认保持标量。
<list><item>a</item><item>b</item></list>
转成 { "list": { "item": ["a", "b"] } }。但只有一个 <item> 时,结果是 { "list": { "item": "a" } },是字符串不是数组。
这正是踩坑点。我吃过一次亏:RSS 源里通常有很多 <item>,代码里我写了 items.map(...)。某天一个源只剩一条新闻,item 变成了字符串,map 直接报错。解决办法是打开"始终数组"选项,强制单个子元素也包成只有一项的数组,下游代码就不用再判断形状。基于这种 JSON 生成 TypeScript 类型时,这个选项几乎是必开的。
一段 SOAP 响应转出来的样子
下面是从 DevTools 复制出来的一小段 SOAP 信封:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getPriceResponse currency="CNY">
<price>199.00</price>
</getPriceResponse>
</soap:Body>
</soap:Envelope>
转出来的 JSON:
{
"soap:Envelope": {
"soap:Body": {
"getPriceResponse": {
"@attrs": { "currency": "CNY" },
"price": "199.00"
}
}
}
}
注意 soap: 这个命名空间前缀原样留在 key 里,没有丢。currency 作为属性进了 @attrs,而 price 作为子元素直接是值。代码里读 data["soap:Envelope"]["soap:Body"].getPriceResponse.price 就能拿到价格,比手动遍历 DOM 干净太多。如果信封里还有 CDATA 块,会包在 #cdata 里,二进制片段和脚本内容都能完整往返。
为什么是浏览器原生解析,而不是装个包
很多人第一反应是 npm i xml2json。但那是 Node 端的库,底层调 libxml 或 expat,流水线里能用,浏览器标签页里没法跑。这个工具走的是浏览器原生的 DOMParser,跟 fetch 解析 XML 响应是同一个引擎,解析行为和你的运行时完全一致,不用装包,DevTools 里复制出来的响应直接粘进来就能转,全程在本地完成,SOAP 响应和 POM 文件都不出标签页。
需要时再转回去也很顺。改完 RSS 源的标题和链接,把 JSON 粘回 XML 转 JSON 工具 反向那一栏,或者用专门的 JSON 转 XML 工具,就能用同样的 @attrs 和 #text key 重建出原来的标签树,元素顺序、嵌套层级、属性拼写都保持一致。
一点提醒
往返不是绝对无损。注释会被丢掉,因为 JSON 没有注释节点;原始的 XML 声明也会丢,因为它是协议元数据不是数据本身;兄弟标签之间的空白同样不保留,不过任何 XML 格式化器都把它当可忽略空白。元素结构、属性、文本、CDATA、子节点顺序这些真正承载数据的东西,都能稳稳往返。把这几条记在心里,XML 转 JSON 就从"碰运气"变成了可预期的日常操作。
Made by Toolora · Updated 2026-06-13