XML 转 JSON 转换器

将 XML 粘贴到左侧,得到右侧的 JSON。属性以 @_ 前缀保留。完全在浏览器中运行 — 无需上传。

  1. 将 XML 粘贴到左侧文本区。
  2. 点击「转换为 JSON」。元素嵌套会变成嵌套对象。
  3. 复制 JSON,或下载为 data.json。
  4. 重复出现的子元素会自动折叠成数组。
它能做什么?

按 fast-xml-parser 约定将 XML 解析为 JSON 对象: 子元素变成对象属性,重复子元素变成数组,属性以 `@_` 前缀保留在父对象上,混合节点的文本进入 `#text` 键。`parseAttributeValue: true` 让数字和布尔属性自动类型化 — XML 中的 `count="42"` 会变为 `"@_count": 42`,而不是字符串 `"42"`。

示例

XML 输入:

<root version="1">
  <name>Ada</name>
  <tags>math</tags>
  <tags>logic</tags>
</root>

JSON 输出:

{
  "root": {
    "@_version": 1,
    "name": "Ada",
    "tags": ["math", "logic"]
  }
}

常见 XML 陷阱及处理方法

XML 拥有 JSON 没有的边界情况。这些是会产生意外输出的模式。

  • 单个子元素 vs 多个子元素。 `<a><b/></a>` 得到 `{"a":{"b":""}}`(单个子元素作为对象属性),而 `<a><b/><b/></a>` 得到 `{"a":{"b":["",""]}}`(多个变为数组)。如果下游代码总是期待数组,请在转换后规范化。
  • 属性 vs 子元素。 属性以 `@_` 前缀与子元素同级出现。`<user id="1"><name>Ada</name></user>` 变成 `{"user":{"@_id":1,"name":"Ada"}}`。一些工具会把属性合并到普通属性中 — 那是不同的约定。
  • 混合内容(文本 + 子元素)。 `<p>Hello <b>world</b></p>` 得到 `{"p":{"#text":"Hello ","b":"world"}}`。文本被捕获了,但相对于子元素的位置丢失 — JSON 无法表达有序的混合内容。大多数配置型 XML 不会命中此情况。
  • 命名空间。 命名空间(`<x:foo xmlns:x="...">`)作为元素名称的一部分(`x:foo`)保留。许多 XML 消费者会去掉前缀;如果你需要,请在后处理中完成。
  • CDATA 段。 `<![CDATA[some text]]>` 被解析为普通文本并合并到父节点的 `#text` 中。CDATA 包装会丢失 — 大多数情况无碍,但如果包装本身有语义意义就要注意。
  • 自闭合 vs 空元素。 在 XML 中,`<x/>` 与 `<x></x>` 等价,产生相同的 JSON 输出(值为 `""`)。原始写法无法从 JSON 还原。
常见问题

为什么我的输出在属性上有 `@_` 前缀?

它用于区分 XML 属性与子元素。没有前缀时, `<user id="1"><id>foo</id></user>` 会有两个 `id` 键 — 而 JSON 对象只能有一个。前缀让两者都可以来回往返。如果你不需要前缀,后处理中将 `"@_"` 替换为 `""` 即可(并接受冲突风险)。

可以拿到不带根键的 JSON 吗?

XML 总有单一根元素。JSON 保留这层包装以便往返。如果你只需要内部对象,转换后取 `result.root`。

XML 注释会被保留吗?

不会。JSON 没有注释语法,解析器也被配置为忽略 XML 注释。如果你需要保留注释,就得使用支持注释的中间表示。

属性值会被类型化吗?

会 — 已设置 `parseAttributeValue: true`,所以 `count="42"` 变为 `"@_count": 42`(数字), `enabled="true"` 变为 `"@_enabled": true`(布尔)。如果需要保留为字符串,请后处理或修改配置。

我的 XML 会被上传吗?

不会。一切都在你的浏览器里运行 — 你的 XML 由本页 JavaScript 解析,不发送到任何服务器。可在浏览器开发者工具中验证。

可以处理非常大的 XML 文件吗?

约 30 MB 后文本框开始变慢。解析器本身按线性扩展。更大的输入请在命令行运行 fast-xml-parser — 同一个库。