# JSON 库使用指南

在 aardio 中，可以使用 `JSON` 库来编码（将表对象转换为 JSON 字符串）和解码（将 JSON 字符串解析为表对象）JSON 数据。

[JSON 库函数参考](../../../library-reference/JSON/_.html)

## 一. JSON 编解码 <a id="parse" href="#parse">&#x23;</a>


### 1. 解码 JSON（解析 JSON 字符串为表对象）

使用 `JSON.parse` 函数将 JSON 字符串解析为 aardio 表对象。

```aardio
import JSON;
import console;

// JSON 字符串
var jsonString = `{
    "name": "John",
    "age": 30,
    "hobbies": ["reading", "swimming"]
}`;

// 解析 JSON 字符串为表对象
var obj = JSON.parse(jsonString);

// 输出解析后的对象
console.dumpJson(obj);
console.log("Name:", obj.name);
console.log("Age:", obj.age);
console.log("Hobbies:", obj.hobbies);

console.pause();
```

JSON.parse 函数在解析出错时会抛出异常， JSON.tryParse 函数用法相同但在解析出错时会返回 null 值而非报错。

### 2. 编码 JSON（将表对象转换为 JSON 字符串）<a id="stringify" href="#stringify">&#x23;</a>


使用 `JSON.stringify` 函数将 aardio 表对象转换为 JSON 字符串。

```aardio
import JSON;

// 表对象
var obj = {
    name = "Alice";
    age = 25;
    hobbies = ["reading", "swimming"];
};

// 将表对象转换为 JSON 字符串
var jsonString = JSON.stringify(obj, true); // 参数 @2 为 true 时格式化 JSON

// 输出 JSON 字符串
print(jsonString);

```

### 3. 读写 JSON 文件 <a id="file" href="#file">&#x23;</a>

#### 编码对象并写入 JSON 文件

```aardio
import JSON;

// 表对象
var data = {
    name = "Bob";
    age = 28;
    isStudent = false;
};

// 将表对象转换为 JSON 字符串并保存到文件
JSON.save("/path/to/file.json", data);
```

#### 读取并解析 JSON 文件

```aardio
import JSON;
import console;

// 读取 JSON 文件并转换为表对象
var loadedObject = JSON.load("/path/to/file.json");
 
// 输出解析后的对象
console.dumpJson(loadedObject);
console.pause();
``` 

## 二. 类据类型转换要点 <a id="type-conversion" href="#type-conversion">&#x23;</a>


#### 1. 区分 JSON 对象与数组

在 aardio 中对象与数组的数据类型都是表（ table ）。
表可以包含数组成员，也可以包含键值对成员，只有在包含数组时才会被处理为 JSON 数组。
使用 `{}` 构造的空表处理为 JSON 空对象。

在 aardio 中也可以使用 `[]` 或 table.array() 函数构造 [纯数组](../../../language-reference/datatype/table/_.html#pure-array)。
aardio 纯数组在 JSON 中总是被处理为数组，aardio 使用 `[]` 构造的空数组在 JSON 中也会被处理为空数组 `[]`。

而 JSON 数组也会被解析为 aardio 纯数组，JSON 解析得到的数组默认会添加 length 元属性并指定解析时的数组长度（以处理 null 值）。length 元属性只对 table.eachIndex,table.len 或 JSON 库函数有效。需要注意的是表经过序列化复制（例如作为线程参数传递）会移除元表。

aardio 中存在很多其他来源的数组（例如 COM 数组，封装外部对象的数组）并不一定符合上面的规则。
JSON 使用 table.type() 函数来检测一个表是否应当被处理为数组。详细规则请查看 table.type() 函数的说明。

也可以使用 JSON.stringifyArray({}) 强制转换表为 JSON 数组。

#### 2. 保存对象的 null 值。

在 aardio 中 null 是一个不存在的值。
例如 { name = null } 等价于空表 {} 。

而在 JSON 中我们有时候需要保存 null 值。
这在 aardio 中很困难，但我们可以解决这个问题。

例如以下 aardio 代码：

```aardio
//定义 JSON
var json = "{name:null,age:22}";

//解析为对象
var object = JSON.parse(json);

//生成 JSON 
var json = JSON.stringify(object);
```

可以正确地保存 name 的 null 值。

aardio 通过在元表的 _defined 字段中指定必须保存 null 值的字段名。
可以调用 table.define() 定义需要保留 null 值的键名（可以重复调用以添加键名）。
JSON 库 或 table.eachName 支持 _defined 元属性。

#### 3. 时间 与 buffer 对象

buffer,time 对象与 JS 一样只负责字符串化，不负责在解析 JSON 时自动还原。

时间对象与 JS 语言相同转换为 ISO8601 格式字符串，
可使用 time.iso8601 函数解析并还原 iso8601 格式的时间对象。

buffer 类与 node.js 中的 Buffer 类相同,转换结果示例：
{"data":[230,181,139],"type":"Buffer"}
其中 type 指明类型,data 为字节串（ buffer 类型）转换得到的字节数组（ table 类型）。
这种表可以作为 raw.buffer 的唯一参数快速还原为 buffer 类型。

## 三. aardio 标准库 JSON 解析规范 <a id="specification" href="#specification">&#x23;</a>


发布日期：2020-12-27

JSON 字符串化时完全符合 JSON 官方标准( https://json.org/json-zh.html )。
JSON 解析时完全支持 JSON，JSONP，并使用宽松的原则兼容JSON5，兼容部分类 YAML 语法。

aardio 以“宽进严出、简洁高效”为基本原则。
解析时规则尽可能宽松容错，生成 JSON 字符串则严格遵守标准 JSON 规则。

aardio 标准库在遵守 JSON 标准协议的前提下为 JSON 解析器扩展了以下功能：

### 1. 可省略和替换的格式标记

- 允许省略根节点对象外部的 `{}`
- 允许使用分号、空格、换行替代元素分隔符`,`
- 允许使用等号、空格、换行替代对象键值分隔符`:`
- 允许省略字符串外部的引号。

### 2. 根节点

- JSON 节点可以是任意数据类型，单个字符串、数值都可以解析并返回值。
- 根节点是对象时，可以省略外层的花括号。
- 根节点是字符串时不可省略引号。
- 根节点解析成功的 JSON 后面如果还有多余的文本时忽略。
- 根节点兼容 JSONP 格式

### 3. 字符串

字符串置于双引号中时支持 JSON 转义符。
JSON 字符串置于单引号内不支持 JSON 转义符，使用 2 个单引号表示原始单引号。
在引号内部时字符串可以换行。

要特别注意 aardio 语法规则正好跟上面相反：
aardio 代码里单引号内是“编译时转义字符串”（反斜杆识别为转义符，属于 “JavaScript 风格字符串” ），而双引号内是原样字符串（编译时将反斜杆作为普通字符，并以两个双引号表示原始双引号,属于 “BASIC/SQL 风格” 字符串）。

JSON 字符串可省略首尾引号，此时不支持 JSON 转义符，遇到回车或换行、逗号、中括号、大括号时字符串结束解析。字符串作为对象键名如果省略引号时不能包含空白字符、换行或键值分隔符。 

### 4. 注释

1、支持 `//` 或 `#` 引导的单行注释
2、支持包含于 `/*......*/` 内的块注释（注意这里按js规则不匹配首尾星号数目）。 

### 5. 数值

数值支持 16 进制

### 6. null值

可以使用 `null`,`undefined`,`~` 表示 `null` 值。

### 7. 日期时间

可使用 ISO 8601 格式表示日期时间，合法的格式如下：

`2021-01-1`
`2021-02-1T15:02:31+08:00`
`2021-02-1T15:02:31+08:00Z`

数字前可不用补 0，但日期分隔符必须使用短横线，时间分隔符必须使用冒号，
尾部时区不可以包含空白字符，但可以包含 +-: 等字符以及数字、字母。

日期时间不用包含在引号内，引号内会被误别为字符串，示例：

```json
{"time":2021-01-1,"string":"2021-01-1" }
```

## aardio 开发环境的相关工具与范例 <a id="example" href="#example">&#x23;</a>


- 工具 » 编码 » JSON 与 table 互转
- 范例 » Web 应用 » JSON 
- 范例 » Web 应用 » REST » JSON