使用Python解析XML - 访问元素

时间:2015-07-02 19:18:50

标签: python xml python-2.7 lxml

我正在使用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']
    ... 

正如您所看到的,这些事情似乎都不起作用。

我做错了什么?

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

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

3 个答案:

答案 0 :(得分:3)

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

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)属于该命名空间。

因此,您需要查找Constant元素而不是{http://www.copasi.org/static/schema}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

答案 1 :(得分: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']

答案 2 :(得分:0)

不要使用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表达式中包含命名空间前缀,并且它们必须映射到与其匹配的命名空间URL之一您文档中的网址。

更新

由于您发布了原始文档,因此我发现没有为您要查找的元素分配命名空间。这将有效,我只是尝试使用您的源文档:

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

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