2012-03-08 81 views
0

解析空白XML標記時,格式爲XML文檔解析:與LXML和Python

<Car> 
    <Color>Blue</Color> 
    <Make>Chevy</Make> 
    <Model>Camaro</Model> 
</Car> 

我使用下面的代碼:

carData = element.xpath('//Root/Foo/Bar/Car/node()[text()]') 
parsedCarData = [{field.tag: field.text for field in carData} for action in carData] 
print parsedCarData[0]['Color'] #Blue 

此代碼不會,如果一個標籤是空的工作如:

<Car> 
    <Color>Blue</Color> 
    <Make>Chevy</Make> 
    <Model/> 
</Car> 

使用相同的代碼如上:

carData = element.xpath('//Root/Foo/Bar/Car/node()[text()]') 
parsedCarData = [{field.tag: field.text for field in carData} for action in carData] 
print parsedCarData[0]['Model'] #Key Error 

我該如何解析這個空白標記。

回答

3

你在[text()]過濾器僅其中明確要求對於具有文本節點元素把他們...然後你不高興時,它不給你沒有文字節點的元素?

離開過濾掉,你會得到你的模型元素:

>>> s=''' 
... <root> 
... <Car> 
...  <Color>Blue</Color> 
...  <Make>Chevy</Make> 
...  <Model/> 
... </Car> 
... </root>''' 
>>> e = lxml.etree.fromstring(s) 
>>> carData = e.xpath('Car/node()') 
>>> carData 
[<Element Color at 0x23a5460>, <Element Make at 0x23a54b0>, <Element Model at 0x23a5500>] 
>>> dict(((e.tag, e.text) for e in carData)) 
{'Color': 'Blue', 'Make': 'Chevy', 'Model': None} 

那說 - 如果你的近期目標是遍歷樹的節點,可以考慮使用lxml.etree.iterparse()相反,這將避免嘗試在內存中構建完整的DOM樹,否則將比構建樹並使用XPath迭代它更有效。 (想想SAX,但沒有瘋狂和痛苦的API)。

iterparse實施看起來是這樣的:

def get_cars(infile): 
    in_car = False 
    current_car = {} 
    for (event, element) in lxml.etree.iterparse(infile, events=('start', 'end')): 
     if event == 'start': 
      if element.tag == 'Car': 
       in_car = True 
       current_car = {} 
      continue 
     if not in_car: continue 
     if element.tag == 'Car': 
      yield current_car 
      continue 
     current_car[element.tag] = element.text 

for car in get_cars(infile = cStringIO.StringIO('''<root><Car><Color>Blue</Color><Make>Chevy</Make><Model/></Car></root>''')): 
    print car 

...這是更多的代碼,但(如果我們不使用StringIO的的例子),它可以處理除了可以適應更大的文件記憶。

+0

現在我正在做一個'element = etree.parse(xmlfile)'。 iterparse如何改變我現有的代碼庫? – lodkkx 2012-03-08 15:39:50

+1

@lodkkx使用iterparse如下所示:lxml.etree.iterparse(xmlfile):...中的for(event_type,element):決定每個元素依次執行什麼操作(通常是通過檢查其標記)。 – 2012-03-08 15:46:52

1

我不知道里面有LXML建立了一個更好的解決方案,但你可以只使用.get()

print parsedCarData[0].get('Model', '') 
-1

解決方案:使用try/except塊來捕捉關鍵錯誤。

+0

錯誤只發生在第一位,因爲他沒有文字過濾掉元素。爲什麼要避開它,在過程中縮短代碼? – 2012-03-08 15:58:17

+0

@CharlesDuffy我認爲OP有這樣做的一些理由,也許他正在使用其他地方創建的數據結構。 – Marcin 2012-03-08 16:00:35

+0

是的,但結構很好 - 這是他用來檢索部分結構的過濾器,而這部分顯然是他的代碼。 – 2012-03-08 16:48:52

0

我捕捉到了異常:

try: 
    print parsedCarData[0]['Model'] 
except KeyError: 
    print 'No model specified' 

異常在Python是不是在同一意義非凡在其他語言中,在那裏它們被更嚴格地鏈接到錯誤條件。相反,它們通常是設計中正常使用模塊的一部分。例如,一個迭代器引發StopIteration來表示它已經達到迭代的結束。

編輯:如果你確定只有這個項目可以是空的@CharlesDuffy有它的權利,因爲使用get()可能更好。但總的來說,我會考慮使用異常來輕鬆處理各種異常輸出。

+0

使用'parsedCarModel [0] .get('Model')'來避免異常(在未找到的情況下返回'None')比提升和處理異常更短更快......儘管我認爲這是當從XPath查詢中移除不必要的限制時,很愚蠢的做法首先會導致這個問題。 – 2012-03-08 15:59:47

+0

@CharlesDuffy:沒錯,但我認爲這種方法有很多優點。我通常使用try/except塊來包裝行,我在其中幾個關於輸入的幾個假設。在這種情況下,使用異常似乎比改變每一行更自然。另外,通常你必須用無論如何處理None。 – 2012-03-08 16:08:13