递归转换JSON并使用jq添加数据

uqzxnwby  于 2023-10-21  发布在  其他
关注(0)|答案(1)|浏览(112)

我想使用jq递归转换任意JSON文件:

输入

{
  "id": 123456,
  "name": "Test",
  "more": [1, 2, 3],
  "instance": {
    "id": 987654,
    "name": "Different"
  }
}

输出

[
  {
    "name" : "id",
    "type": "number",
    "value": 123456
  },
  {
    "name": "name",
    "type": "string",
    "value": "Test"
  },
  {
    "name":"more",
    "type": "array",
    "value": [1, 2, 3]
  },
  {
    "name": "instance",
    "type": "object",
    "value": [
      {
        "name": "id",
        "type": "number",
        "value": 987654
      },
      {
        "name": "name",
        "type": "string",
        "value": "Different"
      }
    ]
  }  
]

转换说明

每个键值对都应该转换为一个包含键name, type, value的对象。而name应该是原始的 keytype应该是jq的type运算符感知到的原始值的 type。由于键值对被转换为复杂对象,因此同一层次结构上的键值对成为同一数组的一部分。
这可以通过jq实现吗?

sz81bmfz

sz81bmfz1#

您的需求几乎符合to_entries正在做的事情。但是你需要在一个自顶向下的递归中向下传递类型(因为使用自底向上的方法,比如using walk,在之后确定类型时,预先被to_entries转换为数组的对象变得与正确的数组无法区分)。因此,递归函数可以设置类型和值,如果值是一个对象,使用to_entries并在递归结果前添加名称:

def f: {
  type: type,
  value: (objects |= (to_entries | map({name: .key} + (.value | f))))
};
f.value
[
  {
    "name": "id",
    "type": "number",
    "value": 123456
  },
  {
    "name": "name",
    "type": "string",
    "value": "Test"
  },
  {
    "name": "more",
    "type": "array",
    "value": [
      1,
      2,
      3
    ]
  },
  {
    "name": "instance",
    "type": "object",
    "value": [
      {
        "name": "id",
        "type": "number",
        "value": 987654
      },
      {
        "name": "name",
        "type": "string",
        "value": "Different"
      }
    ]
  }
]

Demo
关于你的评论数组应该“保持不变”的注解:虽然这澄清了数组不应该被转换(例如,使用数字索引作为它们的项的“名称”),仍然不清楚是否希望再次作为对象本身的数组项也被转换(同时留在未转换的数组中)。例如,将示例中的[1, 2, 3]更改为[1, {"x":2}, 3]。上面假设这个数组应该按原样复制(Demo)。然而,如果你想把递归也向下传播到数组项中,也要更新数组(在对象之前,不要遇到自底向上的问题),例如。使用arrays |= map(f.value) | objects |= …Demo),对于改变的示例,这将产生[1, [{"name": "x", "type": "number", "value": 2}], 3]

相关问题