XML 作为廉价 DSL:老技术的另类复兴
TL;DR
本文核心观点:
- 结构同构性 — XML 和 Lisp 的 S-expression 在结构上是同构的,这是它能做 DSL 的根本原因。
- 约束即优势 — XML 的层级结构 + 属性/元素语义区分 + XSD 验证,构成一个完整的 DSL 约束体系。
- 复古主义务实 — 技术选择存在周期性,SOAP 过度工程催生 REST 极简,REST 过度简化又让人们重新发现结构化表达的价值。
- 场景匹配 — XML 在需要严格验证、层级嵌套、混合内容的场景下仍是好选择,而非因为”过时”就该被排除。
那个引发争议的标题
Reddit 上最近有一篇文章的标题很简单:
“XML is a Cheap DSL”
评论区瞬间分裂成两派:
- 一派:”难道我们还要回到 SOAP 和 WSDL 的时代吗?”
- 另一派:”等等,他说得其实有道理…”
最高赞评论很精辟:
“Imagine lisp but instead of parens you had xml tags”
(想象一下 Lisp,但用 XML 标签代替括号)
这个评论揭示了核心洞察:XML 和 Lisp 的 S-expression 在结构上是同构的。
DSL 的本质是什么?
在讨论 XML 之前,我们需要理解什么是 DSL(Domain-Specific Language,领域特定语言)。
💡 Key Insight
XML 和 Lisp 的 S-expression 在结构上是同构的——XML 本质上是一种用标签语法表达的 S-expression,这也是它能做 DSL 的根本原因。
DSL 的特征
| 特征 | 说明 |
|---|---|
| 表达能力 | 用领域术语表达概念 |
| 约束性 | 不允许表达领域外的概念 |
| 可读性 | 领域专家能读懂 |
| 可验证性 | 可以静态检查正确性 |
例子对比
用 Python 写一个”编译 src/main.cc,生成可执行文件,链接 math 库”的构建逻辑,大致是这样:
# 通用语言:表达方式完全灵活
sources = ["src/main.cc"]
output_name = "my_binary"
libraries = ["m"]
compiler_flags = ["-Wall"]
对应的 Bazel BUILD 文件则直接约束表达方式:
# DSL:约束表达能力,只允许特定函数调用
cc_binary(
name = "my_binary",
srcs = ["src/main.cc"],
deps = ["@math"],
)
DSL 更简洁,且可以在语法层面约束——cc_binary 只接受特定参数,拼写错误在解析阶段就会被捕获,而不需要等到运行时。
XML 的 DSL 特性
那么 XML 如何成为一种 DSL?
💡 Key Insight
XML 的层级结构 + 属性/元素语义区分 + 命名空间验证,构成了一个完整的 DSL 三元组:表达能力、约束性、可验证性——这正是它区别于 JSON/YAML 的核心优势。
XML 的层级结构天然适合表达嵌套的领域概念。例如描述一本书:
<book>
<title>Structure and Interpretation of Computer Programs</title>
<authors>
<author>Harold Abelson</author>
<author>Gerald Jay Sussman</author>
</authors>
<metadata edition="2">
<publisher>MIT Press</publisher>
<year>1996</year>
</metadata>
</book>
等效的 JSON 也能表达同样的嵌套结构,但在标签语义上不如 XML 清晰——JSON 的键名需要靠约定来区分”这是元数据”还是”这是内容”,而 XML 通过属性和元素的语义区分让结构一目了然。
属性 vs 元素的语义区分
XML 用属性表达元数据,用元素表达内容,语义清晰:
<user id="42" role="admin">
<name>Alice Wang</name>
<email>alice@example.com</email>
</user>
在 JSON 里,同样的数据要么全部用键值对堆在一起:
{ "id": 42, "role": "admin", "name": "Alice Wang", "email": "alice@example.com" }
要么需要靠命名约定(如 role_ 前缀)来区分元数据和内容——这种模糊性在 XML 中不存在,属性和元素的语义区分是语言层面的约束。
命名空间和验证
XML 的 Schema(XSD)提供了强大的验证能力:
这比 JSON Schema 更早、更成熟、工具链更丰富。例如,一个描述”序列 + 必选元素”的 XSD 约束:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
xs:sequence 约束子元素顺序,xs:element 的 type 约束类型,xs:attribute use="required" 约束必选属性——这些在 JSON Schema 里需要组合多个关键词才能表达,而在 XSD 里是原语级别的支持。
为什么 XML 失宠了?
Reddit 上有一条高赞评论解释了原因:
“The reason XML fell out of favor is precisely because it’s so complex and flexible. It’s difficult to parse and it’s never really clear if you should use attributes or elements, and the entire namespace concept for most people is totally irrelevant to what they’re trying to do yet the parsing libraries all force you to learn and care about it.”
XML 失宠正是因为它太复杂和灵活。
💡 Key Insight
XML 的失败不是技术失败,而是工程学失败——它试图用一套通用解决方案解决所有问题,导致每个领域的专用方案都最终取代了它。
过度工程的企业应用
SOAP 时代,企业用 XML 表达一切:SOAP envelope → WSDL 描述接口 → UDDI 发现服务。一个简单的”获取用户信息”调用,需要:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getUser xmlns="http://example.com/users/">
<userId>42</userId>
</getUser>
</soap:Body>
</soap:Envelope>
对比 REST:用 HTTP Method + URL + JSON body 做同样的事,复杂度低了一个量级。WSDL 的强类型约束在理论上保证了”接口即文档”,但维护成本让团队最终选择用文档换灵活性——这就是为什么 REST 最终胜出。
解析复杂性
XML 解析器需要处理:
- 命名空间
- CDATA
- 实体引用
- DTD(Document Type Definition)
- 编码问题
而 JSON 解析器只需要处理:
- 对象
- 数组
- 字符串
- 数字
- 布尔/null
属性 vs 元素的困境
没有明确答案,导致团队内部争论。
XML vs 现代格式:场景对比
适合 XML 的场景
| 场景 | 原因 |
|---|---|
| 文档标记 | HTML 的成功证明 XML-like 语法适合文档 |
| 复杂配置 | 需要验证和结构化编辑 |
| 遗留系统集成 | 已经大量使用 XML |
| 需要混合内容 | 如技术文档(文本 + 代码 + 图片) |
| 行业标准 | 如 Maven POM、Android Manifest |
不适合 XML 的场景
| 场景 | 更好的选择 |
|---|---|
| API 通信 | JSON、gRPC |
| 简单配置 | YAML、TOML |
| 脚本/代码 | 专用脚本语言 |
| 人类手写 | YAML、TOML |
XML 作为 DSL 的真实案例
Apache Maven
Maven 的 XML 配置就是一种 DSL:领域术语(dependency、scope、artifact)直接映射到 XML 元素。
Android 布局文件
Android 布局 DSL 直观且强大。
SVG
SVG 就是 XML 作为图形 DSL 的完美例子。
复古主义的工程智慧
Reddit 上有一条幽默的评论:
“Everything that was old and crusty is the hottest rage. Bro let me tell you about soap and wsdl”
这句话背后是一种现象:工程师们开始重新审视被抛弃的老技术。
💡 Key Insight
技术选择存在周期性:每个极端都会引发下一个极端的反弹。SOAP 过度工程催生了 REST 的极简主义,而 REST 过度简化又让人们重新发现结构化表达的价值——这就是 XML 复古主义的本质。
复古主义的四个特征:
- 问题循环:新问题往往是老问题的变种
- 过度矫正:从极端(SOAP)到另一个极端(REST),然后开始寻找中间地带
- 工具成熟:当年折磨我们的工具问题,现在可能已经解决
- 领域适应:某些领域(如配置管理)其实更适合老技术的特性
不是怀旧,是务实
拥抱 XML 不是怀旧,而是:
- 承认 JSON/YAML 不是万能的
- 根据场景选择工具
- 不因为某个技术”过时”就自动排除它
结尾:合适工具做合适的事
XML 是不是一个好的 DSL?
答案是:看情况。
如果你需要:
- ✅ 严格的结构验证
- ✅ 层级嵌套表达
- ✅ 混合内容(文本 + 标记)
- ✅ 成熟的工具链(XSD、XPath、XSLT)
XML 可能是一个好选择。
如果你需要:
- ❌ 人类可读/可写
- ❌ 简单的键值配置
- ❌ 低解析开销
- ❌ Web API
选择 JSON/YAML/TOML。
正如那位 Reddit 用户所说:
“Please don’t.” 😂
但请记住:技术的价值在于解决问题,而不是追随潮流。
SOAP 可能确实过度工程了,但 XML 本身——作为一种结构化的数据表示方式——在某些场景下仍然有其价值。
合适工具做合适的事,无论它是新是旧。
参考与延伸阅读
- XML is a Cheap DSL - 原文
- S-expressions - Wikipedia
- Domain-Specific Languages - Martin Fowler
- XML Schema - W3C
- JSON vs XML - Douglas Crockford
深度阅读时间:约 8 分钟
本文灵感源自 2026-03-16 Reddit r/programming 讨论。
💬 评论
💡 使用 GitHub 账号登录 即可参与讨论