Python和libxml2:如何使用XPATH在XML节点中迭代
我在从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
等,但任何结果(顺便说一句,如果我使用前缀的子查询我有一个错误)。
有什么想法?
这是一个建议。注意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
如果有可能切换到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和名字的记录。 如果缺少id
或name
,ret_list
会将错误的ID和名称进行配对,从而导致无提示失败。在相同的情况下,lxml代码会引发错误。
我使用libxml2无处不在,我想在这种情况下继续使用它。 不过谢谢您的回答! – 2010-07-29 20:01:42
lxml也使用'libxml2'库(&'libxslt')。它基本上是一个顶层让棘手的事情如此简单。 – 2010-07-29 22:18:49
好的,但应该有一种方法可以直接在libxml2中执行! – 2010-07-30 19:27:02
你可以选择你所需要的用一个XPath表达式的元素:
/pre:records/pre:record/*[self::pre:id or self::pre:name]
然后,只需处理在Python中选择的节点。
对不起,但这并不回答我的问题 – 2010-07-30 19:26:27
@ Giovanni-Di-Milia:这回答了XPath部分 - 我不知道Python。选择了你想要的所有节点后,你应该能够用Python处理它们并产生想要的结果。 – 2010-07-30 19:39:12
这是否保证节点返回的顺序?如果没有,这将增加python方面的一些复杂性,以便跟踪哪个'id'属于哪个'name'。 – 2011-02-18 13:05:50
的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 ""
我不认为这会回答问题,或者增加更多内容到已写入的内容 – 2011-08-17 21:23:48
对此没有评论?这确实是一种“直接在libxml2中执行”的方法。 – mzjn 2010-08-11 17:59:07
对不起!我忘了签署这个答案作为最好的答案!它实际上以我想要的方式工作。谢谢! – 2010-10-19 14:52:42