如何使用 jq 中的流选项从 JSON 文件中检索键和值
Posted
技术标签:
【中文标题】如何使用 jq 中的流选项从 JSON 文件中检索键和值【英文标题】:How to retrieve key and value from JSON file using stream option in jq 【发布时间】:2019-04-14 19:59:47 【问题描述】:我有一个结构如下的 json 文件:
"A": [
"B":
"C": [
"D":
"applicationNumberText":
"value": "15570075",
"electronicText": "15570075"
,
"date": "2018-10-01",
"app": "Utility"
]
]
现在我想检索electronicText
值。一种方法是使用如下索引
jq --stream 'select(.[0][1] == "A" and .[0][2] == "B" and .[0][3] == "C") | .[1]'
但在某些情况下结构可能会有所不同,所以我想通过键值而不是索引来引用。我尝试了以下方法,但它不起作用
cat file.json | jq --stream 'select(.A|.[]. B. C|.[]. D.applicationNumberText)'
所以我想在不使用索引的情况下检索 electronicText
键。
Note
:我想对大型 JSON 文件使用 stream
选项。
【问题讨论】:
您的第一个 jq 查询使用的键名甚至没有出现在 JSON 中。请修复。此外,问题的描述非常粗略,似乎与标题不同。请关注minimal reproducible example 并指出 .electronicText 的值是否已知为标量。 JSON 不是一个有效的。从 jsonlint.com 修复它 @Inian 感谢您的宝贵回复,我对 JSON 进行了一些更改,请通过此操作。 @peak 我刚刚更正了键名,请仔细阅读。感谢您的宝贵意见。 【参考方案1】:如果数组的索引是固定的,你可以使用这个过滤器:
jq '.A[0].B.C[0].D.applicationNumberText.electronicText' file
要提取所有electronicText
字段,您可以使用:
jq '.A[].B.C[].D.applicationNumberText.electronicText' file
如果你想使用 jq 流方式(虽然不清楚为什么),你可以使用这个:
jq --stream 'select(.[0]|contains(["electronicText"]))|.[1]//empty'
这将查找字符串electronicText
的键路径,如果找到,则获取其关联值。 //empty
是过滤掉没有值的路径数组。
【讨论】:
这仅返回electronicText
key 的值,但我想要 key 和 value 。你能帮我解决这个问题吗?而且我还想更改键名并将此值分配给新键名。例如:electronicText:1890 我想要“appnumber”:1890
我无法获取多键值,例如 value
键和 electronicText
键。你能帮帮我吗?
@vikash 我不清楚你到底想要什么。你可能会寻找类似jq --stream '"appnumber": (select(.[0]|contains(["electronicText"]))|.[1]//empty)' file
...
@vikash 改变问题的范围不是一个好主意。相反,请创建一个新问题,明确说明您的新问题是什么。
@vikash 您正在更改原始问题的范围。请关闭此问题(通过接受其中一个答案)并提出另一个问题。【参考方案2】:
我相信您正在寻找的是:
. as $inputs | | setpath($inputs[0]; $inputs[1]) | .A[]?.B.C[]?.D.applicationNumberText.electronicText // empty
此过滤器需要 --stream
作为标志(如您的第一个示例),生成一个带有 json 部分的时间 obj,根据您的第二个示例运行过滤器,然后隐藏空结果。注:This based on a example in the cookbook
让我给你一个概述,以防你感到困惑:
The --stream
flag will make your receive your data differently。现在,您的过滤器将使用 [<path>, <leaf-value>]
形式的数据运行多次,当解析器遍历您的 json 文件时接收到该数据,一次一个节点。
当您提到使用索引时,我相信您指的是这一点,在这种情况下,这意味着您正在检查 --streaming flag
公开的 path expression value
而不是 实际 json 数据。
请比较以下输出:
jq '.A[].B.C[].D.applicationNumberText.electronicText' file.json # outputs 15570075
jq --stream '.A[].B.C[].D.applicationNumberText.electronicText' file.json # multiple failures: cannot index array with string "A"
setpath() 接收这些路径和叶值参数将其置于其输入对象之上。例如
| setpath(["a", 0, "b"], "leaf-value") # returns "a":["b":"leaf-value"]
在我们的例子中,当解析访问每个节点时,我们会生成以下值流:
"A":["B":"C":["D":"applicationNumberText":"value":"15570075"]]
"A":["B":"C":["D":"applicationNumberText":"electronicText":"15570075"]]
"A":["B":"C":["D":"applicationNumberText":"electronicText":null]]
"A":["B":"C":["D":"date":"2018-10-01"]]
"A":["B":"C":["D":"app":"Utility"]]
现在数据的格式类似于 json 文件,我们可以运行更熟悉的过滤器。
.A[]?.B.C[]?.D.applicationNumberText.electronicText
请记住,两者之间没有空格。我们还在生成器.A[]
和.C[]
上使用?
运算符,因为我们不确定这些字段是否始终可以作为数组使用
最后一点,您可能需要考虑使用path()
构建一个路径数组,并将其与使用--stream
jq 标志时出现在.[0]
中的路径值进行比较
【讨论】:
你能告诉我使用stream
检索value
和electronicText
等多键值的确切方向吗?
@vikash 我写了一个例子in this gist over in github 并做了一些解释。如果这表明不清楚,请创建另一个关于多值检索的问题【参考方案3】:
回答原来的问题:
jq --stream '
select(length==2 and .[0][-1]=="electronicText")|.[1]
' input.json
"15570075"
如果您也想要value
,那么您可能希望考虑以下过滤器:
select(length==2 and .[0][-2]=="applicationNumberText")
| .[0][-1] as $last
| select($last == "electronicText" or $last == "value")
| ($last): .[1]
使用您的示例 JSON 生成:
"value":"15570075"
"electronicText":"15570075"
将键值对组合成单个 JSON 对象
构造“字典”的一种方法是将inputs
与-n 命令行选项结合使用。只需将上述过滤器包装在结构中即可:
[inputs | ....] | add
这里 .... 代表上述过滤器;并使用 both -n 和 --stream 选项调用 jq。
【讨论】:
谢谢!这是可行的,但我希望将value
和electronicText
或更多键的值合并到一本字典中,你能帮我吗?例如:"appnumber":1717, "value":1717,"key":corresponding values
等
@vikash - 您要求提供字典,这就是使用 inputs
的查询所产生的结果。如果你想添加更多的键/值对,你必须做一些了解。 SO 不是代码编写服务。【参考方案4】:
如果您知道感兴趣对象的名称,只需按名称搜索对象路径。
getpath(paths(objects) | select(.[-1] == "applicationNumberText"))
流式输入应该有助于解决效率问题。只需确定要保留的路径并截断感兴趣的路径即可。
$ jq -n --stream --arg key 'applicationNumberText' '
fromstream(inputs | truncate_stream2((.[0] | index($key) // empty) + 1))
' input.json
这只是检查路径并查找 "applicationNumberText"
键,然后将路径截断为该值,以便可以从流中重建它。
这使用了 truncate_stream/1
函数的反转版本,它交换了我发现使用更直观的常用输入。
def truncate_stream2($count): .[0] |= .[$count:];
【讨论】:
jq: error: truncate_stream2/1 is not defined at <top-level>, line 2:
我收到了这个错误以上是关于如何使用 jq 中的流选项从 JSON 文件中检索键和值的主要内容,如果未能解决你的问题,请参考以下文章
jq json根据条件从内部数组中检索值并将其添加到数组之外
如何删除 jq 输出中的双引号以在 bash 中解析 json 文件?
如何删除 jq 输出中的双引号以在 bash 中解析 json 文件?