关于python:解析XML时如何支持递归include

How to support recursive include when parsing xml

我正在定义自己的XML模式,该模式支持附加的标记"insert_tag",当到达时,该标记应在流中的该点插入文本文件,然后继续分析:

下面是一个例子:

My.XML:



Something

or another

我使用xmlreader如下:

1
2
3
4
5
6
7
8
9
 class HtmlHandler(xml.sax.handler.ContentHandler):

    def __init__(self):
        xml.sax.handler.ContentHandler.__init__(self)

 parser = xml.sax.make_parser()
 parser.setContentHandle(HtmlHandler())

 parser.parse(StringIO(html))

问题是如何将包含的内容直接插入解析流中?当然,我可以通过重复插入包含的文本来递归地构建非插入文本,但这意味着我必须多次解析XML。

我尝试用自己的流替换Stringio(HTML),该流允许在流中间插入内容,但它不起作用,因为SAX解析器读取缓冲的流。

更新:

我确实找到了一个最简单的解决方案。它建立在以下流类上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class InsertReader():
   """A reader class that supports the concept of pushing another
    reader in the middle of the use of a first reader. This may
    be used for supporting insertion commands."""

    def __init__(self):
        self.reader_stack = []

    def push(self,reader):
        self.reader_stack += [reader]

    def pop(self):
        self.reader_stack.pop()

    def __iter__(self):
        return self

    def read(self,n=-1):
       """Read from the top most stack element. Never trancends elements.
        Should it?

        The code below is a hack. It feeds only a single token back to
        the reader.
       """

        while len(self.reader_stack)>0:
            # Return a single token
            ret_text = StringIO()
            state = 0
            while 1:
                c = self.reader_stack[-1].read(1)
                if c=='':
                    break

                ret_text.write(c)
                if c=='>':
                    break

            ret_text = ret_text.getvalue()
            if ret_text == '':
                self.reader_stack.pop()
                continue
            return ret_text
        return ''

    def next(self):
        while len(self.reader_stack)>0:
            try:
                v = self.reader_stack[-1].next()
            except StopIteration:
                self.reader_stack.pop()
                continue
            return v
        raise StopIteration

此类创建一个流结构,该结构限制返回给流用户的字符数。也就是说,即使XML解析器读取(16386),类也只返回到下一个">"字符的字节。由于">"字符也表示标记的结束,因此我们有机会在此时将递归include注入到流中。

这个解决方案的黑客行为如下:

  • 从流中一次读取一个字符很慢。
  • 这有一个关于SAX流类如何读取文本的隐式假设。

这为我解决了问题,但我仍然对更漂亮的解决方案感兴趣。


你是否考虑过使用xinclude?LXML库对它有内置的支持。