2013-01-09 40 views
4

我正在使用python 2.7並試圖解析下面的XML - 我試圖做的是創建一個具有語言屬性的所有流派的python數組用沒有語言屬性的數組。我如何找到沒有屬性的xml節點

我使用Python模塊import xml.etree.cElementTree as ET

我知道我能找到的XML部分,其中的語言屬性通過語法中的「FR」語言:

 

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

我試圖找出是「不」的語法 - 其中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> 

回答

4

您需要在xpath中使用完整的QName,因爲stdlib ElementTree沒有註冊前綴的方法。我通常使用一個輔助函數來創建的QName:

def qname(prefix, element, map={'xml':'http://www.w3.org/XML/1998/namespace'}): 
    return "{{{}}}{}".format(map[prefix], element) 

標準庫的ElementTree實現不支持足夠的XPath做你想要什麼輕鬆。但是,spec for xml:lang指定此屬性的值由包含它的所有內容繼承,有點像​​或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,你的「郎」的使用可以更加健壯,因爲它遵循了完整的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])]') 
+0

輝煌的解釋 - 非常感謝! – fossfreedom

1

我真的不明白,爲什麼我不能使用XML:郎而不是{http://www.w3.org/XML/1998/namespace}lang,但上述似乎工作的Ubuntu的12.04

你正在嘗試做將使用xpath方法(這是cElementTree不可),其中除其他事項外將讀取你的文檔的根元素的命名空間標籤更容易,所以你可以這樣問:

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)語法我之前並不熟悉,但Google搜索「xpath find element without attribute」非常有用。