2010-07-29 58 views
2

我在從XML樹中檢索信息時遇到問題。Python和libxml2:如何使用XPATH在XML節點中迭代

我的XML具有這種形狀:

<?xml version="1.0"?> 
<records xmlns="http://www.mysyte.com/foo"> 
    <record> 
    <id>first</id> 
    <name>john</name> 
    <papers> 
     <paper>john_1</paper> 
     <paper>john_2</paper> 
    </papers> 
    </record> 
    <record> 
    <id>second</id> 
    <name>mike</name> 
    <papers> 
     <paper>mike_a</paper> 
     <paper>mike_b</paper> 
    </papers> 
    </record> 
    <record> 
    <id>third</id> 
    <name>albert</name> 
    <papers> 
     <paper>paper of al</paper> 
     <paper>other paper</paper> 
    </papers> 
    </record> 
</records> 

我想要做的是萃取,如後續數據的元組:

[{'code': 'first', 'name': 'john'}, 
{'code': 'second', 'name': 'mike'}, 
{'code': 'third', 'name': 'albert'}] 

現在,我寫了這個Python代碼:

try: 
    doc = libxml2.parseDoc(xml) 
except (libxml2.parserError, TypeError): 
    print "Problems loading XML" 

ctxt = doc.xpathNewContext() 
ctxt.xpathRegisterNs("pre", "http://www.mysyte.com/foo") 

record_nodes = ctxt.xpathEval('/pre:records/pre:record') 

for record_node in record_nodes: 
    id = record_node.xpathEval('id')[0].content 
    name = record_node.xpathEval('name')[0].content 
    ret_list.append({'code': id, 'name': name}) 

我的問題是,我沒有任何結果,我的印象是我做錯了XPATH w如果我在節點上迭代。

我也試圖與這些XPath的ID和名稱:

/id 
/name 
/record/id 
/record/name 
/pre:id 
/pre:name 

等,但任何結果(順便說一句,如果我使用前綴的子查詢我有一個錯誤)。

有什麼想法?

回答

6

這是一個建議。注意setContextNode()方法:

import libxml2 

xml = "test.xml" 
doc = libxml2.parseFile(xml) 

ctxt = doc.xpathNewContext() 
ctxt.xpathRegisterNs("pre","http://www.mysyte.com/foo") 

ret_list = [] 
record_nodes = ctxt.xpathEval('/pre:records/pre:record') 

for node in record_nodes: 
    ctxt.setContextNode(node) 
    _id = ctxt.xpathEval('pre:id')[0].content 
    name = ctxt.xpathEval('pre:name')[0].content 
    ret_list.append({'code': _id, 'name': name}) 

print ret_list 
+0

對此沒有評論?這確實是一種「直接在libxml2中執行」的方法。 – mzjn 2010-08-11 17:59:07

+0

對不起!我忘了簽署這個答案作爲最好的答案!它實際上以我想要的方式工作。謝謝! – 2010-10-19 14:52:42

0

如果有可能切換到lxml,這裏是一個方式,它可以這樣做:

import lxml.etree as le 
root=le.XML(content) 
result=[] 
namespaces={'pre':'http://www.mysyte.com/foo'} 
for record in root: 
    id=record.xpath('pre:id',namespaces=namespaces)[0] 
    name=record.xpath('pre:name',namespaces=namespaces)[0] 
    result.append({'code':id.text,'name':name.text}) 
print(result) 
# [{'code': 'first', 'name': 'john'}, {'code': 'second', 'name': 'mike'}, {'code': 'third', 'name': 'albert'}] 

大廈關閉的Dimitre Novatchev's XPath expression,你可以這樣做:

id_name_nodes = iter(ctxt.xpathEval('/pre:records/pre:record/*[self::pre:id or self::pre:name]')) 

ret_list=[] 
for id,name in zip(id_name_nodes,id_name_nodes): 
    ret_list.append({'code':id.content,'name':name.content}) 
print(ret_list) 

這libxml2的代碼,依靠每個有id和名字的記錄。 如果缺少idnameret_list會將錯誤的ID和名稱進行配對,從而導致無提示失敗。在相同的情況下,lxml代碼會引發錯誤。

+0

我使用libxml2無處不在,我想在這種情況下繼續使用它。 不過謝謝您的回答! – 2010-07-29 20:01:42

+0

lxml也使用'libxml2'庫(&'libxslt')。它基本上是一個頂層讓棘手的事情如此簡單。 – 2010-07-29 22:18:49

+0

好的,但應該有一種方法可以直接在libxml2中執行! – 2010-07-30 19:27:02

0

你可以選擇你所需要的用一個XPath表達式的元素:

/pre:records/pre:record/*[self::pre:id or self::pre:name] 

然後,只需處理在Python中選擇的節點。

+0

對不起,但這並不回答我的問題 – 2010-07-30 19:26:27

+0

@ Giovanni-Di-Milia:這回答了XPath部分 - 我不知道Python。選擇了你想要的所有節點後,你應該能夠用Python處理它們併產生想要的結果。 – 2010-07-30 19:39:12

+0

這是否保證節點返回的順序?如果沒有,這將增加python方面的一些複雜性,以便跟蹤哪個'id'屬於哪個'name'。 – 2011-02-18 13:05:50

-1

的libxslt缺少這樣一個重要的命名空間支持出於某種原因,但是從它我們可以預先解析xml文件,預讀的命名空間,然後調用xsltproc的這些命名空間

def xpath(xml, xpathexpression): 
    f=open(xml) 
    fcontent = f.read() 
    f.close() 

    doc=libxml2.parseFile(xml) 
    xp = doc.xpathNewContext() 
    for nsdeclaration in re.findall('xmlns:*\w*="[^"]*"', fcontent): 
     m = re.match('xmlns:(\w+)=.*', nsdeclaration) 
     if m: 
      ns = m.group(1) 
     else: 
      ns = "default" 
     url = nsdeclaration[nsdeclaration.find('"')+1:nsdeclaration.rfind('"')] 
     xp.xpathRegisterNs(ns, url) 
    a=xp.xpathEval(xpathexpression) 
    if len(a): 
     return a[0].content 
    return "" 
+0

我不認爲這會回答問題,或者增加更多內容到已寫入的內容 – 2011-08-17 21:23:48

相關問題