--------------------------------------------------------------------------------------------------------
XML 和 JSON,是程序员几乎每天都会打交道的数据、特别是配置数据的承载格式。我想你心里应该有一个大致的印象,它们二者各有什么优劣,但是也许没有系统地比较过。那今天我们就把它们放到一起,丁是丁卯是卯地分析分析,对比一下它们各自的特点。另外,这些年来,对于配置,特别是复杂 DSL 的配置,YAML 也逐渐流行开来,因此我们也把它拿过来剖析一番。
XML 和 JSON 的比较
XML 全称叫做 Extensible Markup Language,就像 HTML、CSS 一样,是一种标记语言(标记语言不属于传统意义上的编程语言),且是一种具备结构化特征的数据交换语言;类似地,JSON,也就是 JavaScript Object Notation,被称作 JavaScript 对象表示法,非结构化,更轻量,但归根结底也是一种数据交换语言。因此,二者具备相当程度的相似性,在实际应用中,往往也可以比较和替代。
1. 简洁还是严谨
在 [第 04 讲] 的时候,介绍了 REST 和 SOAP 这样一个简洁、一个严谨的俩兄弟。而在本讲中,JSON 和 XML 也在一定程度上同样满足这样的比较关系,JSON 往往是更为简洁、快速的那一个,而 XML 则更为严谨、周全。
我们来看一个简单的例子,id 为 1 的城市北京:
<?xml version="1.0" encoding="UTF-8" ?>
<city>
  <name>Beijing</name>
  <id>1<id>
</city>
一键获取完整项目代码
XML
如果用 JSON 表示:
{
  "city": {
    "name": "Beijing",
    "id": 1
  }
}
一键获取完整项目代码
bash
你可能会说,除了 XML tag 的名字,在 JSON 中只需要写一遍以外,看起来复杂复杂、严谨的程度似乎也差不太多啊。
别急,往下看。XML 的结构,强制要求每一个内容数据,都必须具备能够说明它的结构,而 JSON 则没有这样的要求。比方说,如果我们把城市组成数组,用 XML 来表示,请你把这个文件存成 cities.xml,因为我们会多次用到这个文件:
<?xml version="1.0" encoding="UTF-8" ?>
<cities>
  <city>
    <name>Beijing</name>
    <id>1</id>
  </city>
  <city>
    <name>Shanghai</name>
    <id>2</id>
  </city>
</cities>
一键获取完整项目代码
XML
如果使用 JSON 的话,由于对于数组可以使用中括号直接支持,而不需要显式写出上例中的 city 这个 tag 的名称,请你同样建立 cities.json:
{
  "cities": [
    {"name": "Beijing", "id": 1},
    {"name": "Shanghai", "id": 2}
  ]
}
一键获取完整项目代码
bash
从这就可以看出,在这种情况下,JSON 似乎确实要更为简洁一些。上例中 JSON 能够使用中括号直接表示数组,能够直接支持数值、字符串和布尔型的表示。
等等,这样说的话,JSON 因为能够直接支持数值的表示,这个 id 没有双引号修饰,就是数值类型,可是从 XML 中并不能看出这一点啊。因此,从这个角度说,应该是 JSON 更严谨啊!那为什么说 XML 更严谨,严谨在哪呢?
有些程序员朋友可能会马上想到,XML 是可以定义 tag 属性的,预定义一个 type 不就好了?
<city>
  <name type="String">Beijing</name>
  <id type="number">1<id>
</city>
一键获取完整项目代码
XML
看起来也能达到“严谨”的目的,可这很可能就是一个不好的实践了,因为 XML 对于这些常见的数据类型,内置了直接的支持。我们可以通过定义 XML Schema Definition(XSD)来对 XML 的结构做出明确的要求,也就是说,我们不必自己去造轮子,来定义并实现这个 type 属性。针对上面的 cities.xml,我们可以定义这样的 XSD:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="cities">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="city" maxOccurs="unbounded" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:string" name="name"/>
              <xs:element type="xs:byte" name="id"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
一键获取完整项目代码
XML
这样一来,我们就对 cities 和 city 这两个 tag 做了严格的内容限定,包括包含的子节点有哪些,顺序如何,取值类型是什么等等。在实际的 XML 定义中,我们可以引用这个 XSD,这样 XML 的处理程序就会加载这个 XSD 并根据 schema 的规则对 XML 进行校验,从而发现 XML 不合要求的问题。
进一步地,你可以自己动动手,看一下这个工具,它可以帮助你通过 XML 快速生成样例 XSD;而这个工具则可以帮你快速验证 XML 是不是满足某 XSD 的要求,它们都很有用。
补充一下,你可能也听说过,或使用过类似的叫做 DTD,也就是 Document Type Definition 的方式,能想到这个很好,但是 XSD 相对来说有着更大的优势,并成为了 W3C 的标准。因此我在这里不提 DTD,但是我在扩展阅读中放了关于 XSD 和 DTD 的比较材料,供感兴趣的朋友拓展。
我想,从 XSD 你应该可以体会到 XML 的严谨性了。那喜爱使用 JSON 的程序员,就不能创造一个类似的东西,来填补这个坑——即定义和保证 JSON 的严谨性吗?
有,它就是 JSON Schema,也许你已经在项目中使用了,但是还没有统一成标准,也没有被足够广泛地接纳,因此我就不展开来说了。你可以自己实践一下,把上面提到的 JSON 填写到这个 JSON Schema 推断工具上面,去看看生成的 JSON Schema 样例。
2. JavaScript 一家亲
对于全栈工程师来说,和 XML 比较起来,JSON 对于前端开发来说,可以说有着不可比拟的亲和力。本来,JSON 就是 JavaScript 对象表示法,就是从 JavaScript 这个源头发展而来的,当然,JSON 如今是不依赖于任何编程语言的。这个“一家亲”,首先表现在,JSON 和 JavaScript 对象之间的互相转化,可以说是轻而易举的。
我们来动动手实践一下,打开 Chrome 的开发者工具,切换到 Console 页,打开前面建立的 cities.json,拷贝其中的内容到一对反引号(backtick,就是键盘上 esc 下面的那个按键)中,并赋给变量 text:
var text = `JSON 字符串`;
一键获取完整项目代码
javascript
我们很轻松地就可以把它转化为 JavaScript 对象(反序列化),不需要任何第三方的 parser:
var obj = JSON.parse(text);
一键获取完整项目代码
javascript
在早些时候的 ES 版本中,这个方法不支持,那么还可以使用 eval 大法,效果是一样的:
var obj = eval('(' + text + ')');
一键获取完整项目代码
javascript
不过,在现代浏览器中,如果 text 不是绝对安全的,就不要使用这样的方法,因为 eval 可以执行任何恶意代码。
当然,我们也可以把 JavaScript 对象转换回(序列化)JSON 文本:
var serializedText = JSON.stringify(obj);
一键获取完整项目代码
javascript
完成以后,先不要关闭控制台,下面还会用到。
--------------------------------------------------------------------------------------------------------
JSON、XML、TOML、CSON、YAML 大比拼
在数据序列化和配置文件领域,JSON、XML、TOML、CSON 和 YAML 是五种常见的格式。它们各有优缺点,适用于不同的场景。下面我们将从定义、应用场景、优缺点等方面进行详细对比。
1. JSON (JavaScript Object Notation)
定义
JSON 是一种轻量级的数据交换格式,基于 JavaScript 的对象语法,易于人阅读和编写,也易于机器解析和生成。
语法示例

应用场景
- 
Web API 数据交换:JSON 是 RESTful API 中最常用的数据格式。
 - 
配置文件:许多工具和框架(如 ESLint、Prettier)使用 JSON 作为配置文件格式。
 - 
数据存储:NoSQL 数据库(如 MongoDB)支持 JSON 格式的数据存储。
 
优点
- 
简洁:语法简单,易于阅读和编写。
 - 
广泛支持:几乎所有编程语言都支持 JSON 解析和生成。
 - 
轻量级:文件体积小,传输效率高。
 
缺点
- 
不支持注释:JSON 标准不支持注释,不适合需要注释的配置文件。
 - 
数据类型有限:仅支持字符串、数字、布尔值、数组、对象和
null。 
2. XML (eXtensible Markup Language)
定义
XML 是一种标记语言,用于存储和传输数据,具有自我描述性。
语法示例

应用场景
- 
数据交换:XML 曾广泛用于 Web 服务和 SOAP 协议。
 - 
配置文件:Java 生态系统(如 Maven、Spring)常用 XML 作为配置文件格式。
 - 
文档存储:Microsoft Office 文件(如
.docx、.xlsx)内部使用 XML。 
优点
- 
可扩展性:支持自定义标签和结构。
 - 
支持注释:XML 支持注释,适合需要注释的配置文件。
 - 
广泛支持:几乎所有编程语言都支持 XML 解析和生成。
 
缺点
- 
冗长:语法繁琐,文件体积大。
 - 
解析复杂:解析 XML 需要更多的计算资源。
 
3. TOML (Tom's Obvious, Minimal Language)
定义
TOML 是一种旨在易于阅读和编写的配置文件格式,语法类似于 INI 文件。
语法示例

应用场景
- 
配置文件:TOML 常用于 Rust 项目(如 Cargo)和 Python 项目(如 Poetry)。
 - 
数据存储:适合需要人类可读的配置文件。
 
优点
- 
简洁易读:语法简单,易于阅读和编写。
 - 
支持注释:支持行注释(
#)。 - 
数据类型丰富:支持字符串、数字、布尔值、数组、表等。
 
缺点
- 
生态系统较小:相比 JSON 和 YAML,TOML 的生态系统较小。
 - 
嵌套结构复杂:处理嵌套结构时语法稍显繁琐。
 
4. CSON (CoffeeScript Object Notation)
定义
CSON 是一种基于 CoffeeScript 语法的配置文件格式,支持更灵活的语法。
语法示例

应用场景
- 
配置文件:Atom 编辑器使用 CSON 作为配置文件格式。
 - 
数据存储:适合需要灵活语法的配置文件。
 
优点
- 
语法灵活:支持多行字符串、注释等。
 - 
易于阅读:语法简洁,适合人类阅读。
 
缺点
- 
生态系统较小:CSON 的生态系统较小,支持的工具和库较少。
 - 
解析复杂:解析 CSON 需要额外的库支持。
 
5. YAML (YAML Ain't Markup Language)
定义
YAML 是一种人类可读的数据序列化格式,旨在简洁易读。
语法示例

应用场景
- 
配置文件:Kubernetes、Ansible、GitLab CI 等工具使用 YAML 作为配置文件格式。
 - 
数据交换:适合需要人类可读的数据交换场景。
 
优点
- 
简洁易读:语法简洁,适合人类阅读和编写。
 - 
支持注释:支持行注释(
#)。 - 
数据类型丰富:支持字符串、数字、布尔值、数组、对象等。
 
缺点
- 
缩进敏感:YAML 依赖缩进,容易因缩进错误导致解析失败。
 - 
解析复杂:处理复杂数据结构时,解析器实现较为复杂。
 
对比总结

选择建议
- 
JSON:适合 Web API 数据交换和简单的配置文件。
 - 
XML:适合需要复杂结构和注释的场景(如 Java 生态系统)。
 - 
TOML:适合需要简洁易读的配置文件(如 Rust、Python 项目)。
 - 
CSON:适合需要灵活语法的配置文件(如 Atom 编辑器)。
 - 
YAML:适合需要人类可读的配置文件和数据交换(如 Kubernetes、Ansible)。
 
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------