【问题标题】:select within either array or object在数组或对象中选择
【发布时间】:2020-01-27 01:55:32
【问题描述】:

鉴于这三个文件...

一个带有 Statement 对象的:

{
    "PolicyVersion": {
        "CreateDate": "2017-07-13T18:59:21Z", 
        "VersionId": "v2", 
        "Document": {
            "Version": "2012-10-17", 
            "Statement": {
                "Action": "*", 
                "Resource": "*", 
                "Effect": "Allow"
            }
        }, 
        "IsDefaultVersion": true
    }
}

...还有一个带有 Statement 数组的:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

...还有一个语句嵌套在完整文档中:

{
    "PolicyVersion": {
        "CreateDate": "2017-07-13T18:59:21Z", 
        "VersionId": "v2", 
        "Document": {
            "Version": "2012-10-17", 
            "Statement": [
                {
                    "Action": "*", 
                    "Resource": "*", 
                    "Effect": "Allow"
                }
            ]
        }, 
        "IsDefaultVersion": true
    }
}

.Action == '*'.Resource == '*' 存在于语句中时,是否可以有一个命令来选择,无论它是一个数组,一个对象,以及它的嵌套位置?

例如,我正在扫描数千个文档,其中唯一的区别是 Statement 可能是一个对象或一个数组。

当然是这样的:jq '.PolicyVersion.Document.Statement[] | select((.Action == "*") and .Resource == "*") 适用于数组,jq '.PolicyVersion.Document.Statement | select((.Action == "*") and .Resource == "*") 适用于它不是数组但我想在一个命令中实现这一点。

我在select 周围尝试了一些方法,例如:

jq '.PolicyVersion.Document | select((.Statement[] | select((.Action == "*") and .Resource == "*") or select((.Statement[] | select((.Action == "*") and .Resource == "*")'

什么都不返回,并且:

jq '.PolicyVersion.Document | select((.Statement[] | select((.Action == "*") and .Resource == "*") or select((.Statement | select((.Action == "*") and .Resource == "*")'

返回一个 unix shell 引用错误。

【问题讨论】:

  • 供您参考,可以使用 alternative unix walk-path 实用程序 jtc 来实现相同的 JSON 查询: <file.json jtc -w'<Statement>l[Action]:<*>[-1][Resource]:<*>[^0]'。如果您愿意,我可以在单独的答案中详细说明工具的使用(PS。我是该工具的开发人员)。
  • 感谢您传播知识,@Dmitry :) 始终欣赏替代方案并学习不同的方式。
  • 顺便说一句,在上面的例子中,整个文档被选中(我可能误解了这个问题),在下面的答案中,我将详细说明如何只选择Statement 中包含Action的记录和Resource,如果两者都是"*"。让我知道这个问题是否意味着不同。
  • 我还发现了一个使用 jmespath 的 lambda 函数,它使用以下方法实现它:if jmespath.search('PolicyVersion.Document.Statement[?Effect == \'Allow\' && contains(Resource, \'*\') && contains (Action, \'*\')]', policy_version): 认为我会在这里分享另一种可能的方法/解决方案。

标签: json types filtering jq jtc


【解决方案1】:

以下内容可能比您需要的更通用,或者可能过于通用,因此请随意调味:

..
| objects
| select(.Statement)
| .Statement
| if type == "array" then .[] else . end
| select(.Action == "*" and .Resource == "*")

【讨论】:

  • 太棒了,谢谢!适用于迄今为止我能想到/见过的所有用例(我在最终 OP 中包含的三个)。如果可以的话,你介意分解它是如何工作的吗?再次感谢:)
【解决方案2】:

另一种针对这种特殊情况的方法:

.PolicyVersion.Document.Statement
| ..
| select(type == "object" and .Action == "*" and .Resource == "*")

【讨论】:

  • 确实有效,谢谢。在我完成添加我的用例示例之前,我已经更新了我的问题。可能是另一个问题,但如果 Statement 位于文档根目录并且也没有嵌套,我希望它也能正常工作。
  • @TryTryAgain 请参考 peak 的回答
【解决方案3】:

在获得 OP 许可的情况下,让我在这里展示如何使用 walk-path unix 实用程序 jtc 实现相同的 JSON 查询。但是,我不会解释步行路径,而是展示如何构建它。

我对这个问题的理解:验证 JSON 文档,以便如果文档中有任何带有标签 Statement 的条目包含元素 "Action": "*""Resource": "*",然后打印包含这些元素的整个记录​​,否则不要't(即留空输出)

1。让我们从递归查找带有标签 Statement 的 JSON 条目开始(递归搜索的符号是 <..>,后缀 l 指示仅搜索 标签),因此它可以位于JSON 文档(我将使用第一个 JSON 示例):

bash $ <file.json jtc -w'<Statement>l'
[
   {
      "Action": "*",
      "Effect": "Allow",
      "Resource": "*"
   }
]
bash $ 

2。一旦找到Statement 记录,我们需要查看在找到的条目附加 到标签"Action" 的某处是否有记录"*"(使用递归搜索再次但将搜索限制为仅具有 Action 标签的条目 - 也称为 范围搜索):

bash $ <file.json jtc -w'<Statement>l[Action]:<*>'
"*"
bash $ 

3。现在我们需要查看找到的条目是否有兄弟姐妹 ("Resource": "*")。为此,让我们在 JSON 树中更上一层楼(也就是父级地址):

bash $ <file.json jtc -w'<Statement>l[Action]:<*>[-1]'
{
   "Action": "*",
   "Effect": "Allow",
   "Resource": "*"
}
bash $

然后使用非递归范围搜索(非递归搜索符号是&gt;..&lt;):

bash $ <file.json jtc -w'<Statement>l[Action]:<*>[-1][Resource]:>*<'
"*"
bash $ 

4。最后,为了选择记录,让我们再次寻址最后找到/遍历的条目的父项:

bash $ <file.json jtc -w'<Statement>l[Action]:<*>[-1][Resource]:>*<[-1]'
{
   "Action": "*",
   "Effect": "Allow",
   "Resource": "*"
}
bash $ 

上述 walk-path 将有助于对所有 JSON 文档进行所需的 JSON 查询(​​无论 Statement 是否嵌套,或者 ActionResource 记录是否(深度)在数组与否 - 但他们必须保持兄弟姐妹)。
如果任何 walk lexemes 失败,则整个输出将为空白:

bash $ <file.json jtc -w'<Statement>l[Action]:<blah>[-1][Resource]:>*<[-1]' 
bash $ 

最后,jtc 从文件读取时要快几倍(而不是 stdin),出于性能原因,最好使用它作为参数传递文件:

jtc -w'<Statement>l[Action]:<*>[-1][Resource]:>*<[-1]' file.json 

PS>我是用于 JSON 处理的 jtc unix 实用程序的创建者

【讨论】:

    猜你喜欢
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-08-11
    相关资源
    最近更新 更多