我有一个包含以下内容的 json 文件:
{
"id1": {
"key": "value"
},
"id2": {
"key": "value"
}
}
我想检查每个顶级密钥,即。
id1, id2
在文件中仅出现一次,如果不出现则会产生错误。所以类似
{
"id1": {
"key": "value"
},
"id1": {
"key": "value"
}
}
必须显示为错误。
有没有办法使用像
jq
或json-glib-validate
这样的json解析器来做到这一点?
我想出了一个Pythonic解决方案,它可以工作,但如果有一个实际的解析器会更好。
这应该在 CI 中使用。
import collections
import json
import sys
def check_duplicates(pairs):
count = collections.Counter(i for i,j in pairs)
duplicates = ", ".join(i for i,j in count.items() if j>1)
if len(duplicates) != 0:
print("Duplicate keys found: {}".format(duplicates))
sys.exit(1)
def validate(pairs):
check_duplicates(pairs)
return dict(pairs)
with open("file.json", "r") as file:
try:
obj = json.load(file, object_pairs_hook=validate)
except ValueError as e:
print("Invalid json: %s" % e)
sys.exit(1)
有没有办法用像
这样的json解析器来做到这一点jq
您可以使用 jq 的流表示,它可以通过
--stream
标志或通过 tostream
函数调用。不同之处在于,对于该函数,输入已经被解析(并且重复的键被折叠),而使用该标志将在读取输入时开始流式传输,因此在任何折叠发生之前。因此,例如,在 bash 中,只需比较两者的输出,例如使用 diff
:
$ diff -q <(jq --stream . nodupkeys.json) <(jq tostream nodupkeys.json)
# no output
$ diff -q <(jq --stream . withdupkeys.json) <(jq tostream withdupkeys.json)
Files /dev/fd/63 and /dev/fd/62 differ
解决@peak的comment:如果使用itchyny/gojq而不是jqlang/jq,上述方法将会失败,因为它会自动对键进行排序,但只有在解析输入之后(使用该函数时会遇到这种情况,但在使用该标志时则不然),因此对于具有无序键但没有重复项的文档,它仍然会产生差异。
以下(无外壳)方法尝试通过将标志变体提供的所有路径收集到一个数组中来缓解这种情况,然后将其
sort
ed 版本与其 unique
d 版本(也是自动排序的)进行比较,使得与所使用的处理器的实现执行的潜在排序无关。
$ jq --stream -n '[inputs[-2] | arrays] | sort == unique' nodupkeys.json
true
$ jq --stream -n '[inputs[-2] | arrays] | sort == unique' withdupkeys.json
false
根据定义,JSON 中不可能有重复的键。因此,为了让您的生活更轻松,请将 json 更改为如下所示:
{
"value": {
...
},
"value": {
...
}
}
还应该有解析器。