我正在使用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
答案 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"]
答案 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']
您不需要命名空间,因为文档本身没有指定默认命名空间。