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。キーがドキュメントのルートにある場合だけでなく、ドキュメントのどこでも機能する完全なクエリを作成する方法を示すために、OPs の 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 に答える