我正在定义一个我自己的 xml 模式,它支持附加标签“insert_tag”,当达到该标签时应该在流中的那个点插入文本文件,然后继续解析:
这是一个例子:
我的.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
此类创建一个流结构,限制返回给流用户的字符数量。 IE。即使 xml 解析器确实读取(16386),该类也只会返回下一个“>”字符之前的字节。由于 '>' 字符也表示标记的结束,因此我们有机会在此时将我们的递归包含注入(inject)到流中。
这个解决方案有以下问题:
- 从流中一次读取一个字符很慢。
- 这有一个关于 sax 流类如何读取文本的隐式假设。
这解决了我的问题,但我仍然对更漂亮的解决方案感兴趣。
请您参考如下方法:
