用 Python 解析 XML - 访问元素

Parsing XML with Python - accessing elements

我正在使用 lxml 来解析一些 xml,但由于某种原因我找不到特定的元素。

我正在尝试访问 <Constant> 个元素。

这是一个 xml 片段:

  </rdf:Description>
</rdf:RDF>
        </MiriamAnnotation>
        <ListOfSubstrates>
          <Substrate metabolite="Metabolite_5" stoichiometry="1"/>
        </ListOfSubstrates>
        <ListOfModifiers>
          <Modifier metabolite="Metabolite_9" stoichiometry="1"/>
        </ListOfModifiers>
        <ListOfConstants>
          <Constant key="Parameter_4344" name="Kcat" value="433.724"/>
          <Constant key="Parameter_4343" name="km" value="479.617"/>

我使用的代码是这样的:

    >>> from lxml import etree as ET
    >>> parsed = ET.parse('ct.cps')
    >>> root = parsed.getroot()    
    >>> for a in root.findall(".//Constant"):
    ...     print a.attrib['key']
    ... 
    >>> for a in root.findall('Constant'):
    ...     print a.get('key')
    ... 
    >>> for a in root.findall('Constant'):
    ...     print a.attrib['key']
    ... 

如您所见,none 这些东西似乎有效。

我做错了什么?


编辑:我想知道这是否与 <Constant> 元素为空这一事实有关?


EDIT2:来源xml 此处:https://www.dropbox.com/s/i6hga7nvmcd6rxx/ct.cps?dl=0

首先,请无视我的评论。事实证明 xml.etree 比标准的 xml.etree.ElementTree 好得多,因为它负责命名空间。你遇到的问题是你想搜索 '//Constant',这意味着节点可以在任何级别。但是,根元素不允许你这样做:

>>> root.findall('//Constant')
SyntaxError: cannot use absolute path on element

但是,您可以在更高级别执行此操作:

>>> parsed.findall('//Constant')
[<Element Constant at 0x10a7ce128>, <Element Constant at 0x10a7ce170>]

更新

我在这里张贴全文。由于我没有你的完整 XML 文件,我做了一些东西来填补空白。

from lxml import etree as ET
from StringIO import StringIO

xml_text = """<?xml version='1.0' encoding='utf-8' ?>

<rdf:root  xmlns:rdf='http://foo.bar.com/rdf'>
<rdf:RDF>
  <rdf:Description>
    DescriptionX
  </rdf:Description>
</rdf:RDF>
<rdf:foo>
        <MiriamAnnotation>
          bar
        </MiriamAnnotation>
        <ListOfSubstrates>
          <Substrate metabolite="Metabolite_5" stoichiometry="1"/>
        </ListOfSubstrates>
        <ListOfModifiers>
          <Modifier metabolite="Metabolite_9" stoichiometry="1"/>
        </ListOfModifiers>
        <ListOfConstants>
          <Constant key="Parameter_4344" name="Kcat" value="433.724"/>
          <Constant key="Parameter_4343" name="km" value="479.617"/>
        </ListOfConstants>
</rdf:foo>
</rdf:root>
"""

buffer = StringIO(xml_text)
tree = ET.parse(buffer)
for constant_node in tree.findall('//Constant'):
    print constant_node.attrib['key']

不要使用 findall。它的功能集有限,旨在与 ElementTree.

兼容

而是使用 xpath,它支持命名空间。从上面看来,你可能想说

# possibilities, you need to get these right...
ns_dict = {'atom':"http://www.w3.org/2005/Atom",,
    "rdf":"http://www.w3.org/2000/01/rdf-schema#" }

root = parsed.getroot()    
for a in root.xpath('.//rdf:Constant', namespaces=ns_dict):
    print a.attrib['key']

请注意,只要元素具有非空白命名空间,您 必须 xpath 表达式中包含命名空间前缀,并且它们必须映射到其中一个命名空间与您文档中的相同网址相匹配的网址。

更新

由于您发布了原始文档,我发现没有为您要查找的元素分配名称空间。这会起作用,我刚刚用你的源文件试过了:

for a in tree.xpath("//Constant"):
    print a.attrib['key']

您不需要命名空间,因为文档本身没有指定默认命名空间。

以下是获取所需值的方法:

from lxml import etree

parsed = etree.parse('ct.cps')

for a in parsed.findall("//{http://www.copasi.org/static/schema}Constant"):
    print a.attrib["key"]

输出:

Parameter_4344
Parameter_4343
Parameter_4342
Parameter_4341
Parameter_4340
Parameter_4339
Parameter_4338
Parameter_4337
Parameter_4336
Parameter_4335
Parameter_4334
Parameter_4333
Parameter_4332
Parameter_4331
Parameter_4330
Parameter_4329
Parameter_4328
Parameter_4327
Parameter_4326
Parameter_4325
Parameter_4324
Parameter_4323
Parameter_4322
Parameter_4321
Parameter_4320
Parameter_4319

这里重要的是 XML 文件中的 COPASI 根元素(Dropbox URL 中的真实元素)声明了一个默认命名空间 (http://www.copasi.org/static/schema ).这意味着该元素及其所有后代,包括 Constant,都属于该命名空间。

因此,您需要寻找 {http://www.copasi.org/static/schema}Constant 个元素,而不是 Constant 个元素。

参见http://lxml.de/tutorial.html#namespaces


这是使用 XPath 而不是 findall 的方法:

from lxml import etree

NSMAP = {"c": "http://www.copasi.org/static/schema"}

parsed = etree.parse('ct.cps')

for a in parsed.xpath("//c:Constant", namespaces=NSMAP):
    print a.attrib["key"]

http://lxml.de/xpathxslt.html#namespaces-and-prefixes