0

概括

我有一个有效的jq过滤器,它可以正确解析三个不同的名称有效负载对象,并将它们按摩成所需的输出格式。问题是我必须明确表达每个对象路径,因为我无法找到一种方法来表达对象标识符中的交替。

我希望过滤器更加灵活,以便它可以显示从containers下到任何标题以 . 开头的包管理器的数据结构Packages。不过,我需要整个结构,而不仅仅是终端节点。

认为我需要的是用交替或通配符来表达我的对象标识符,例如:

  • .capabilities.*.payload?
  • .capabilities.([apk, dpkg, rpm]).payload?

我意识到以上都不是有效的 jq 语法,这就是问题的原因。我在下面包含了一个带有有效 JSON 的测试语料库,我当前的 jq 过滤器列在下面的部分中。

最小的 JSON 文件

这是我的测试语料库,在当前目录中存储为minimum.json 。

{
  "containers": {
    "3dc76c82e566a116e5b64bc91a0b6220c71db7052f68317ebbe90521db55bf36": {
      "container_name": "/apache-46869",
      "capabilities": {
        "apk": {
          "title": "Packages (APK)"
        },
        "dpkg": {
          "title": "Packages (DPKG)",
          "payload": {
            "apt": "1.0.9.8.4",
            "libnghttp2-14": "1.18.1-1"
          }
        },
        "rpm": {
          "title": "Packages (RPM)"
        }
      }
    },
    "474047a1fe238e39fa1917aff0c93154624bbf159d321d49d5e685302589ab51": {
      "container_name": "/nginx-alpine-46869",
      "capabilities": {
        "apk": {
          "title": "Packages (APK)",
          "payload": {
            ".nginx-rundeps": "0",
            "apk-tools": "2.6.8-r2"
          }
        },
        "dpkg": {
          "title": "Packages (DPKG)"
        },
        "rpm": {
          "title": "Packages (RPM)"
        }
      }
    },
    "d7dcd90791240d78022941cf054a6b474f5329acd79aa15b58dc342f95a8ce33": {
      "container_name": "/apache-alpine-46869",
      "capabilities": {
        "apk": {
          "title": "Packages (APK)",
          "payload": {
            ".httpd-rundeps": "0",
            "apk-tools": "2.6.8-r2",
            "apr": "1.5.2-r1",
            "apr-util": "1.5.4-r2"
          }
        },
        "dpkg": {
          "title": "Packages (DPKG)"
        },
        "rpm": {
          "title": "Packages (RPM)"
        }
      }
    }
  }
}

显式 jq 过滤器

这是我当前的过滤器,它有效但明确定义了每个可选对象 indentifier-index

jq '
    [ .containers[] | { 
        name: .container_name, package_inventory: {
            apk: .capabilities.apk.payload?,
            dpkg: .capabilities.dpkg.payload?,
            rpm: .capabilities.rpm.payload?
        }   
    }]  
' minimal.json

预期产出

我当前的输出(如下所示)是正确的。目标不是修复输出,而是使过滤器更灵活。

[
  {
    "name": "/apache-46869",
    "package_inventory": {
      "apk": null,
      "dpkg": {
        "apt": "1.0.9.8.4",
        "libnghttp2-14": "1.18.1-1"
      },
      "rpm": null
    }
  },
  {
    "name": "/nginx-alpine-46869",
    "package_inventory": {
      "apk": {
        ".nginx-rundeps": "0",
        "apk-tools": "2.6.8-r2"
      },
      "dpkg": null,
      "rpm": null
    }
  },
  {
    "name": "/apache-alpine-46869",
    "package_inventory": {
      "apk": {
        ".httpd-rundeps": "0",
        "apk-tools": "2.6.8-r2",
        "apr": "1.5.2-r1",
        "apr-util": "1.5.4-r2"
      },
      "dpkg": null,
      "rpm": null
    }
  }
]
4

2 回答 2

1

诀窍是定义一个辅助函数。例如,如果你写:

def payloads(keys): . as $in
  | reduce keys[] as $key ({}; .[$key] = ($in|.[$key].payload?) );

那么您的查询变为:

.containers[] | { 
    name: .container_name,
    package_inventory: (.capabilities | payloads( ["apk","dpkg","rpm"] ))
}

当然,其他变体也是可能的。例如,您可以定义payloads为 arity-2 函数,从而传入“功能”。

使用 JSON 对象指定键

这是payloads/1说明(a)如何避免的变体reduce,以及(b)如何通过将 JSON 对象作为模板来指定键:

def payloads_at(object):
  . as $in
  | object as $object
  | ({}
     | [($object|keys_unsorted[]) as $key
        | .[$key] = ($in|.[$key].payload?) ])
  | add;

这可以这样调用:payloads_at( {apk, dpkg, rpm} ),或者如果您希望动态确定密钥:

(.capabilities | payloads_at( . ) )
于 2017-05-06T17:17:08.433 回答
0

此辅助函数可能更接近您正在寻找的内容:

def star(pre; template; post):
  pre as $object
  | ({} | [($object|template|keys_unsorted[]) as $key | .[$key] = ($object | .[$key] | post) ])
  | add;

用法

显式键名列表:

star(.capabilities; {apk,dpkg,rpm}; .payload)

.capabilities 的关键:

star(.capabilities; .; .payload)

例子:

.containers[] | { 
    name: .container_name,
    package_inventory: star(.capabilities; .; .payload)
}
于 2017-05-06T19:46:50.493 回答