Python和libxml2:如何使用XPATH在xml节点中迭代

2024-05-14 14:11:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我在从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上做了一些错误的事情。

我还试过用这些xpath来获取id和名称:

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

等等,但是有任何结果(顺便说一下,如果我在子查询中使用前缀,我就有一个错误)。

知道吗?


Tags: nameidnodecodexmlrecordjohnpre
3条回答

这是一个建议。注意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和名称的记录。 如果缺少idname,则ret_list将配对错误的id和名称,并以静默方式失败。在相同的情况下,lxml代码将引发一个错误。

您可以用一个XPath表达式选择所需的所有元素

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

然后在python中处理选定的节点。

相关问题 更多 >

    热门问题