我正在尝试使用 python 的 sax 库获取子标签的名称。我使用 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;
假设我只知道 parent 的名字,如何获取字符串“child1”和“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 解析器更快,占用的内存更少,这在十年前很重要,但现代处理器上的差距要小得多,尤其是在小文档上。程序员的时间更有值(value)。
