jq - 在多个级别上应用过滤器

Posted

技术标签:

【中文标题】jq - 在多个级别上应用过滤器【英文标题】:jq - apply a filter on multiple levels 【发布时间】:2015-05-13 10:36:17 【问题描述】:

我有一个这样的 json 文件


    "log": 
            "version": 
                    "$t": "1.1"
            ,
            "creator": 
                    "name": 
                            "$t": "Internet Explorer Network Inspector"
                    ,
                    "version": 
                            "$t": "10.0.9200.17229"
                    
            

我需要将文件展平,以便它可以读取


    "log": 
            "version": "1.1",
            "creator": 
                    "name": "Internet Explorer Network Inspector",
                    "version": "10.0.9200.17229"
            

我知道过滤器 "version": .version ."$t" 将单个元素 "version": "$t": "10.0.9200.17229" 减少到 "version": "10.0.9200.17229",但是这个过滤器应该递归地应用于任何级别的任何元素。

【问题讨论】:

【参考方案1】:

您可以通过定义新函数来创建递归过滤器:

def untag: (objects | ."$t")
    // (objects | with_entries(.value |= untag))
    // (arrays | map(untag))
    // .
    ;
untag

所以给定这样的输入:


  "log": 
    "version": 
      "$t": "1.1"
    ,
    "creator": 
      "name": 
        "$t": "Internet Explorer Network Inspector"
      ,
      "version": 
        "$t": "10.0.9200.17229"
      
    
  

你会回来的:


  "log": 
    "creator": 
      "name": "Internet Explorer Network Inspector",
      "version": "10.0.9200.17229"
    ,
    "version": "1.1"
  

【讨论】:

所以解释一下。我们定义了一个函数untag,它选择作为对象的输入,如果它们有$t,则提取值否则使用来自untag的值更新对象的值(这是递归部分)。最后,如果我们没有任何$t,该函数将返回输入本身。 如果你有数组,我已经添加了一些来处理数组。并且不需要对 $t 属性的初始检查。我以为它会抛出一个错误,但它不会。 谢谢杰夫,我正在编辑答案以添加数组处理。希望我注意到 *** 顶部栏上的红色警报;-) 这样做的原因是将 IE 中的 NetworkData.xml 转换为 HAR 格式。我发现xml2json 的第一个 XML > JSON 工具非常冗长,因此我需要将结果展平。确实还有一步,将pageentries中的对象转换为普通数组,但这应该很简单...... untag 函数放在哪里?它是如何从命令行调用的?我正在尝试使用 some_command | xml2json | jquntag 进行类似的操作。 @jwfearn 只需调用它。 ... | jq 'untag'【参考方案2】:

如果你的jq有walk,你可以如下使用它,如果没有,你可以很容易地google它的def并通过剪切和粘贴的方式包含它:

walk( if type=="object" and has("$t")
      then .["$t"] else . end )

【讨论】:

【参考方案3】:

扩展 @JeffMercado 的出色回答:

问题

您有一些生成 JSON 的命令,其中字符串值表示如下

"some key": "$t": "some string value"

并且您希望将其转换为如下所示:

"some key": "some string value"

解决方案

把它放在你的~/.jq 文件中:

def untag: (objects | ."$t")
  // (objects | with_entries(.value |= untag))
  // (arrays | map(untag))
  // .
  ;

像这样使用它:

some_command | jq untag

例子:

$ echo '"some key": "$t": "some string value"' | jq

  "some key": 
    "$t": "some string value"
  


$ echo '"some key": "$t": "some string value"' | jq untag

  "some key": "some string value"

【讨论】:

以上是关于jq - 在多个级别上应用过滤器的主要内容,如果未能解决你的问题,请参考以下文章

如何在弹性搜索的过滤器聚合中引用多个嵌套级别?

logback:两个appender,多个logger,不同级别

如何在 dstore 上应用多个过滤器?

Sharepoint 2010列表视图阈值和项级别权限

跨多个 Web 应用程序的服务器范围功能

如何过滤父子数组的多个属性,这些属性可能是几个树级别的深度