首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在嵌套的JSON上使用jq递归,其中每个对象都有一个name属性?

如何在嵌套的JSON上使用jq递归,其中每个对象都有一个name属性?
EN

Stack Overflow用户
提问于 2017-05-12 20:36:07
回答 2查看 3.3K关注 0票数 2

我有一个嵌套的JSON对象,每个级别都有相同的属性键,每个级别的区别是一个名为name的属性。如果我想向下遍历到具有特定的name属性“路径”的级别,我将如何构造jq过滤器?

下面是一些表示文件系统目录结构的示例JSON数据:

代码语言:javascript
复制
{
  "subs": [
    {
      "name": "aaa",
      "subs": [
        {
          "name": "bbb",
          "subs": [
            {
              "name": "ccc",
              "subs": [
                {
                  "name": "ddd",
                  "payload": "xyz"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

什么是用于获取“路径”aaa/bbb/ccc/ddd中有效载荷值的jq过滤器?

先前的研究:

  1. jq - select objects with given key name --在JSON中查找包含指定名称的任何元素,而我正在寻找嵌套在一组具有特定名称的对象下的元素。
  2. http://arjanvandergaag.nl/blog/wrestling-json-with-jq.html --在第4节中很有帮助,它展示了如何提取具有具有特定值的属性name的对象。但是,执行的递归基于一组特定的已知属性名("values[].links.clone[]")。在我的例子中,我的等价物就是"subs[].subs[].subs[]“。
EN

回答 2

Stack Overflow用户

发布于 2017-05-12 21:38:04

以下是通用解决方案的基础:

代码语言:javascript
复制
def descend(name): .subs[] | select(.name == name);

因此,您的特定查询可以表述如下:

代码语言:javascript
复制
descend( "aaa") | descend( "bbb") | descend( "ccc") | descend( "ddd") | .payload

或者稍微好一点,仍然使用descend的上述定义

代码语言:javascript
复制
def path(array): 
  if (array|length)==0 then . 
  else descend(array[0]) | path(array[1:])
  end;

path( ["aaa", "bbb", "ccc", "ddd"] ) | .payload

TCO

上面对path/1的递归定义非常简单,但是不适合非常深嵌套的数据结构,例如,如果深度大于1000。下面是利用jq的尾叫优化的另一个定义,因此它运行得非常快:

代码语言:javascript
复制
def atpath(array):
  [array, .] 
  |  until( .[0] == []; .[0] as $a | .[1] | descend($a[0]) | [$a[1:], . ] )
  | .[1];

.aaa.bbb.ccc.ddd

如果您想要能够使用.aaa.bbb.ccc.ddd表示法,一种方法是首先将数据“扁平化”:

代码语言:javascript
复制
def flat:
  { (.name): (if .subs then (.subs[] | flat) else .payload end) };

由于顶层元素没有"name“标记,所以查询将是:

代码语言:javascript
复制
.subs[] | flat | .aaa.bbb.ccc.ddd

下面是一种更有效的方法,再次使用上面定义的descend

代码语言:javascript
复制
def payload(p):
  def get($array):
    if $array == []
    then .payload
    else descend($array[0]) | get($array[1:]) end;
  get( null | path(p) );

payload( .aaa.bbb.ccc.ddd )
票数 3
EN

Stack Overflow用户

发布于 2017-05-12 20:36:07

以下jq命令中的筛选器递归到具有name属性的对象的“路径”,这些对象对应于“路径”aaa/bbb/ccc/ddd:

代码语言:javascript
复制
jq '.subs[] | select(.name = "aaa") | .subs[] | select(.name = "bbb") | .subs[] | select(.name = "ccc") | .subs[] | .payload'

这里是在qplay.org上直播的:

https://jqplay.org/s/tblW7UX0Si

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43946092

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档