【问题标题】:How to transform json tree recursively with jq?如何用jq递归转换json树?
【发布时间】:2020-11-11 13:44:31
【问题描述】:

我有以下需要用 jq 转换的 JSON。主要任务是在树中只保留指定的属性。树中的层数可能不同。

    {
    "metaModel": [ {
        "clazz": "AttributeClass1",
        "code": "code1",
        "default": "value1",
        "children": [ {
            "clazz": "AttributeClass2",
            "code": "code21",
            "default": "value21"
        },
        {
            "clazz": "AttributeClass1",
            "code": "code22",
            "default": "value22",
            "children": [ {
                "clazz": "AttributeClass1",
                "code": "code31",
                "default": "value31",
                "children": []
            }
            ]
        }
        ]
    },
    {
        "clazz": "AttributeClass2",
        "code": "code2",
        "default": "value2"
    }
    ]
}

是否有可能得到如下输出(只留下 clazz、code、children)?

    {
        "clazz": "AttributeClass1",
        "code": "code1",
        "children": [ {
            "clazz": "AttributeClass2",
            "code": "code21"
        },
        {
            "clazz": "AttributeClass1",
            "code": "code22",
            "children": [ {
                "clazz": "AttributeClass1",
                "code": "code31",
                "children": []
            }
            ]
        }
        ]
    },
    {
        "clazz": "AttributeClass2",
        "code": "code2"
    }

'metaModel' 也可能留在输出中。

【问题讨论】:

    标签: json recursion tree jq


    【解决方案1】:

    使用walk/1

    .metaModel
    | walk( if type == "object" and has("clazz")
            then {clazz, code} + (if .children then { children } else null end )
            else .
            end )
    

    【讨论】:

      【解决方案2】:

      下面的递归函数似乎满足要求,或者至少过滤器.metaModel | transform按照样本输出对样本输入进行变换:

      def transform:
        if type == "object" and has("clazz")
        then  {clazz, code} + (if has("children") then {children: (.children|transform)} else null end)
        elif type == "array" then map(transform)
        else .
        end;
      

      脚注

      如果你不喜欢表达式的冗余

      {children: (.children|transform)}
      

      你可以写:

      {children} | map_values(transform)
      

      【讨论】:

        【解决方案3】:

        这是一种使用tostreamsetpathreduce的方法:

        reduce (tostream|select(.[0][-1]|.=="clazz" or .=="code" or .=="children")) as [$p,$v] (
          {}; setpath($p;$v)
        )
        

        Try it online!

        tostream 将您的输入转换为“流”[path,value] 形式:

        [["metaModel",0,"children",0,"clazz"],"AttributeClass2"]
        [["metaModel",0,"children",0,"code"],"code21"]
        [["metaModel",0,"children",0,"default"],"value21"]
        [["metaModel",0,"children",0,"default"]]
        [["metaModel",0,"children",1,"children",0,"children"],[]]
        [["metaModel",0,"children",1,"children",0,"clazz"],"AttributeClass1"]
        [["metaModel",0,"children",1,"children",0,"code"],"code31"]
        [["metaModel",0,"children",1,"children",0,"default"],"value31"]
        [["metaModel",0,"children",1,"children",0,"default"]]
        [["metaModel",0,"children",1,"children",0]]
        [["metaModel",0,"children",1,"clazz"],"AttributeClass1"]
        [["metaModel",0,"children",1,"code"],"code22"]
        [["metaModel",0,"children",1,"default"],"value22"]
        [["metaModel",0,"children",1,"default"]]
        [["metaModel",0,"children",1]]
        [["metaModel",0,"clazz"],"AttributeClass1"]
        [["metaModel",0,"code"],"code1"]
        [["metaModel",0,"default"],"value1"]
        [["metaModel",0,"default"]]
        [["metaModel",1,"clazz"],"AttributeClass2"]
        [["metaModel",1,"code"],"code2"]
        [["metaModel",1,"default"],"value2"]
        [["metaModel",1,"default"]]
        [["metaModel",1]]
        [["metaModel"]]
        

        select 过滤掉所有不以“clazz”、“code”或“children”结尾的路径:

        [["metaModel",0,"children",0,"clazz"],"AttributeClass2"]
        [["metaModel",0,"children",0,"code"],"code21"]
        [["metaModel",0,"children",1,"children",0,"children"],[]]
        [["metaModel",0,"children",1,"children",0,"clazz"],"AttributeClass1"]
        [["metaModel",0,"children",1,"children",0,"code"],"code31"]
        [["metaModel",0,"children",1,"clazz"],"AttributeClass1"]
        [["metaModel",0,"children",1,"code"],"code22"]
        [["metaModel",0,"clazz"],"AttributeClass1"]
        [["metaModel",0,"code"],"code1"]
        [["metaModel",1,"clazz"],"AttributeClass2"]
        [["metaModel",1,"code"],"code2"]
        

        reduce 和 setpath 重构最终结果:

        {
          "metaModel": [
            {
              "children": [
                {
                  "clazz": "AttributeClass2",
                  "code": "code21"
                },
                {
                  "children": [
                    {
                      "children": [],
                      "clazz": "AttributeClass1",
                      "code": "code31"
                    }
                  ],
                  "clazz": "AttributeClass1",
                  "code": "code22"
                }
              ],
              "clazz": "AttributeClass1",
              "code": "code1"
            },
            {
              "clazz": "AttributeClass2",
              "code": "code2"
            }
          ]
        }
        

        【讨论】:

          猜你喜欢
          • 2020-08-04
          • 2023-01-23
          • 1970-01-01
          • 2017-03-26
          • 1970-01-01
          • 2017-08-23
          • 1970-01-01
          • 2020-06-05
          • 1970-01-01
          相关资源
          最近更新 更多