Python ElementTree模块:如何在使用方法“find”,“findall”时忽略XML文件的命名空间来定位匹配元素,

我想使用“findall”的方法来查找ElementTree模块中源xml文件的一些元素。

但是,源XML文件(test.xml)具有名称空间。 我截断了一部分xml文件作为示例:

<?xml version="1.0" encoding="iso-8859-1"?> <XML_HEADER xmlns="http://www.test.com"> <TYPE>Updates</TYPE> <DATE>9/26/2012 10:30:34 AM</DATE> <COPYRIGHT_NOTICE>All Rights Reserved.</COPYRIGHT_NOTICE> <LICENSE>newlicense.htm</LICENSE> <DEAL_LEVEL> <PAID_OFF>N</PAID_OFF> </DEAL_LEVEL> </XML_HEADER> 

示例python代码如下:

 from xml.etree import ElementTree as ET tree = ET.parse(r"test.xml") el1 = tree.findall("DEAL_LEVEL/PAID_OFF") # Return None el2 = tree.findall("{http://www.test.com}DEAL_LEVEL/{http://www.test.com}PAID_OFF") # Return <Element '{http://www.test.com}DEAL_LEVEL/PAID_OFF' at 0xb78b90> 

虽然它可以工作,但是由于存在名称空间“{http://www.test.com}”,因此在每个标签前添加一个名称空间非常不方便。

如何在使用“find”,“findall”等方法时忽略名称空间?

而不是修改XML文档本身,最好parsing它,然后修改结果中的标记。 这样你可以处理多个名字空间和名字空间别名:

 from StringIO import StringIO import xml.etree.ElementTree as ET # instead of ET.fromstring(xml) it = ET.iterparse(StringIO(xml)) for _, el in it: if '}' in el.tag: el.tag = el.tag.split('}', 1)[1] # strip all namespaces root = it.root 

这是基于这里的讨论: http : //bugs.python.org/issue18304

如果您在parsingxml之前从xml中删除了xmlns属性,那么树中的每个标记都不会有一个名称空间。

 import re xmlstring = re.sub(' xmlns="[^"]+"', '', xmlstring, count=1) 

到目前为止的答案明确地把名字空间值放在脚本中。 对于更通用的解决scheme,我宁愿从xml中提取命名空间:

 def get_namespace(element): m = re.match('\{.*\}', element.tag) return m.group(0) if m else '' 

并在查找方法中使用它:

 namespace = get_namespace(tree.getroot()) print tree.find('./{0}parent/{0}version'.format(namespace)).text 

这是nonagon的答案的扩展,它也剥夺了属性的命名空间:

 from StringIO import StringIO import xml.etree.ElementTree as ET # instead of ET.fromstring(xml) it = ET.iterparse(StringIO(xml)) for _, el in it: if '}' in el.tag: el.tag = el.tag.split('}', 1)[1] # strip all namespaces for at in el.attrib.keys(): # strip namespaces of attributes too if '}' in at: newat = at.split('}', 1)[1] el.attrib[newat] = el.attrib[at] del el.attrib[at] root = it.root 

您也可以使用优雅的string格式化结构:

 ns='http://www.test.com' el2 = tree.findall("{%s}DEAL_LEVEL/{%s}PAID_OFF" %(ns,ns)) 

或者,如果您确定PAID_OFF只出现在树中的一个级别中:

 el2 = tree.findall(".//{%s}PAID_OFF" % ns)