【问题标题】:Extract schema of nested JSON object提取嵌套 JSON 对象的模式
【发布时间】:2017-09-08 20:00:37
【问题描述】:

假设这是源 json 文件:

{    
    "name": "tom",
    "age": 12,
    "visits": {
        "2017-01-25": 3,
        "2016-07-26": 4,
        "2016-01-24": 1
    }
}

我想得到:

[
  "age",
  "name",
  "visits.2017-01-25",
  "visits.2016-07-26",
  "visits.2016-01-24"
]

我可以使用jq '. | keys' file.json 提取密钥,但这会跳过嵌套字段。如何包含这些?

【问题讨论】:

    标签: json nested key jq


    【解决方案1】:

    前段时间,我写了一个结构模式推理引擎, 生成反映所考虑的 JSON 文档的简单结构模式, 例如对于此处给出的示例 JSON,推断的架构是:

    {
      "name": "string",
      "age": "number",
      "visits": {
        "2017-01-25": "number",
        "2016-07-26": "number",
        "2016-01-24": "number"
      }
    }
    

    这不完全是原始帖子中要求的格式,但是 对于大型对象集合,它确实提供了有用的概述。

    更重要的是,现在有一个补充验证器 检查 JSON 文档的集合是否与结构匹配 架构。验证器检查写入的模式 JESS(JSON 扩展结构模式),简单的超集 由模式推理引擎生成的结构模式 (SSS)。

    (这个想法是可以使用 SSS 作为起点添加 更精细的约束,包括递归约束, 文档内参照完整性约束等)

    作为参考,这里是您的 sample.json 的 SSS 之一 将使用"schema" module:

    jq 'include "schema"; schema' source.json > source.schema.json
    

    并针对 SSS 或 ESS 验证 source.json:

    JESS --schema  source.schema.json  source.json
    

    【讨论】:

      【解决方案2】:

      根据您的输入,调用:

      jq 'leaf_paths | join(".")'
      

      产生:

      "name"
      "age"
      "visits.2017-01-25"
      "visits.2016-07-26"
      "visits.2016-01-24"
      

      如果您想包含“访问”,请使用paths。如果您希望结果为 JSON 数组,请用方括号将过滤器括起来:[ ... ]

      如果您的输入可能包含数组,那么除非您使用 jq 1.6 或更高版本,否则您需要将整数索引显式转换为字符串;此外,由于 leaf_paths 现在已弃用,您可能需要使用它的 def。结果:

      jq 'paths(scalars) | map(tostring) | join(".")'
      

      所有路径

      要包含 null 的路径,您可以使用 allpaths 定义如下:

      def allpaths:
        def conditional_recurse(f):  def r: ., (select(.!=null) | f | r); r;
        path(conditional_recurse(.[]?)) | select(length > 0);
      

      例子:

      {"a": null, "b": false} | allpaths | join(".")
      

      产生:

      "a"
      "b"
      

      all_leaf_paths

      假设 jq 版本为 1.5 或更高,我们可以按照 builtins.jq 中使用的策略,即添加这些定义来获取all_leaf_paths

      def allpaths(f):
        . as $in | allpaths | select(. as $p|$in|getpath($p)|f);
      
      def isscalar:
        . == null or . == true or . == false or type == "number" or type == "string";
      
      def all_leaf_paths: allpaths(isscalar);
      

      例子:

      {"a": null, "b": false, "object":{"x":0} } | all_leaf_paths | join(".")
      

      产生:

      "a"
      "b"
      "object.x"
      

      【讨论】:

      • 我认识到,两者(pathleaf_paths)都会忽略具有nullfalse 之类的值的字段。知道如何包含这些吗?
      • 您的“所有路径”编辑看起来很有希望,但遗憾的是,这个编辑似乎没有按预期工作。它实际上输出了完整的文件,包括属性的值。
      • 在了解我只需将您的自定义函数定义添加到 ~/.jq 文件之后,这一切都像一个魅力。很想给你第二次投票!
      • 您不必将函数添加到 ~/.jq ——例如,您可以简单地将它们包含在您使用命令行上的 -f 选项指定的任何文件中。感谢您的虚拟第二次投票。
      【解决方案3】:

      这是你想要的,但它不会返回数组中的数据,但它应该是一个简单的修改:

      https://github.com/ilyash/show-struct

      您还可以查看此页面: https://ilya-sher.org/2016/05/11/most-jq-you-will-ever-need/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-08
        • 2021-03-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多