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

jq - apply a filter on multiple levels

我有一个 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"} 但是这个过滤器应该递归地应用于任何级别的任何元素。

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

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"
  }
}

如果您的 jq 有 walk,您可以按如下方式使用它,如果没有,您可以轻松地 google 它的 def 并通过剪切和粘贴来包含它:

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

扩展@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"
}