2011-09-06 3 views
25

중첩 된 파이썬 사전에 대한 XPath 유형 쿼리를 정의하는 방법이 있습니까? 이 같은중첩 된 파이썬 사전에 대한 Xpath와 유사한 쿼리

뭔가 :

foo = { 
    'spam':'eggs', 
    'morefoo': { 
       'bar':'soap', 
       'morebar': {'bacon' : 'foobar'} 
       } 
    } 

print(foo.select("/morefoo/morebar")) 

>> {'bacon' : 'foobar'} 

또한 중첩 된 목록을 선택하는 데 필요한,

이것은 @의 젤리 빈의 솔루션을 쉽게 수행 할 수 있습니다) :

def xpath_get(mydict, path): 
    elem = mydict 
    try: 
     for x in path.strip("/").split("/"): 
      try: 
       x = int(x) 
       elem = elem[x] 
      except ValueError: 
       elem = elem.get(x) 
    except: 
     pass 

    return elem 

foo = { 
    'spam':'eggs', 
    'morefoo': [{ 
       'bar':'soap', 
       'morebar': { 
          'bacon' : { 
             'bla':'balbla' 
            } 
          } 
       }, 
       'bla' 
       ] 
    } 

print xpath_get(foo, "/morefoo/0/morebar/bacon") 

[EDIT 2016]이 질문과 대답은 고대다. 새로운 대답은 원래의 대답보다 더 잘할 수 있습니다. 그러나 나는 그 (것)들을 시험하지 않았다 그래서 나는 받아 들여진 응답을 바꾸지 않을 것이다.

+0

왜'foo [ 'morefoo'] [ 'morebar']'를 사용하지 않습니까? – MarcoS

+3

내가 원하는 이유는 다음과 같습니다. def bla (query) : data.select (query) – RickyA

+0

@MarcoS 경로 마이크로 언어가 여러 항목을 반환하는 목록에서 더 재미있을 것입니다. –

답변

8

정확히 아름다운하지 않습니다,하지만 당신은 표시된 / 키 트랩 unutbu 말할 것도없고 ... 이것은 물론, 인덱스 같은 XPath는 물건을 지원하지 않습니다

def xpath_get(mydict, path): 
    elem = mydict 
    try: 
     for x in path.strip("/").split("/"): 
      elem = elem.get(x) 
    except: 
     pass 

    return elem 

같은 STH를 사용할 수 있습니다.

+0

2011 년에는 오늘만큼 많은 옵션이 없을 수도 있지만 2014 년에는 이런 식으로 문제를 해결하는 것이 우아하지 않으므로 피해야합니다. – nikolay

+8

@nikolay는 단지 추측입니까? 아니면이 문제를 해결하는 솔루션이 있습니까? –

1

XPath와 같은 선택기가 어떻게 작동하는지 더 많은 작업을해야 할 것입니다. '/'는 유효한 사전 키, 그래서 어떻게

foo={'/':{'/':'eggs'},'//':'ham'} 

는 처리 할 것인가?

foo.select("///") 

은 모호합니다.

+0

예,이를 위해 파서가 필요합니다. 하지만 내가 묻는 것은 xpath _like_ 메소드에 대한 것이다. "morefoo.morebar"는 나에게 괜찮습니다. – RickyA

+2

@RickyA :' '.''도 값 사전 키입니다. 같은 문제가 존재합니다. 'foo.select ('...')'는 모호합니다. – unutbu

1

XPath 패턴과 같은 방식으로 쿼리 할 이유가 있습니까? 귀하의 질문에 대한 의견 제시 자로서, 그것은 단지 사전이므로, 당신은 둥지 방식으로 요소에 액세스 할 수 있습니다. 또한 데이터가 JSON 형태라는 점을 감안할 때 simplejson 모듈을 사용하여로드하고 요소에 액세스 할 수 있습니다.

이 프로젝트은 사람들이 당신이하고자하는 것과는 반대되는 것을 돕기 위해 노력하고 있습니다 (주어진 XPATH, 파이썬 객체를 통해 쉽게 액세스 할 수있게하는 방법).

+0

이유는 데이터와 쿼리를 분할하기 위해서입니다. 나는 쿼리 부분에서 유연 해지고 싶다. 중첩 된 방식으로 액세스하면 프로그램에서 쿼리가 하드 코드됩니다. – RickyA

+0

@RickyA, 다른 의견에서 morefoo.morebar는 괜찮습니다. JSONPATH 프로젝트를 확인 했습니까 (소스 및 테스트를 다운로드하여 살펴보십시오). –

+0

JSONPATH를 살펴 봤지만 입력 한 내용이 text/json이 아닙니다. 중첩 된 사전입니다. – RickyA

1

(즉 jellybean에 의해 제안 외에) 다른 대안은 이것이다 :

def querydict(d, q): 
    keys = q.split('/') 
    nd = d 
    for k in keys: 
    if k == '': 
     continue 
    if k in nd: 
     nd = nd[k] 
    else: 
     return None 
    return nd 

foo = { 
    'spam':'eggs', 
    'morefoo': { 
       'bar':'soap', 
       'morebar': {'bacon' : 'foobar'} 
       } 
    } 
print querydict(foo, "/morefoo/morebar") 
11

지금이 작업을 수행 할 수있는 쉬운 방법이있다.

$ easy_install dpath 
>>> dpath.util.search(YOUR_DICTIONARY, "morefoo/morebar") 

http://github.com/akesterson/dpath-python

은 ... 다. 당신이보기 (경로를 유지 병합 사전)에 다시 결과를 얻는 마음에 들지 않는 경우 또는, 대신 그들을 얻을 :

$ easy_install dpath 
>>> for (path, value) in dpath.util.search(YOUR_DICTIONARY, "morefoo/morebar", yielded=True) 

... 그리고 일을. 이 경우 'value'는 { 'bacon': 'foobar'}를 유지합니다. 당신이 바란대로 사전배열이, 거기에 JSONPATH 구문을 지원하는 새로운 jsonpath-rw 라이브러리는하지만, 파이썬에 대한

+0

iterated 문이 실행되지 않습니다. for 문에 본문이 없습니다. – Mittenchops

10

.

그래서 첫번째 예는된다 :

from jsonpath_rw import parse 

print(parse('$.morefoo.morebar').find(foo)) 

그리고 2 :

print(parse("$.morefoo[0].morebar.bacon").find(foo)) 

PS를 : 또 다른 간단한 라이브러리는 사전을 지원하는 것은 더 XPath를-등으로 python-json-pointer입니다 통사론.

+0

jsonpath는 eval을 사용하고 jsonpath-rw는 유지 보수가되지 않은 것처럼 보입니다 (또한 일부 기능이 없지만 시도하지는 않았습니다). –

15

내가 확인할 수있는 최고의 라이브러리 중 하나는 매우 활발히 개발되었으며 boto : JMESPath의 압축 된 프로젝트입니다. 표현하기 위해 일반적으로 코드 페이지를 사용하는 일을하는 매우 강력한 구문을 가지고 있습니다. 간결성이 당신의 공상 인 경우

search('foo | bar', {"foo": {"bar": "baz"}}) -> "baz" 
search('foo[*].bar | [0]', { 
    "foo": [{"bar": ["first1", "second1"]}, 
      {"bar": ["first2", "second2"]}]}) -> ["first1", "second1"] 
search('foo | [0]', {"foo": [0, 1, 2]}) -> [0] 
0

: 여기

은 몇 가지 예입니다 물론

def xpath(root, path, sch='/'): 
    return reduce(lambda acc, nxt: acc[nxt], 
        [int(x) if x.isdigit() else x for x in path.split(sch)], 
        root) 

만 dicts이 다음 그것의 경우, 간단한 :

def xpath(root, path, sch='/'): 
    return reduce(lambda acc, nxt: acc[nxt], 
        path.split(sch), 
        root) 

행운을 빌어 경로 사양에 오류가 있음을 확인하십시오 .-)