Skip to main content

JSON & YAML 教程

· 约28分钟
Proca

在数据传输交换和配置文件的领域,JSON 和 YAML 是两种常见的格式,它们都可以表示复杂的数据结构和对象。

本文将通过一些具体的例子,介绍 JSON 和 YAML 的历史、语法、用法和区别,帮助你了解这两种格式的特点和适用场景。

JSON 简介

JSON 是一种纯文本的数据交换格式,它的全称是 JavaScript Object Notation,意思是用 JavaScript 语言的对象结构来表示数据。

可见,JSON 是 JavaScript 语言的一个子集,但它不包含 JavaScript 的代码逻辑,只包含数据的键值对。因此,JSON 可以被不同的平台和语言轻松地解析和使用。

相较于其他数据格式,JSON有以下几个优点:

优点描述
简洁JSON使用了很少的标记符号,比XML等其他格式更紧凑
易读JSON的结构清晰,易于人类阅读和理解。
易写JSON的语法简单,易于编写和修改。
易解析JSON可以被JavaScript和许多其他语言直接解析为对象或数组,无需额外的转换步骤。

要使用 JSON 格式,我们就必须遵循 JSON 语法。JSON 的语法非常简单,接下来,让我们逐步了解 JSON 的语法。

JSON 语法

键值对

当 JSON 数据是一个对象时,就像 JavaScript 中那样,它由键值对(key-value pair)组成。具体来说,JSON 的每个键值对用冒号(:)隔开,多个键值对用逗号(,)隔开。键值对可以表示一个属性、一个变量、一个参数等。

例如,下面的 JSON 数据表示一个人的信息,包含姓名、年龄、性别三个键值对:

{
"name": "Tom",
"age": 25,
"gender": "male"
}

JSON 数据中的键必须是字符串(string),用双引号(")括起来,不能使用单引号(')。键可以是任意合法的 JavaScript 标识符,但不能包含空格或特殊字符。

例如,下面的 JSON 数据中有四个键:name、age、gender、scores:

{
"name": "Alice",
"age": 18,
"gender": "female",
"scores": {
"math": 90,
"english": 85,
"science": 95
}
}

JSON 数据中的值可以是以下几种类型:

类型描述
数字(number)可以是十进制整数或小数,不能使用科学计数法或其他进制表示。
字符串(string)用双引号括起来,可以包含任意字符,包括转义字符(\),例如换行符(\n)、双引号(\")、反斜杠(\)等。
布尔值(boolean)true或false,表示逻辑真或假。
空值(null)null,表示没有值或者未知的值。
对象(object)用花括号({ })括起来,表示一个由键值对(key-value pair)组成的数据结构。对象可以嵌套其他对象或数组,形成复杂的层次结构。

例如,下面的 JSON 数据中有五种类型的值:对象、数字、字符串、布尔值、空值:

{
"id": 123,
"name": "Tom",
"is_admin": true,
"email": null,
"address": {
"city": "New York",
"zip": 10001
}
}

需要强调的是,下面这些格式 JSON 是不支持的:

格式
函数(function)
日期(date)
正则表达式(regexp)
undefined
NaN
Infinity
-Infinity

但我们都知道,JavaScript 中的函数、日期、正则表达式等数据类型都可以转换为字符串,因此,JSON 中可以使用字符串来表示这些类型的数据。

例如,下面的 JSON 数据中使用字符串来表示日期和正则表达式:

{
"birthday": "1990-01-01",
"pattern": "^\\w+@[a-z]+\\.[a-z]+$"
}

数组

上面的例子中的 JSON 数据都是一个对象,事实上,JSON 数据也可以是一个数组(array)。

JSON 数组中的元素必须用方括号([ ])括起来,表示一个有序的数据集合,包含多个元素。数组中的元素可以是任意类型的 JSON 数据,包括对象和数组。

例如,下面的 JSON 数据表示一组颜色,包含红色、绿色、蓝色三个元素:

[
"red",
"green",
"blue"
]

另外,就像刚才介绍的,数组中的元素也可以是对象,例如,下面的 JSON 数据表示一组超级英雄的信息,它包含两个超级英雄:

[
{
"name": "Captain Marvel",
"age": 32,
"secretIdentity": "Carol Danvers",
"powers": [
"Super strength",
"Flight",
"Energy projection"
]
},
{
"name": "Spider-Man",
"age": 18,
"secretIdentity": "Peter Parker",
"powers": [
"Spider sense",
"Web shooting",
"Wall crawling"
]
}
]

编码

JSON 数据必须使用 UTF-8 编码,否则在多语言环境下,可能导致解析错误或乱码。UTF-8 编码可以支持多种语言和字符,包括中文、日文、韩文、阿拉伯文、希腊文等。

拓展阅读

更多有关字符编码的内容,可参阅 了解字符编码:ASCII、UTF-8

例如,下面的 JSON 数据中使用 UTF-8 编码来表示中文和日文:

{
"language": "日文",
"greeting": "はちみはちみはちみはちみはちみ,はちみを舐めると~"
}
提示

如果你没看到乱码,那基本说明你在浏览本网页时,默认使用了 UTF-8 编码。

格式

JSON 数据标准不允许有注释(comment)。这是为了保持 JSON 数据的简洁和一致性。

例如,下面的 JSON 数据是一个不合法的格式,因为它包含了注释:

{
// 用户信息 (这是一个注释,JSON不允许有注释)
"name": "Tom",
"age": 25
}

把注释去掉就好了:

{
"name": "Tom",
"age": 25
}

JSON 用法

JSON 通常应用于以下场景:

场景描述
存储数据作为一种轻量级的数据库格式,存储简单的数据结构和对象
配置文件作为一种配置文件格式,存储应用程序或系统的设置和参数
数据交换作为一种数据交换格式,在不同的平台和语言之间传递和处理数据。例如,Web服务和API通常使用JSON作为响应格式,返回给客户端请求的数据

下面我们通过一些具体的例子来介绍 JSON 的用法,并让你对 JSON 有更深入的了解。

存储数据

假设我们要存储一个学生信息表,每个学生有姓名、年龄、性别、成绩等属性。我们可以使用JSON来表示这个数据结构,如下所示:

[
{
"name": "Alice",
"age": 18,
"gender": "female",
"scores": {
"math": 90,
"english": 85,
"science": 95
}
},
{
"name": "Bob",
"age": 19,
"gender": "male",
"scores": {
"math": 80,
"english": 75,
"science": 85
}
},
{
"name": "Charlie",
"age": 20,
"gender": "male",
"scores": {
"math": 70,
"english": 65,
"science": 75
}
}
]

这个 JSON 数据是一个数组,数组中的每个元素是一个对象,对象中的每个键值对表示一个学生的一个属性。 而对象中的值可以是另一个对象,例如 scores 属性的值是一个对象,表示学生的各科成绩。

我们可以将这个 JSON 数据保存为一个文件,例如 student.json ,然后在需要的时候读取和解析这个文件,获取我们想要的数据。

配置文件

现在假设我们有一个Web服务器,自然地,我们需要配置该服务器的基本信息,例如端口号、日志文件路径、静态文件目录等。

我们可以使用 JSON 来表示这些参数,如下所示:

{
"port": 8080,
"log_file": "/var/log/webserver.log",
"static_dir": "/var/www/html"
}

这个 JSON 数据是一个对象,对象中的每个键值对表示一个参数的名称和值。另外,你应该还记得,值可以是数字、字符串、布尔值或空值。

同样地,我们可以将这个 JSON 数据保存为一个文件,例如 webserver.json,然后在启动Web服务器的时候读取和解析这个文件,设置相应的参数。

数据交换

当我们需要通过 Web 服务器来查询某些数据,例如天气信息时,JSON 也是一个很好的选择。

我们假设某个 Web 服务提供了一个 API 接口,接受一个城市名称作为参数,返回该城市的当前温度、湿度、风速等信息。我们可以使用JSON来表示这个请求和响应的格式,如下所示:

请求:

{
"city": "ShenZhen"
}

响应:

{
"city": "ShenZhen",
"temperature": 25,
"humidity": 60,
"wind_speed": 5
}

注意,请求和响应的 JSON 数据必须使用 UTF-8 编码,并且遵循 HTTP 协议的规范。

总之,我们可以使用 JavaScript 或其他语言来编写客户端程序,发送请求并接收响应,然后解析响应中的JSON数据,获取我们想要的信息。

YAML 是什么?

在上面,我们介绍了JSON的用法,但你有没有觉得 JSON 还是有点复杂? 有没有一种更简洁、易读、易写的数据序列化格式呢?答案是肯定的,那就是 YAML。

YAML 是一种数据序列化格式,它的全称是YAML Ain't Markup Language,意思是:“YAML 不是一种标记语言”。所谓标记语言,就是使用标记来表示数据的语言,例如XML、HTML等。 YAML 最初是为了取代 XML 而设计的,但后来也被用于取代 JSON。YAML 的目标是让人类可以方便地阅读和编写数据,同时也便于被机器解析。

YAML 在日常开发、配置文件、博客文章等领域都有广泛的应用,例如 Docker Compose、Kubernetes、Jekyll、RASA 等都使用了 YAML。下面让我们从学习 YAML 的语法开始,进入 YAML 的世界。

YAML 语法

YAML 的语法非常简单,它主要有以下几个特点:

  1. YAML 使用缩进来表示层级关系,缩进的空格数目不重要,只要相同层级的元素左对齐即可。
  2. YAML 支持使用 # 来添加注释,注释必须在行尾或者单独一行
  3. YAML 使用冒号 : 来表示键值对,冒号后面必须有一个空格
  4. YAML 使用短横线 - 来表示列表项,短横线后面也必须有一个空格
  5. YAML 支持使用双引号 " 或者单引号 ' 来表示字符串,也可以不使用引号,但要注意避免与保留字符冲突。
  6. YAML 支持使用 | 或者 > 来表示多行字符串,| 会保留换行符,而 > 会折叠换行符。
  7. YAML 支持使用 &* 来表示锚点和引用,可以实现复用和继承的功能。

目前你只需要对这些要点有个大概的印象即可,下面我们会通过具体的例子来学习 YAML 的语法和用法。

基本语法

我们先来看一个最简单的 YAML 文件,它只包含了一个键值对:

url: http://127.0.0.1:3000

这个文件的含义是:url 是一个键,http://127.0.0.1:3000 是它的值。这个值是一个字符串,它表示一个 URL 地址。

我们可以用 JSON 来表示同样的数据:

{
"url": "http://127.0.0.1:3000"
}

可以看到,YAML 比 JSON 更加简洁,不需要使用花括号、逗号等符号。YAML 也更加易读,因为它使用了缩进和空格来表示结构。

要注意,YAML格式下,键的冒号后面必须有一个空格,这是因为,在没有空格的情况下,冒号后的字符串如果也含有冒号,就会被误认为是键值对的分隔符。

比如,如果我们把上面的文件改成下面这样,就会出错:

# 错误的示范
url:http://127.0.0.1:3000

如果我们想要定义多个键值对,我们只需要在同一层级下添加更多的键值对即可:

name: Alice
age: 18
gender: female

这个文件的含义是:定义了三个键值对,分别是 nameagegender。它们的值分别是字符串 Alice、数字 18 和字符串 female。我们可以用 JSON 来表示同样的数据:

{
"name": "Alice",
"age": 18,
"gender": "female"
}

可以看到,YAML 和 JSON 的数据结构是一致的,只是表达方式不同。

纯量

在 YAML 中,纯量来示基本的数据类型。纯量就是单个的,它没有层级关系或者结构。纯量可以是字符串、数字、布尔值、日期、时间等。可见,纯量的范围非常广泛。

我们先来看一个纯量的例子:

pi: 3.14159

这个文件的含义是:定义了一个名为 pi 的键,它的值是一个数字 3.14159。我们可以用 JSON 来表示同样的数据:

{
"pi": 3.14159
}

如果我们想要定义多个纯量,我们只需要在同一层级下添加更多的键即可:

pi: 3.14159
e: 2.71828
g: 9.8
date: 2020-01-01

这个文件的含义是:定义了四个键,分别是 piegdate。前三个键的值都是数字,分别是 3.141592.718289.8;最后一个键 date 的值是日期 2020-01-01。我们可以用 JSON 来表示同样的数据:

{
"pi": 3.14159,
"e": 2.71828,
"g": 9.8,
"date": "2020-01-01"
}

注意,JSON 中的日期必须使用字符串来表示,而 YAML 中的日期可以直接使用日期类型。

对象

在 YAML 中,我们可以使用对象来表示复杂的数据结构。对象就是由多个键值对组成的集合,它们之间有层级关系。对象可以嵌套对象,也可以嵌套列表(数组)。

我们先来看一个对象的例子:

person:
name: Alice
age: 18
gender: female

这个文件的含义是:定义了一个名为 person 的键,它的值是一个对象。这个对象包含了三个键值对,分别是 nameagegender。我们可以用 JSON 来表示同样的数据:

{
"person": {
"name": "Alice",
"age": 18,
"gender": "female"
}
}

如果我们想要定义多个对象,我们只需要在同一层级下添加更多的键即可:

person1:
name: Alice
age: 18
gender: female
person2:
name: Bob
age: 20
gender: male

这个文件的含义是:定义了两个键,分别是 person1person2。它们的值都是对象,分别包含了三个键值对,分别是 nameagegender。我们可以用 JSON 来表示同样的数据:

{
"person1": {
"name": "Alice",
"age": 18,
"gender": "female"
},
"person2": {
"name": "Bob",
"age": 20,
"gender": "male"
}
}

同样地,你会发现 YAML 比 JSON 更加简洁!

数组

在 YAML 中,我们可以使用数组来表示一组有序的数据。数组就是由多个元素组成的列表,它们之间没有键值对的关系。数组可以嵌套数组,也可以嵌套对象。

我们先来看一个数组的例子:

colors:
- red
- green
- blue

这个文件的含义是:定义了一个名为 colors 的键,它的值是一个数组。当然,别忘了,YAML 中的数组也是有层级关系的,它们之间也要缩进。并且,数组的元素前面的短横线 - 后,也要有一个空格。

上面的数组包含了三个元素,分别是字符串 redgreenblue。我们可以用 JSON 来表示同样的数据:

{
"colors": [
"red",
"green",
"blue"
]
}

可以看到,YAML 使用了短横线来表示数组中的元素,没有方括号和逗号等符号。但事实上,你也可以使用方括号来表示数组:

colors: [red, green, blue]

YAML 中的方括号和短横线是等价的,它们都表示数组。在实际开发中,我们一般会使用短横线,因为这样更加易读。

如果我们想要定义多个数组,我们只需要在同一层级下添加更多的键即可:

colors:
- red
- green
- blue
fruits:
- apple
- banana
- orange

这个文件的含义是:定义了两个键,分别是 colorsfruits。它们的值都是数组,分别包含了三个元素,分别是字符串 redgreenblue,以及字符串 applebananaorange。我们也可以用 JSON 来表示同样的数据:

{
"colors": [
"red",
"green",
"blue"
],
"fruits": [
"apple",
"banana",
"orange"
]
}

锚点和引用

在 YAML 中有一项强大的功能,叫做锚点和引用。它们可以让我们复用和继承数据。

锚点就是给某个值或者对象起一个别名,引用就是使用这个别名来代替原来的值或者对象。

我们再来看一个纯量的锚点和引用的例子:

port: &port '8080'

server1:
port: *port

server2:
port: *port

这个文件的含义是:定义了一个名为 port 的键,它的值是一个字符串 '8080'。这个字符串使用了 &port 来表示一个锚点,意思是给这个字符串起了一个别名叫做 port

然后定义了两个键,分别是 server1server2。它们的值都是对象,并且包含了一个键值对 port。这两个键值对的值都是一个引用,使用了 *port 来表示,意思是把 port 这个字符串的内容作为当前键的值。

我们可以用 JSON 来表示同样的数据,只是 JSON 中没有锚点和引用的概念,因此当我们需要复用的时候,就需要重复在两个 server 的配置中都写上 8080,并且当我们需要同时修改它们的端口时,也需要修改两次。

{
"port": "8080",
"server1": {
"port": "8080"
},
"server2": {
"port": "8080"
}
}

我们再来看一个对象的锚点和引用的例子:

defaults: &defaults
adapter: postgres
host: localhost

development:
database: dev_db
<<: *defaults

test:
database: test_db
<<: *defaults

这个文件的含义是:定义了一个名为 defaults 的键,它的值是一个对象,这个对象包含了两个键值对,分别是 adapterhost。这个对象使用了 &defaults 来表示一个锚点,意思是给这个对象起了一个别名叫做 defaults

然后定义了两个键,分别是 developmenttest。它们的值都是对象,并且包含了一个键值对 database。同时,这两个对象都使用了 <<: *defaults 来表示一个引用,意思是把 defaults 这个对象的内容合并到当前对象中。

我们可以用 JSON 来表示同样的数据:

{
"defaults": {
"adapter": "postgres",
"host": "localhost"
},
"development": {
"database": "dev_db",
"adapter": "postgres",
"host": "localhost"
},
"test": {
"database": "test_db",
"adapter": "postgres",
"host": "localhost"
}
}

可见,<< 这个符号的作用是把引用的对象的内容合并到当前对象中,它在 YAML 中被称为“合并键”。

YAML 用法

就像我们一开始介绍的,YAML 的用法非常广泛。下面我们来看一些 YAML 的常见用法。

配置文件

YAML 是一种非常适合作为配置文件的格式,因为它可以表示复杂的数据结构,同时又非常简洁和易读。 许多流行的软件或者框架都使用 YAML 作为配置文件的格式,例如 Docker、Kubernetes、Ansible、Ruby on Rails 等。

例如,下面是一个 Docker Compose 的配置文件,它使用 YAML 来定义了一个服务集合:

version: '3'
services:
web:
image: nginx
ports:
- '80:80'
depends_on:
- app
app:
image: node
volumes:
- .:/app
command: node app.js

这个文件的含义是:定义了一个版本为 3 的配置文件,它包含了两个服务,分别是 webappweb 服务使用了 nginx 镜像,并且映射了端口 80web 服务依赖于 app 服务。app 服务使用了 node 镜像,并且挂载了当前目录到 /app 目录。app 服务执行了命令 node app.js

可以看到,YAML 使用了缩进、短横线、冒号等符号来表示服务之间的层级关系和属性。YAML 的优势在于它更加简洁和易读。

数据交换

许多流行的数据交换协议或者格式都支持 YAML ,例如 RESTful API、Swagger、OpenAPI 等。

例如,下面是一个 Swagger 的配置文件,它使用 YAML 来定义了一个 API 文档:

swagger: '2.0'
info:
title: Sample API
description: A sample API for testing
version: '1.0'
paths:
/users:
get:
summary: Get all users
responses:
'200':
description: OK
schema:
type: array
items:
$ref: '#/definitions/User'
definitions:
User:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
email:
type: string
format: email

可以看到,YAML 使用了缩进、冒号、引用等符号来表示 API 文档的结构和内容。

这个文件的含义是:定义了一个版本为 2.0 的 Swagger 文件,它包含了一些基本信息,例如标题、描述、版本等。然后定义了一个路径 /users,它支持一个 get 操作,用于获取所有用户。这个操作有一个 summary 和一个 responsesresponses 包含了一个 200 状态码,它的描述是 OK,它的返回值是一个数组,数组的元素是一个 User 对象。最后定义了一个 User 对象,它包含了三个属性,分别是 idnameemail

文档生成

下面是一个 Jekyll 的配置文件,它使用 YAML 来定义了一个静态网站的设置:

title: My Blog
description: A personal blog about tech and life
url: https://example.com
theme: minima
plugins:
- jekyll-feed
- jekyll-seo-tag

这个文件的含义是:定义了一个标题为 My Blog 的静态网站,它有一个描述为 A personal blog about tech and life 的静态网站,它的网址是 https://example.com。它使用了一个主题为 minima 的静态网站,它有两个插件,分别是 jekyll-feedjekyll-seo-tag

总结

在这篇博客中,我们学习了 JSON 和 YAML 这两种数据格式的基本知识和应用场景。 我们学习了它们的定义、特点、优势、语法和用途,以及它们与其他数据格式的比较。 我们希望这篇博客能够帮助你更好地使用 JSON 和 YAML 来处理数据和配置文件,提高你的工作效率和质量。

如果你对 JSON 和 YAML 还有任何疑问,欢迎在评论区留言!

支持一下

暂无评论,来留下友好的评论吧