我正在尝试使用python的sax库获取children标记的名称。我使用ContentHandler作为处理程序。有人知道如何获得标签名称吗?
让我们假设我们的xml文档看起来像:
<root>
<parent>
<child1>X</child1>
<child2>Y</child2>
</parent>
</root>
让我们假设我们使用处理程序的模板:
class parserSAXHandler(handler.ContentHandler):
def __init__(self):
pass;
def startElement(self, name, attrs):
pass;
def endElement(self,name):
pass;
def characters(self, content):
pass;
假设我只知道父项的名称,我如何获得字符串"child1"one_answers"child2"?
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解析器更快,占用的内存更少,但在现代处理器上,尤其是在小文档上,差距要小得多。程序员的时间更有价值。