需要过滤值包含特定子字符串的所有键/值对

时间:2019-05-13 08:15:22

标签: json jq

我尝试为所有包含值“;从版本”的“描述”键筛选JSON文件,以打印其路径和该值中包含的版本。我用bash脚本来完成所有这些工作。

我要过滤的JSON来自API,并且在不同的路径上具有“ description”键。

这是服务器JSON的摘录

到目前为止,我使用curl来从服务器获取JSON并将其通过以下过滤器传递给jq,以获取包含所有路径的列表,这些路径的描述中包含该值:

curl $api | jq 'paths(objects and (.description|index("; Since version")))'

这将返回一个列表,其中包含指向包含搜索值的端点的路径,如下所示:

[
  "paths",
  "/v4/user/profileAttributes/{key}",
  "delete"
]
[
  "paths",
  "/v4/users/{user_id}/last_admin_rooms",
  "get"
]
[
  "definitions",
  "GeneralSettings",
  "properties",
  "s3TagsEnabled"
]

我发现这个filter会返回一个看似随机的键/值对“描述”的值,该值适用于我搜索的字符串而不是整个列表。不幸的是,由于作者没有在其帖子中解释它,所以我对整个过滤器并不十分了解。改编后

curl -s -N $api | jq '. as $in
| reduce paths(type == "string" and test("; Since version")) as $path ({};
    ($in|getpath($path)) as $x
    | if ($path[-1]|type) == "string"
      then .[$path[-1]] = $x
      else .[$path[-2]|tostring] += [$x]
      end )'

返回

{
  "description": "Some_Text_We_Dont_Care_About; Since version 4.10.2 Some_More_Text_We_Dont_Care_About"
}

如果第二个过滤器将返回所有条目而不是(接缝随机的)条目,我将能够将两个过滤后的响应缝合在一起。我在此处发布了这两个过滤器,因为也许有人知道如何以一种更简洁的方式进行过滤。

理想情况下,最终结果将返回包含以下条目的列表:

{
  "path": "
    [
    "paths",
    "/v4/users/{user_id}/last_admin_rooms",
    "get"
    ]"
  ",
  "version": {
    "description": "Some_Text_We_Dont_Care_About; Since version 4.10.2 Some_More_Text_We_Dont_Care_About"
  }
}

以下是摘录/示例输入内容:

{
  "info": {4 items},
  "host": "some_hostname",
  "basePath": "/api",
  "tags": [19 items],
  "paths": {
    "/v4/config/info/defaults": {
      "get": {
        "tags": [
          "config"
        ],
        "summary": "Get default values",
        "description": "SomeText; Since version 4.6.0 SomeMoreText",
        "operationId": "getSystemDefaultsInfo",
        "produces": [
          "application/json;charset=UTF-8"
        ],
      }
    }
    "/v4/config/info/general": {
      "get": {
        "tags": [
          "config"
        ],
        "summary": "Get general values",
        "description": "SomeText; Since version 4.6.0 SomeMoreText",
        "operationId": "getSystemDefaultsInfo",
        "produces": [
          "application/json;charset=UTF-8"
        ],
      }
    }
  "definitions": {
    "GeneralSettings": {
      "type": "object",
      "properties": {
        "cryptoEnabled": {
          "type": "boolean",
          "description": "Activation status of encryption"
        },
        "s3TagsEnabled": {
          "type": "boolean",
          "description": "Defines if S3 tags are enabled; Since version 4.9.0 NEW"
        },
        "sharePasswordSmsEnabled": {
          "type": "boolean",
          "description": "Allow sending of share passwords via SMS"
        }
      }
    }
  }
}

1 个答案:

答案 0 :(得分:1)

让我为您提供替代解决方案-使用基于步行路径的Unix实用程序 jtc

根据您想要的输出,使用jtc进行查询,

bash $ <file.json jtc -w'[description]:<.*; Since version.*>R: [-1] <act>k [-1] <path>k [-1] <pathname>k' -T'{ "path": [ {{pathname}}, {{path}}, {{act}}], "version": { "description": {{$0}}} }'
{
   "path": [
      "paths",
      "/v4/config/info/defaults",
      "get"
   ],
   "version": {
      "description": "SomeText; Since version 4.6.0 SomeMoreText"
   }
}
{
   "path": [
      "paths",
      "/v4/config/info/general",
      "get"
   ],
   "version": {
      "description": "SomeText; Since version 4.6.0 SomeMoreText"
   }
}
{
   "path": [
      "GeneralSettings",
      "properties",
      "s3TagsEnabled"
   ],
   "version": {
      "description": "Defines if S3 tags are enabled; Since version 4.9.0 NEW"
   }
}
bash $ 

鉴于您的Json是不规则的(不确定走description的要求),尽管您是否需要查看最后一个对象也不确定。如果您不需要它,那么知道JSON的结构后,就可以轻松地增强查询以排除像最后一个这样的假阳性匹配。

编辑: 说明:

-T选项提供了一个Json模板,该模板项(用双花括号{{..}}括起来)在每次遍历(-w)结束时从名称空间中插入成功了。

现在,行走路径(-w)是行走源JSON的方式:jtc让Json自由地上下行走(使用下标[..])并执行递归搜索<..>。尽管有些项目是directives-它们不进行任何搜索/匹配,但是它们应用了某些操作(此符号<..>S中的一个字母后缀定义了它是搜索还是指令)

让我在这里进行分解(顺便说一句,链接中描述了所有词素):

  • [description]:<.*; Since version.*>R:-对包含; Since version的JSON字符串执行RE搜索,但是由于RE拼写匹配整个这样的字符串(请注意RE表达式的开头和结尾处的.* )。现在,附加标签[description]:确保仅在具有附加标签的字符串中(而不是其他任何字符串)进行这种RE匹配。 lexeme(又称量词)末尾的:指示查找所有此类情况(搜索和下标中的量词均与Python表示法兼容)。
  • [-1]<act>k-[-1]寻址找到的条目的父节点(来自上一个步骤),<act>k在名称空间act中存储条目的标签(以供以后使用)模板插值)-搜索词素末尾的后缀定义是搜索还是指令(在这种情况下,k是提取标签并存储在名称空间中的指令)
  • 步行路径的重置是相同的:[-1]<path>k将寻址最后找到的条目的父项(在第一步中,该父项又是找到的条目的父项),并将其存储在名称空间中名称为path下的标签(键)(名称在jtc中是任意的)
  • [-1]<pathname>k'-做几乎相同的事情,然后遍历结束(嗯,对于给定的迭代-如果您记得第一个遍历lexeme是迭代的-它找到了每个出现的对象),然后应用了模板插值,从而得到打印的项目。

您可以轻松地处理查询(删除每个词位或添加您的词位,查看行走的方式)-我编辑了词位路径,用空格将每个词位打断。

PS>披露:我是jtc工具的创建者