我能否告诉SAX解析器在某个元素处停止并将其子节点作为字符串获取?

3 投票
4 回答
2239 浏览
提问于 2025-04-17 09:36

我有一些比较大的XML文档,所以我不想用DOM来处理。不过在用SAX解析器解析文档时,我想在某个点停下来(比如说当我遇到一个特定名称的元素时),然后把那个元素里面的所有内容作为字符串获取。“所有内容”不一定是文本节点,它可能包含标签,但我不想解析这些标签,我只想把它们当作文本获取。

我是在用Python写代码。这个问题能解决吗?谢谢!

4 个回答

0

这里有一种比较“hack”的方法,可以使用SAX来实现。这种方法可以保留你文本节点中的内容。不过,如果你还想保留那些文本节点里的标签和属性,那就会变得更复杂了。

from xml.sax import handler, make_parser

class CustomContentHandler(handler.ContentHandler):

    def __init__(self):
        handler.ContentHandler.__init__(self)
        self.inside_text_tag = False
        self.text_content = []

    def startElement(self, name, attrs):
        if name == 'text':
            self.inside_text_tag = True

    def endElement(self, name):
        if name == 'text':
            self.inside_text_tag = False
            self.text = ''.join(self.text_content)
            print "%s" % (self.text)

    def characters(self, content):        
        if self.inside_text_tag:
            self.text_content.append(content)

def parse_file(filename):
    f = open(filename)
    parser = make_parser()
    ch = CustomContentHandler()
    parser.setContentHandler(ch)
    parser.parse(f)
    f.close()

if __name__ == "__main__":
    filename = "sample.xml"
    parse_file(filename)

这个方法是针对下面这个sample.xml文件使用的:

<tag1>
  <tag2>
    <title>XML</title>
    <text>
      Text001
      <h1>Header</h1>
      Text002
      <b>Text003</b>
    </text>
  </tag2>
</tag1>

执行后会得到

Text001
Header
Text002
Text003
1

我觉得用 xml.sax 是不太可能做到这个的。BeautifulSoup 有个叫 SoupStrainer 的功能,正好可以实现这个。如果你愿意使用这个库,它其实很简单上手。

2

看起来在 xml.sax 这个API里没有提供直接的方法来中断控制流程,但你可以用另一种方式来实现:那就是使用异常。

你只需要定义一个自定义的异常来达到这个目的:

class FinishedParsing(Exception):
    pass

当你完成解析时,在你的处理函数里抛出这个异常,然后就可以忽略它了。

try:
    parser.parse(xml)
except FinishedParsing:
    pass

撰写回答