SAX風格的解析器要求你保持你所需要的所有狀態,如哪些標籤,你見過的軌道。在nminimum,你需要做的是寫一個startElement()
處理程序設置一個標誌,當它看到一個<parent>
標籤和endElement()
掃清當它看到結束標記標誌。當該標誌被設置時,startElement()
處理程序也需要累積它在列表中看到的標籤。
class parserSAXHandler(handler.ContentHandler):
def __init__(self):
self.parentflag = False
self.childlist = []
def startElement(self, name, attrs):
if name == "parent":
self.parentflag = True
elif self.parentflag:
self.childlist.append(name)
def endElement(self,name):
if name == "parent":
self.parentflag = False
解析後,該實例的childlist
屬性將有你想要的清單。
如果可以將其他標記嵌套在<child>
標記和不需要需要這些標記名稱內,則可能需要更復雜的邏輯。實際上,包含任何級別的嵌套在<parent>
容器內的任何標籤都包含在內。跟蹤嵌套的最簡單的方法可能是用棧:推動各開放標籤,彈出每個關閉標籤,然後你可以檢查,看看是否parent
是在堆棧的頂部。
class parserSAXHandler(handler.ContentHandler):
def __init__(self):
self.tagstack = []
self.childlist = []
def startElement(self, name, attrs):
if self.tagstack[-1] == "parent":
self.childlist.append(name)
self.tagstack.append(name)
def endElement(self,name):
if name == self.tagstack[-1]:
self.tagstack.pop()
else:
raise SAXParseException("tag closed without being open")
一個DOM式解析器,如xml.dom.minidom
或lxml
,是一個更容易爲這些類型的任務的工作,因爲它會跟蹤你的元素之間的關係。這樣的解析器可能是你需要一個更好的選擇:
from xml.dom.minidom import parseString
xml = """
<root>
<parent>
<child1>X</child1>
<child2>Y</child2>
</parent>
</root>
"""
dom = parseString(xml)
children = [c.localName for p in dom.getElementsByTagName("parent")
for c in p.childNodes if c.nodeType == c.ELEMENT_NODE]
你會發現,一旦minidom
模塊解析我們的XML,你的查詢是單一的Python聲明(其中包含兩個過程循環, ,但這是一個單一的聲明)。用SAX風格的解析器不能真正達到這種簡潔程度。
現在,SAX風格的解析器運行速度更快,比DOM解析器,這在十年前是重要的內存更少,但差距是非常小的現代處理器,尤其是在短小的文件。程序員的時間更有價值。