我正在使用python 2.7并尝试解析下面的XML - 我要做的是创建一个包含语言属性的所有类型的python数组以及没有语言属性的数组。
我正在使用python模块import xml.etree.cElementTree as ET
我知道我可以通过语法找到语言属性在“fr”语言中的XML部分:
tree=ET.ElementTree(file='popups.xml') root = tree.getroot() for x in root.findall('alt[@{http://www.w3.org/XML/1998/namespace}lang="fr"]/alt'): print x.text
我真的不明白为什么我不能使用xml:lang
而不是{http://www.w3.org/XML/1998/namespace}lang
,但上面的内容似乎适用于Ubuntu 12.04
我想要找出的是“not”语法 - 其中XML部分没有任何语言属性
有人想过如何实现这个目标吗?
<genre>
<alt>
<alt genre="easy listening">lounge</alt>
<alt genre="alternative">ska</alt>
</alt>
<alt xml:lang="fr">
<alt genre="gospel">catholique</alt>
</alt>
</genre>
答案 0 :(得分:4)
您需要在xpath中使用完整的QName,因为stdlib ElementTree没有注册前缀的方法。我通常使用辅助函数来创建QNames:
def qname(prefix, element, map={'xml':'http://www.w3.org/XML/1998/namespace'}):
return "{{{}}}{}".format(map[prefix], element)
标准库中的ElementTree
实现不支持足够的XPath来轻松完成您想要的操作。但是,spec for xml:lang
指定此属性的值由包含它的所有内容继承,类似于xml:base
或xmlns
命名空间声明。因此,作为替代方案,我们可以在所有元素上明确语言设置:
xml_lang = qname('xml', 'lang')
def set_xml_lang(root, defaultlang=''):
xml_lang = qname('xml', 'lang')
for item in root:
try:
lang = item.attrib[xml_lang]
except KeyError, err:
item.set(xml_lang, defaultlang)
lang = defaultlang
set_xml_lang(item, lang)
set_xml_lang(root)
namespaces = {'xml':'http://www.w3.org/XML/1998/namespace'}
# Every element in root now has an xml:lang attribute
# so XPath is easy now:
alts_with_no_lang = root.findall('alt[@{{{xml}}}lang=""]'.format(**namespaces))
如果您愿意使用lxml
,那么您对“lang”的使用会更加强大,因为它遵循完整的XPath 1.0规范。特别是,您可以使用lang()
函数:
import lxml.etree as ET
root = ET.fromstring(xml)
print root.xpath('//alt[lang("fr")]')
作为奖励,它将具有正确的lang()
语义,例如不区分大小写并且对语言区域很聪明(例如lang('en')
也适用于xml:lang="en-US"
。
很遗憾,您无法使用lang()
来确定节点的语言。您需要找到第一个xml:lang
祖先并使用它:
mylang = node.xpath('(ancestor-or-self::*/@xml:lang)[1]')
全部放在一起,以匹配没有语言的节点:
tree.xpath('//alt[not((ancestor-or-self::*/@xml:lang)[1])]')
答案 1 :(得分:1)
我真的不明白为什么我不能使用xml:lang而不是{http://www.w3.org/XML/1998/namespace}lang,但上面的内容似乎适用于Ubuntu 12.04
使用xpath
方法(cElementTree
中 not )可以更轻松地尝试做什么,其中包括从import lxml.etree as et
root = et.parse(open('mydoc.xml')).getroot()
for x in root.xpath('alt[not(@xml:lang)]/alt'):
print x.text
中读取命名空间标签文档的根元素,所以你可以这样问:
not(@attr)
我以前不熟悉的{{1}}语法,但Google搜索“xpath find element without attribute”非常有用。