之前的文章使用jq处理JSON数据(一)中,我分享了​jq​​工具的基本用法。今天开始分享​jq​​的高阶使用,包括管道符、函数以及格式换。

管道符和函数

在这个章节中中,将分享​​jq​​更多过滤​​JSON​​数据的方法。

使用​​|​​运算符,我们可以结合两个过滤器。它的工作原理与​​Unix​​系统管道符类似。左边的过滤器的输出传递到右边的过滤器。

请注意:​​.name.first​​与​​.name | .first​​使用结果是完全相同的,就将​​JSON​​数据中​​.name​​节点数据传递到第二个过滤器,然后选择​​.first​​。

管道可以跟其他功能组合。例如,我们可以使用​​keys​​函数来获取​​JSON​​数据某个节点的键集合:

✘ fv@FunTester  ~/Downloads  cat FunTester.json  | jq '. | keys'
[
"article",
"name"
]
fv@FunTester  ~/Downloads 
复制代码

使用​​length​​函数,我们可以获得数组中元素的数量长度:

fv@FunTester  ~/Downloads  cat FunTester.json  | jq '. | keys | length'
2
复制代码

​length​​函数的输出取决于输入元素:


  • 如果传递了字符串,则返回字符​​length​
  • 对于数组,返回元素个数​​length​​或者​​size​
  • 对于对象,返回键-值对的​​size​

我们还可以将​​length​​函数跟运算符组合使用:

fv@FunTester  ~/Downloads  cat FunTester.json  | jq '. | keys | length > 1'
true
复制代码

还有一个更厉害的筛选函数​​select​​,有点​​MySQL​​数据库的意味。

✘ fv@FunTester  ~/Downloads  cat FunTester.json | jq '.article[] | select (.author == "tester2")'
{
"author": "tester2",
"title": "performanceTest"
}
复制代码

​select​​函数后面跟的​​boolean​​表达式还可以是其他很多种形式,这里不再意义演示。

转换格式

这个章节,我将分享一些使用​​jq​​将原来​​JSON​​数据组合换其他格式的技巧。

先来拼接一个简单的​​JSON​​格式数据:

fv@FunTester  ~/Downloads  cat FunTester.json | jq  '{(.article[0].title): "FunTester"}'
{
"ApiTest": "FunTester"
}
复制代码

这个例子中,首先我创建了一个只有一对键值对的​​JSON​​对象,其中​​key​​是从原来数据中取到的,表达式为​​(.article[0].title)​​,这个在上一篇文章中已经讲过了,这里不多说。​​value​​我直接赋值为​​FunTester​​。

请注意,​​jq​​表达式中,要想构建新的​​JSON​​格式数据,如果​​key​​为表达式时,需要用​​()​​括起来,但是​​value​​是表达式的时候就不用了,仅限于单表达式,下面会介绍一些复合表达式不适用。下面这个例子演示​​value​​的值是表达式的时候。

fv@FunTester  ~/Downloads  cat FunTester.json | jq  '{(.article[0].title): .article}'
{
"ApiTest": [
{
"author": "tester1",
"title": "ApiTest"
},
{
"author": "tester2",
"title": "performanceTest"
}
]
}
复制代码

下面介绍一下​​map​​函数,​​map​​函数用于通过提取某个节点下的某个​​value​​值集合来组成新的数组。

✘ fv@FunTester  ~/Downloads  cat FunTester.json | jq  '{(.article[0].title): (.article | map(.title))}'
{
"ApiTest": [
"ApiTest",
"performanceTest"
]
}
复制代码

我们再通过一个实验来探索一下​​map​​函数的用法:

fv@FunTester  ~/Downloads  cat FunTester.json | jq  '{(.article[0].title): (.article | map("FunTester1","FunTester2"))}'
{
"ApiTest": [
"FunTester1",
"FunTester2",
"FunTester1",
"FunTester2"
]
}
复制代码

这里我将​​map​​函数中的参数写成了两个常量,最终的输出结果是两遍的常量,所以​​map​​函数执行了两遍,是跟前面的数组的长度一致的,而且没有去重功能。

接下来分享另外一个函数​​join​​,这个跟​​Java​​中拼接字符串的​​StringUtils.join()​​非常相似。下面是​​Java​​用的使用​​Demo​​。

public static String join(String text, String separator) {
return StringUtils.join(ArrayUtils.toObject(text.toCharArray()), separator);
}
复制代码

下面是​​jq​​中​​join​​函数的使用:

fv@FunTester  ~/Downloads  cat FunTester.json | jq  '{(.article[0].title): (.article | map("FunTester1","FunTester2") | join("-"))}'
{
"ApiTest": "FunTester1-FunTester2-FunTester1-FunTester2"
}
复制代码

我用连接符,将刚才使用​​map​​函数构建的数组连接起来。