如何将带有 JQ 的嵌套 JSON 解析为 CSV 聚合输出?

  • 本文关键字:CSV 输出 JSON JQ 嵌套 bash jq
  • 更新时间 :
  • 英文 :


我有一个问题,是对我之前提出的问题的扩展/跟进: 如何根据字段值连接 JQ 中的虚拟值,然后对这些串联进行 CSV 聚合?

在我的 bash 脚本中,当我对我的卷曲结果运行以下 jq 时:
curl -u someKey:someSecret someURL 2>/dev/null | jq -r '.schema' | jq -r -c '.fields'

我得到一个 JSON 数组,如下所示:

[
{"name":"id", "type":"int"},
{
"name": "agents",
"type": {
"type": "array",
"items": {
"name": "carSalesAgents",
"type": "record"
"fields": [
{
"name": "agentName",
"type": ["string", "null"],
"default": null
},
{
"name": "agentEmail",
"type": ["string", "null"],
"default": null
},
{
"name": "agentPhones",
"type": {
"type": "array",
"items": {
"name": "SalesAgentPhone",
"type": "record"
"fields": [
{
"name": "phoneNumber",
"type": "string"
}
]
}
},
"default": []
}
]
}
},
"default": []
},
{"name":"description","type":"string"}
]

注意:此处添加了换行符和缩进,以便于阅读。这实际上都是一团文本。

我的目标是在应用jq的情况下进行调用以返回以下内容,给定上面的示例(为了可读性,再次添加了行和空格,但只需要返回有效的JSON blob(:

{
"id":1234567890,
"agents": [
{
"agentName": "xxxxxxxxxx",
"agentEmail": "xxxxxxxxxx",
"agentPhones": [
{
"phoneNumber": "xxxxxxxxxx"
},
{
"phoneNumber": "xxxxxxxxxx"
},
{
"phoneNumber": "xxxxxxxxxx"
}
]
},
{
"agentName": "xxxxxxxxxx",
"agentEmail": "xxxxxxxxxx",
"agentPhones": [
{
"phoneNumber": "xxxxxxxxxx"
},
{
"phoneNumber": "xxxxxxxxxx"
},
{
"phoneNumber": "xxxxxxxxxx"
}
]
}
],
"description":"xxxxxxxxxx"
}

总而言之,我正在尝试自动生成与上面显示的"架构"JSON 匹配的模板化值。

因此,为了澄清起见,"name"的值(包括其周围的双引号(与以下任一值连接在一起:

  • :1234567890 ...当该对象的"类型"为"int"时
  • ":xxxx" ...当该对象的"类型"为"字符串"时
  • 。当类型为"数组"或"记录"时,将添加相应的外壳 {} 或 [],其中包含嵌套的内容。
  • 如果是记录数组,则为输出生成两条记录

我开始为满足像这样的嵌套内容解析而开始的方法是为每个可能的 jq 类型的每个组合提供一系列 if-then-else。

但这很快就会变得非常难以管理和痛苦。从我最初的从头开始努力...

echo '[{"name":"id","type":"int"},{"name":"test_string","type":"string"},{"name":"string3ish","type":["string","null"],"default":null}]' | jq -c 'map({(.name): (if .type == "int" then 1234567890 else (if .type == "string" then "xxxxxxxxxx" else (if .type|type == "array" then "xxARRAYxx" else "xxUNKNOWNxx" end) end) end)})|add'

我想知道是否有人知道一种更聪明的方法可以在 bash/shell 中使用 JQ 执行此操作。

PS:我已经找到了使用 Java 和 Python 模块进行此类解析的替代解决方案,但 JQ 更适合可移植性限制的独特情况。 :)

谢谢!

jq支持函数。这些函数可以递归。

#!/usr/bin/env jq -f
# Ignore all but the first type, in the case of "type": ["string", "null"]
def takeFirstTypeFromArray:
if (.type | type) == "array" then
.type = .type[0]
else
.
end;
def sampleData:
takeFirstTypeFromArray |
if .type == "int" then
1234567890
elif .type == "string" then
"xxxxxxxxxx"
elif .type == "array" then   # generate two entries for any test array
[(.items | sampleData), (.items | sampleData)]
elif .type == "record" then
(.fields | map({(.name): sampleData}) | add)
elif (.type | type) == "array" then
(.type[] | sampleData)
elif (.type | type) == "object" then
(.type | sampleData)
else
["UNKNOWN", .]
end;
map({(.name): sampleData}) | add

最新更新