我正在定义一个我自己的xml架构,它支持附加标签“insert_tag”,到达时应该在流中的那一点插入文本文件,然后继续解析:
以下是一个例子:
my.xml:
<xml>
Something
<insert_file name="foo.html"/>
or another
</xml>
我正在使用xmlreader
,如下所示:
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解析器读取缓冲的流。
更新
我确实找到了最好的解决方案。它基于以下流类构建:
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),该类也只会返回字节,直到下一个'&gt;'字符。由于'&gt;'字符也表示标记的结束,我们有机会在此时将我们的递归包含注入流中。
这个解决方案的主要内容如下:
这解决了我的问题,但我仍然对一个更美丽的解决方案感兴趣。