2011-09-06 36 views
25

Có cách nào để xác định truy vấn kiểu XPath cho từ điển python lồng nhau không.Xpath giống như truy vấn cho từ điển python lồng nhau

Something như thế này:

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

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

>> {'bacon' : 'foobar'} 

Tôi cũng cần thiết để chọn danh sách lồng nhau;)

Điều này có thể được thực hiện dễ dàng bằng dung dịch @ Jellybean của:

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] Đây câu hỏi và câu trả lời được chấp nhận là cổ xưa. Các câu trả lời mới hơn có thể thực hiện công việc tốt hơn câu trả lời gốc. Tuy nhiên tôi đã không kiểm tra chúng vì vậy tôi sẽ không thay đổi câu trả lời được chấp nhận.

+0

Tại sao không sử dụng 'foo ['morefoo'] ['morebar']'? – MarcoS

+3

vì tôi muốn làm: def bla (truy vấn): data.select (truy vấn) – RickyA

+0

@MarcoS Nó sẽ thú vị hơn với các danh sách nơi đường dẫn microlanguage sẽ trả về nhiều mục. –

Trả lời

8

Không hẳn xinh đẹp, nhưng bạn có thể sử dụng sth như

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

    return elem 

này không hỗ trợ thứ xpath như chỉ số, tất nhiên ... chưa kể đến / trọng bẫy unutbu chỉ định.

+0

Năm 2011 có thể không có nhiều lựa chọn như ngày nay, nhưng trong năm 2014, tôi nghĩ, giải quyết vấn đề theo cách này không thanh lịch và nên tránh. – nikolay

+8

@nikolay đây có phải chỉ là một sự đoán hay có giải pháp nào giải quyết điều này một cách độc đáo hơn? –

1

Công việc khác sẽ phải được đưa vào cách bộ chọn giống XPath hoạt động như thế nào. '/' là chìa khóa từ điển lệ, vậy làm thế nào

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

sẽ bị xử lý?

foo.select("///") 

sẽ không rõ ràng.

+0

Có, bạn sẽ cần một trình phân tích cú pháp cho điều đó. Nhưng những gì tôi yêu cầu là cho một phương pháp xpath _like_. "morefoo.morebar" là tốt của tôi. – RickyA

+2

@RickyA: ''.'' cũng là một khóa từ điển giá trị. Cùng một vấn đề sẽ tồn tại. 'foo.select ('...')' sẽ không rõ ràng. – unutbu

1

Có lý do nào để bạn truy vấn nó theo cách giống như mẫu XPath không? Khi người nhận xét cho câu hỏi của bạn được đề xuất, nó chỉ là một từ điển, vì vậy bạn có thể truy cập các phần tử theo cách lồng. Ngoài ra, xem xét dữ liệu đó ở dạng JSON, bạn có thể sử dụng mô-đun simplejson để tải nó và truy cập các phần tử.

Có dự án này JSONPATH, đang cố gắng giúp mọi người đối diện với những gì bạn định làm (cho XPath, cách làm cho nó dễ truy cập thông qua các đối tượng python), có vẻ hữu ích hơn.

+0

Lý do là tôi muốn chia dữ liệu và truy vấn. Tôi muốn linh hoạt trong phần truy vấn. Nếu tôi truy cập nó theo cách lồng nhau thì truy vấn được mã hóa cứng trong chương trình. – RickyA

+0

@RickyA, trong nhận xét khác bạn nói morefoo.morebar là tốt. Bạn đã kiểm tra dự án JSONPATH (Tải xuống và xem nguồn và kiểm tra). –

+0

Tôi đã xem JSONPATH, nhưng đầu vào của tôi không phải là văn bản/json. Đó là từ điển lồng nhau. – RickyA

1

Một thay thế (bên cạnh đó đề xuất bởi jellybean) là thế này:

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

Có một cách dễ dàng hơn để làm điều này ngay bây giờ.

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

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

... thực hiện. Hoặc nếu bạn không muốn đưa kết quả của mình trở lại trong chế độ xem (từ điển đã hợp nhất giữ lại đường dẫn), hãy mang lại thay vào đó:

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

... và thực hiện. 'value' sẽ giữ {'bacon': 'foobar'} trong trường hợp đó.

+0

Câu lệnh lặp lại không chạy --- không có phần thân nào cho câu lệnh for. – Mittenchops

10

Có là jsonpath-rw thư viện mới hơn hỗ trợ một cú pháp JSONPATH nhưng đối với python điểnmảng, như bạn mong muốn.

Vì vậy, ví dụ 1 của bạn trở thành:

from jsonpath_rw import parse 

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

Và thứ 2:

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

PS: Một thư viện đơn giản thay thế cũng hỗ trợ các từ điển là python-json-pointer với hơn XPath giống như cú pháp.

+0

Lưu ý rằng jsonpath sử dụng eval và jsonpath-rw trông không được duy trì (nó cũng cho biết một số tính năng bị thiếu, nhưng tôi chưa thử nó). –

15

Một trong những thư viện tốt nhất mà tôi có thể xác định, trong đó, ngoài ra, được phát triển rất tích cực, là một dự án được trích xuất từ ​​boto: JMESPath. Nó có một cú pháp rất mạnh mẽ để làm những việc mà thông thường sẽ lấy các trang mã để diễn đạt.

Dưới đây là một số ví dụ:

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

Nếu terseness là ưa thích của bạn:

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) 

Tất nhiên, nếu bạn chỉ có dicts, sau đó nó đơn giản hơn:

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

Chúc may mắn tìm thấy bất kỳ lỗi nào trong đường dẫn của bạn spec tho ;-)

Các vấn đề liên quan