11

给定以下json:

{
    "README.rst": {
        "_status": {
            "md5": "952ee56fa6ce36c752117e79cc381df8"
        }
    },
    "docs/conf.py": {
        "_status": {
            "md5": "6e9c7d805a1d33f0719b14fe28554ab1"
        }
    }
}

是否有可以产生的查询语言:

{
    "README.rst": "952ee56fa6ce36c752117e79cc381df8",
    "docs/conf.py": "6e9c7d805a1d33f0719b14fe28554ab1",
}

到目前为止,我对 JMESPath ( http://jmespath.org/ ) 的最佳尝试并不是很接近:

>>> jmespath.search('*.*.md5[]', db)
['952ee56fa6ce36c752117e79cc381df8', '6e9c7d805a1d33f0719b14fe28554ab1']

我对 ObjectPath ( http://objectpath.org ) 也有同样的看法:

>>> t = Tree(db)
>>> list(t.execute('$..md5'))
['952ee56fa6ce36c752117e79cc381df8', '6e9c7d805a1d33f0719b14fe28554ab1']

我无法理解 JSONiq(我真的需要阅读 105 页的手册吗?)这是我第一次看 json 查询语言。

4

6 回答 6

6

不知道为什么要使用查询语言,这很容易

def find_key(data,key="md5"):
    for k,v in data.items():
       if k== key: return v
       if isinstance(v,dict):
          result = find_key(v,key)
          if result:return result

dict((k,find_key(v,"md5")) for k,v in json_result.items()) 

如果值 dict 总是将“_status”和“md5”作为键,那就更容易了

dict((k,v["_status"]["md5"]) for k,v in json_result.items()) 

或者我认为你可以做类似的事情

t = Tree(db)
>>> dict(zip(t.execute("$."),t.execute('$..md5'))

虽然我不知道它会完全匹配它们......

于 2015-09-12T00:17:50.237 回答
4

这是完成这项工作的 JSONiq 代码:

{|
    for $key in keys($document)
    return {
        $key: $document.$key._status.md5
    }
|}

您可以在此处使用 Zorba 引擎执行它。

如果您提到的 105 页手册是规范,我不建议作为 JSONiq 用户阅读它。我宁愿建议阅读教程或在线书籍,它们会提供更温和的介绍。

于 2015-10-12T13:09:07.527 回答
3

在 ObjectPath 中执行:

l = op.execute("[keys($.*), $..md5]")

你会得到:

[
  [
    "README.rst",
    "docs/conf.py"
  ],
  [
    "952ee56fa6ce36c752117e79cc381df8",
    "6e9c7d805a1d33f0719b14fe28554ab1"
  ]
]

然后在 Python 中:

dict(zip(l[0],l[1]))

要得到:

{
    'README.rst': '952ee56fa6ce36c752117e79cc381df8', 
    'docs/conf.py': '6e9c7d805a1d33f0719b14fe28554ab1'
}

希望有帮助。:)

PS。我正在使用 OP 的 keys() 来展示如何进行在文档中任何地方都可以使用的完整查询,而不仅仅是当键位于文档的根目录中时。

PS2。我可能会添加新函数,使其看起来像:object([keys($.*), $..md5])。如果您愿意,请向我发送推文http://twitter.com/adriankal 。

于 2015-11-20T00:45:05.543 回答
2

错过了 python 的要求,但如果你愿意调用外部程序,这仍然有效。请注意,此功能需要 jq >= 1.5。

# If single "key" $p[0] has multiple md5 keys, this will reduce the array to one key.
cat /tmp/test.json | \
jq-1.5 '[paths(has("md5")?) as $p | { ($p[0]): getpath($p)["md5"]}] | add '

# this will not create single object, but you'll see all key, md5 combinations
cat /tmp/test.json | \
jq-1.5 '[paths(has("md5")?) as $p | { ($p[0]): getpath($p)["md5"]}] '

获取带有“md5”-key '?'=ignore 错误的路径(例如测试键的标量)。从结果路径 ($p) 过滤并用 '{}' = object 包围结果。然后它们在一个数组中([] 围绕整个表达式),然后将其“添加/合并”在一起|add

https://stedolan.github.io/jq/

于 2015-09-18T09:08:16.010 回答
2

实现新查询语言的解决方案:

def keylist(db):
    "Return all the keys in db."

    def _keylist(db, prefix, res):
        if prefix is None:
            prefix = []

        for key, val in db.items():
            if isinstance(val, dict):
                _keylist(val, prefix + [key], res)
            else:
                res.append(prefix + [key])

    res = []
    _keylist(db, [], res)
    return ['::'.join(key) for key in res]

def get_key(db, key):
    "Get path and value from key."

    def _get_key(db, key, path):
        k = key[0]
        if len(key) == 1:
            return path + [k, db[k]]
        return _get_key(db[k], key[1:], path + [k])

    return _get_key(db, key, [])

def search(query, db):
    "Convert query to regex and use it to search key space."
    keys = keylist(db)
    query = query.replace('*', r'(?:.*?)')
    matching = [key for key in keys if re.match(query, key)]
    res = [get_key(db, key.split('::')) for key in matching]
    return dict(('::'.join(r[:-1]), r[-1]) for r in res)

这给了我一些非常接近要求的东西:

>>> pprint.pprint(search("*::md5", db))
{'README.rst::_status::md5': '952ee56fa6ce36c752117e79cc381df8',
 'docs/conf.py::_status::md5': '6e9c7d805a1d33f0719b14fe28554ab1'}

和一个看起来像 glob/re 混合的查询语言(如果我们正在制作一种新语言,至少让它看起来很熟悉):

>>> pprint.pprint(search("docs*::md5", db))
{'docs/conf.py::_status::md5': '6e9c7d805a1d33f0719b14fe28554ab1'}

因为数据包含我随机用作::路径分隔符的文件路径。(我很确定它还没有处理完整的 json 语法,但这应该主要是繁重的工作)。

于 2015-09-12T02:03:56.867 回答
1

如果您的 json 结构良好,即。确保您将拥有_statusmd5子元素,您可以加载 json 并使用列表推导来吐出您正在寻找的项目。

>>> import json
>>> my_json = json.loads(json_string)
>>> print [(key, value['_status']['md5']) for key, value in my_json.iteritems()]
[(u'README.rst', u'952ee56fa6ce36c752117e79cc381df8'), (u'docs/conf.py', u'6e9c7d805a1d33f0719b14fe28554ab1')]
于 2015-09-21T13:04:36.403 回答