SAX 风格的解析器要求您跟踪您需要的所有状态,例如您看到了哪些标签。至少,您需要编写一个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 解析器更快,使用更少的内存,这在十年前很重要,但在现代处理器上差距要小得多,尤其是在小型文档上。程序员的时间更宝贵。