添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Skip to main content

函数库:json - 优雅地处理JSON

JSON是一种轻量级的数据交换格式。它使用文本格式来传输结构化数据,包括数组、对象、字符串、数字、布尔值和null。JSON格式被广泛用于Web应用程序和API中,作为一种数据格式,以实现不同应用程序之间的数据交换。JSON是一种平台无关的格式,可以使用许多编程语言进行解析和生成,包括JavaScript、Python、Java等。JSON的语法简单、易于理解和阅读,与XML和HTML相比,它更轻量级和灵活,因此在数据传输和存储方面更加高效。

在 Yaklang 中我们不仅支持基础的 JSON 处理接口,同时还支持更加优雅的 JsonPath 机制。

JSON PATH 是什么?

JSON Path是一种用于从JSON格式的数据结构中提取特定数据的查询语言,类似于XPath。它提供了一种通用的方式来访问和操作JSON数据,可以用于编程语言或命令行中,以实现复杂的JSON数据处理和分析。

#

yak 提供了一个类似 Python 的 json.loads/dumps 的处理方式

#

jsonRaw1 = `{"abc":123, "cde":"efg", "foo": "bar-123123", "azz": {"key1": "result2", "key2": 123, "e": ["abc", 111]}, "d": [1,2,3,"123"]}`jsonRaw2 = `[1,23,4,"abc",true,false, {"abc": 123123, "dddd":"123"}]`jsonRaw3 = `"123123123"`jsonRaw4 = `123123`jsonRaw5 = `false`jsonRaw6 = `null`dump(json.loads(jsonRaw1))dump(json.loads(jsonRaw2))dump(json.loads(jsonRaw3))dump(json.loads(jsonRaw4))dump(json.loads(jsonRaw5))dump(json.loads(jsonRaw6))
/*OUTPUT:
(map[string]interface {}) (len=5) { (string) (len=3) "abc": (float64) 123, (string) (len=3) "cde": (string) (len=3) "efg", (string) (len=3) "foo": (string) (len=10) "bar-123123", (string) (len=3) "azz": (map[string]interface {}) (len=3) {  (string) (len=4) "key1": (string) (len=7) "result2",  (string) (len=4) "key2": (float64) 123,  (string) (len=1) "e": ([]interface {}) (len=2 cap=2) {   (string) (len=3) "abc",   (float64) 111  } }, (string) (len=1) "d": ([]interface {}) (len=4 cap=4) {  (float64) 1,  (float64) 2,  (float64) 3,  (string) (len=3) "123" }}([]interface {}) (len=7 cap=8) { (float64) 1, (float64) 23, (float64) 4, (string) (len=3) "abc", (bool) true, (bool) false, (map[string]interface {}) (len=2) {  (string) (len=3) "abc": (float64) 123123,  (string) (len=4) "dddd": (string) (len=3) "123" }}(string) (len=9) "123123123"(float64) 123123(bool) false(interface {}) <nil>*/

#

a = ["123", true, false, "123123", 123, {"abc": 123},nil]println(json.dumps(a))// OUTPUT: ["123",true,false,"123123",123,{"abc":123},null]
a = {"abcccc": 123, "12": ["aaa", "123", {"a": 12, "arr": [123, true]}]}println(json.dumps(a))// OUTPUT: {"12":["aaa","123",{"a":12,"arr":[123,true]}],"abcccc":123}
a = falseprintln(json.dumps(a))// OUTPUT: false
a = "asdfasdfasdf\x00\x0a你好"println(json.dumps(a))// OUTPUT: "asdfasdfasdf\u0000\n你好"
a = nilprintln(json.dumps(a))// OUTPUT: null

#

JSON Path是一种用于从JSON格式的数据结构中提取特定数据的查询语言,类似于XPath。它提供了一种通用的方式来访问和操作JSON数据,可以用于编程语言或命令行中,以实现复杂的JSON数据处理和分析。

JSON Path使用一种类似于XPath的表达式语法,以匹配JSON对象的特定元素。例如,以下是一些简单的JSON Path表达式示例:

  1. $ :表示JSON对象的根元素
  2. $.name :表示根元素下的“name”属性值
  3. $..name :表示所有对象中的“name”属性值
  4. $.people[*].name :表示根元素下的“people”数组中所有对象的“name”属性值
  5. $.people[?(@.age > 18)].name :表示根元素下的“people”数组中年龄大于18岁的所有对象的“name”属性值

通过JSON Path表达式,可以轻松地从JSON数据结构中提取特定的数据,这在数据分析和数据处理方面非常有用。

#

提取数据是 Json Path 的典型用途之一,我们在进行后续的技术描述之前,应该大致对 Json Path 有一些深入的了解,下面是一份常见的 JSONPath支持的功能列表:

  1. 属性(property)操作符: $ 用于表示根节点, @ 用于表示当前节点。
  2. 属性访问操作符: . 用于访问属性, [ ] 用于访问数组或者属性。
  3. 筛选器(Filter)操作符: ?() 用于在表达式中进行筛选。
  4. Wildcard操作符: * 用于匹配任意字符, [*] 用于匹配任意数组元素。
  5. 支持通过下标访问数组元素,以及支持切片操作。
  6. 支持使用逻辑运算符 && || 进行条件筛选。
  7. 支持比较运算符 ==, !=, <, <=, >, >= 以及正则表达式运算符 =~ !~
  8. 支持聚合操作符 min , max , sum , avg , size 以及 reverse 等。

需要注意的是,不同的 JSONPath实现可能会略有差异,不完全一致。因此,在使用JSONPath时,需要查看具体实现的文档,以确保所使用的功能能够正确地实现。

#

例如,我们要提取一个 JSON 数据中的 name 字段,如下

待处理的 JSON
{    "name": "YaklangUser",    "criticalList": [        {"key": "a1", "name": "b1"},        {"key": "a1-3", "name": "b4"},        {"key": "a2", "value": "c3"},        {"key": "a2-3", "value": "c6", "age": 12},        {"key": "a5", "anothorList": [            {"key": "in", "age": 30},            {"key": "in3", "age": 88}        ], "age": 14},        {"key": "a6", "age": 19}    ]}

我们使用 json.Find() 函数来进行处理,代码为:

Yaklang 中的 JSONPath 接口:json.Find
jsonRaw = `{    "name": "YaklangUser",    "criticalList": [        {"key": "a1", "name": "b1"},        {"key": "a1-3", "name": "b4"},        {"key": "a2", "value": "c3"},        {"key": "a2-3", "value": "c6", "age": 12},        {"key": "a5", "anothorList": [            {"key": "in", "age": 30},            {"key": "in3", "age": 88}        ], "age": 14},        {"key": "a6", "age": 19}    ]}`
rootName = json.Find(jsonRaw, "$.name")printf("Fetch `name` in root node: %v\n", rootName)
/*OUTPUT:    Fetch `name` in root node: YaklangUser*/

#

上述代码我们仅需要把 json.Find 中的规则修改为 $..name ,即可完成

提取所有 name 字段

results = json.Find(jsonRaw, "$..name")dump(results)/*Output:
([]interface {}) (len=3 cap=4) { (string) (len=11) "YaklangUser", (string) (len=2) "b1", (string) (len=2) "b4"}*/

#

我们通过上述的操作,可以实现操作一个或者递归查找所有 JSON 中的对象,这个技能非常实用,能帮助我们快速提取数据。同时,我们还可以使用 Json Path 操作 JSON 中的数组。

我们仍然针对案例中的 JSON,如果要提取数组中的 name 或者直接操作节点,应该怎么操作呢?直观来说,我们使用 [ ] 来操作数组。

提取 criticalList 中第二个元素
jsonRaw = `{    "name": "YaklangUser",    "criticalList": [        {"key": "a1", "name": "b1"},        {"key": "a1-3", "name": "b4"},        {"key": "a2", "value": "c3"},        {"key": "a2-3", "value": "c6", "age": 12},        {"key": "a5", "anothorList": [            {"key": "in", "age": 30},            {"key": "in3", "age": 88}        ], "age": 14},        {"key": "a6", "age": 19}    ]}`
results = json.Find(jsonRaw, "$.criticalList[1]")dump(results)/*Output: