How to support recursive include when parsing xml
我正在定义自己的XML模式,该模式支持附加的标记"insert_tag",当到达时,该标记应在流中的该点插入文本文件,然后继续分析:
下面是一个例子:
My.XML:
Something
or another
我使用
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库对它有内置的支持。