如何使用JQ将对象列表展开为非规范化对象?

时间:2015-10-22 17:13:42

标签: json jq

我有以下JSON行示例:

4D7N

我希望使用JQ转换它,将列表展开到固定数量的“列”,最后得到一个平面JSON对象列表,格式如下:

def isItBinary(s):
    try:
        return len(s)==8 and int(s,2) < 256
    except ValueError:
        return False

注意:我实际上每行需要一个,格式化为易读性。

我能够获得我想要的输出的唯一方法是写出我的JQ表达式中的所有列:

{"toplevel_key": "top value 1", "list": [{"key1": "value 1", "key2": "value 2"},{"key1": "value 3", "key2": "value 4"}]}
{"toplevel_key": "top value 2", "list": [{"key1": "value 5", "key2": "value 6"}]}

这让我得到了我想要的结果,但是我必须手动编写所有固定的“列”(并且在生产中它将远远超过它)。

我知道我可以使用脚本来生成JQ代码,但我对这样的解决方案感兴趣 - 它不能解决我的问题,因为这是针对应用程序的只接受JQ。

有没有办法在纯JQ中做到这一点?

这是我迄今为止所能得到的:

{
    "top-level-key": "top value 1",
    "list_0_key1": "value 1",
    "list_0_key2": "value 2",
    "list_1_key1": "value 3",
    "list_1_key2": "value 4",
}
{
    "top-level-key": "top value 2",
    "list_0_key1": "value 4",
    "list_0_key2": "value 5",
    "list_1_key1": "",
    "list_1_key2": "",
}

2 个答案:

答案 0 :(得分:9)

只要您知道特定按键的名称,Jeff的答案就很棒。这是一个没有对特定键名进行硬编码的答案,也就是说,它适用于任何结构和嵌套级别的对象:

[leaf_paths as $path | {
    "key": $path | map(tostring) | join("_"),
    "value": getpath($path)
}] | from_entries

解释:paths是一个内置函数,它递归地输出一个数组,表示传递给它的输入的每个元素的位置:所述数组中的元素是有序键名和导致请求的数组元素。 leaf_paths是它的一个版本,它只获取&#34; leaf&#34;的路径。元素,即不包含其他元素的元素。

澄清一下,如果输入[[1, 2]]paths将输出[0], [0, 0], [0, 1](即[1, 2]1和{{1}的路径分别)2只会输出leaf_paths

这是最难的部分。之后,我们将[0, 0], [0, 1](形式为$path)的每个路径转换为其每个元素,并使用["list", 1, "key2"]将其转换为字符串表示形式(这使我们map(tostring))并且["list", "1", "key2"]带有下划线。我们将此作为&#34;条目的关键&#34;在我们想要创建的对象中:作为值,我们在给定的join处获得原始对象的值。

最后,我们使用$path将键值对数组转换为JSON对象。这将为我们提供类似于杰夫答案的输出:即只显示带有值的键的输出。

但是,原始问题请求出现在任何输入对象上的值出现在所有输出中,并且在输入中缺少时,相应的值设置为空字符串。这是一个执行此操作的jq程序:正如杰夫在他的回答中所说,你需要啜饮(from_entries)所有输入值才能实现:

-s

您会注意到它与第一个程序非常相似:主要区别在于我们将诽谤对象中的所有唯一路径都设为(map(leaf_paths) | unique) as $paths | map([$paths[] as $path | { "key": $path | map(tostring) | join("_"), "value": (getpath($path) // "") }] | from_entries)[] ,并且对于我们经历的每个对象那些而不是通过那个对象的路径。我们还使用替代运算符($paths)将缺少值设置为空字符串。

希望这有帮助!

答案 1 :(得分:4)

以下是如何构建它的:

{ "top-level-key": .toplevel_key } + ([
    range(.list|length) as $i
        | .list[$i]
        | to_entries[]
        | .key = "list_\($i)_\(.key)"
    ] | from_entries)

这将映射每个相应的列表条目。

{
  "top-level-key": "top value 1",
  "list_0_key1": "value 1",
  "list_0_key2": "value 2",
  "list_1_key1": "value 3",
  "list_1_key2": "value 4"
}
{
  "top-level-key": "top value 2",
  "list_0_key1": "value 5",
  "list_0_key2": "value 6"
}

如果你需要填写它,你必须捏造结果以确定实际需要多少并添加填充。但是我现在就把它留下来。