Skip to main content
Bun v1.4 中新增
在 Bun 中,XML 与 JSON、TOML、YAML 和 JSON5 一样是一等公民。你可以:
  • 使用 Bun.XML.parseBun.XML.stringify 解析和序列化 XML
  • 在运行时将 XML 文件 importrequire 为模块(包括热重载和 watch 模式支持)
  • 在使用 Bun 打包器的前端应用中 importrequire XML 文件

运行时 API

Bun.XML.parse()

将 XML 文档解析为普通 JavaScript 对象。
默认情况下,结果是一个以元素名称为键的紧凑对象——这是大多数 XML 转对象库所使用的形状:
  • 结果只有一个键,即根元素的名称
  • 没有属性且没有子元素的元素会变成其文本内容,并去除周围的空白(为空时为 ""
  • 其他元素会变成一个对象:每个属性对应一个 "@name" 键,每个不同的子元素名称对应一个键——当该名称重复时使用数组,并保持文档顺序——如果存在经过修剪的字符数据,则使用 "#text" 表示
  • CDATA 节和实体引用已经展开到文本中。注释和处理指令会被丢弃
  • 所有值都是字符串。不会将任何内容强制转换为数字、布尔值或 null
紧凑形状不会保留不同名称的同级元素之间,或子元素之间文本的相对顺序。当这一点很重要时——处理文档而非数据时——传入 { compact: false },以获得一个能够保留所有文档顺序的根元素节点树
每个元素都是 { name, attributes, children }children 保存子元素和字符串,文本会原样传递(包括元素之间仅由空白组成的文本)。

输入类型和编码

XML.parse 接受字符串,或作为 BufferTypedArrayArrayBufferBlob 的字节数据。 字符串已经是解码后的文本,因此会检查其中 encoding 声明的语法,但除此之外会忽略该声明。字节数据会按照 XML 规则解码:字节顺序标记或 <?xml version="1.0" encoding="..."?> 中的 encoding 会选择 UTF-8(默认)、UTF-16(任一字节序)或 ISO-8859-1。其他编码会抛出错误。

错误处理

当文档格式不正确时,Bun.XML.parse() 会抛出 SyntaxError

Bun.XML.stringify()

将任一形状重新序列化为 XML。输出没有 XML 声明,并且始终格式正确:会对 &<>(以及属性中的引号、制表符和换行符)进行转义,而不是 XML 名称的元素名或属性名会抛出错误。
具有字符串 name 以及 childrenattributes 属性的值会作为节点写入;其他内容都是紧凑对象,并且必须恰好有一个用于命名根元素的键。字符串、数字、布尔值、bigint 和 Date(作为 ISO 字符串)会变成文本,null 会变成空元素,而 undefined、函数和符号会像 JSON.stringify 跳过它们一样被跳过(与 JSON.stringify 不同,bigint 会以十进制数字写入,而不是被拒绝)。

美化打印

传入 space 参数(空格数量或缩进字符串,与 JSON.stringify 一致)即可缩进仅包含元素的内容。包含文本的元素会以内联形式写入,因此字符数据不会改变:
对于 XML.parse 生成的任何值,无论哪种形状,XML.parse(XML.stringify(value)) 都会返回 value

模块导入

ES Modules

你可以直接导入 XML 文件。文件的解码方式与传递给 XML.parse 的字节数据相同(根据字节顺序标记或声明使用 UTF-8、UTF-16 或 ISO-8859-1),模块的值是上文所述的紧凑对象:
config.xml

默认导入

app.ts

命名导入

根元素也可以作为命名导入使用:
app.ts

CommonJS

app.ts

导入属性

使用 with { type: "xml" } 将其他扩展名的文件作为 XML 解析:

XML 热重载

使用 bun --hot 运行应用程序时,Bun 会在 XML 文件发生变化时重新加载它们:
server.ts
terminal

打包器集成

使用 Bun 进行打包时,导入的 XML 文件会在构建时解析,并以内联 JavaScript 对象的形式写入:
terminal
在构建时解析意味着:
  • 生产环境中零运行时 XML 解析开销
  • 更小的打包体积
  • 对未使用的属性进行 Tree Shaking

动态导入

XML 文件可以动态导入:

一致性

Bun 的 XML 解析器使用 Rust 编写,实现了 XML 1.0(第五版),作为一种不读取外部实体的非验证处理器
  • 整个文档(包括内部 DTD 子集)都必须格式正确——否则会抛出 SyntaxError
  • 文档中声明的内部实体会被展开(具有展开限制,因此“billion laughs”负载会失败,而不会耗尽内存),属性值会被规范化,并且会应用内部子集中声明的属性默认值
  • 永远不会获取或读取外部 DTD 和外部实体,因此不存在 XXE 攻击面。在没有 DTD 的文档中,对未声明实体的引用会出错;当 DOCTYPE 指向外部子集(或使用可能声明该实体的参数实体)时,该引用会按原样保留(&nbsp; 保持为 &nbsp;),除非文档声明了 standalone="yes"
  • 不会根据 DTD 进行验证,不会解析命名空间(带前缀的名称会原样保留),并且会跳过注释和处理指令
它会针对 W3C XML 一致性测试套件运行:对于此类处理器具有必需结果的全部 1,679 个测试用例均已通过——格式不正确的文档会被拒绝,格式正确的文档会被接受;如果测试套件提供了规范输出,其元素树也会逐字节匹配。 已翻译的测试套件列出了每个测试用例,包括那些结果合理地取决于不读取外部实体的测试用例。

性能

解析器分两个阶段工作,与 Bun 的 JSON 解析器类似:SIMD 阶段(运行时分派 AVX2/AVX-512/NEON/SVE 内核)会找出可能改变解析结果的字节,因此不会逐字节扫描字符数据、属性值、注释和 CDATA 节;元素名和属性名会复用 JavaScriptCore 的原子字符串缓存,其方式与 JSON.parse 相同。 bench/xml/xml.mjs 会在相同文档上比较 Bun.XML.parse 与常用的 npm 解析器(越低越好;Linux x64,单核):