2010-10-10 47 views
2

我正在定义一个我自己的xml模式,它支持额外的标记“insert_tag”,当它到达时应该在文件流中插入文本文件,然后继续解析:如何在解析xml时支持递归包括

下面是一个例子:

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),允许插入内容中流,但它不工作,因为萨克斯分析器读取缓冲流。

更新:

我没有找到一个解决方案是最好的的hackish。它建立在以下流类别上:

 
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),该类也只会返回字节直到下一个'>'字符。由于'>'字符也表示标签的结束,因此我们有机会在此处将递归包含注入到流中。

什么是hackish的这个解决方案是:

  • 在从流中每次读一个字符是缓慢的。
  • 这暗示了萨克斯流类如何读取文本。

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

+0

我知道这不是您现在采用的方法,但XSLT允许您使用document()函数从外部源创建。因此,您可以通过XSLT样式表解析XML来创建一个复合XML文档,从而避免在Python端创建自己的新宏语言。 – 2010-10-10 22:18:49

+0

这听起来很有趣,但我必须弄清楚什么python xml解析库支持这一点。 – 2010-10-11 10:15:22

回答

1

您是否考虑过使用xincludelxml库已经为它提供内置支持。

+0

谢谢,我会检查出来。我仍然有很多要了解xml。尽管我有两个用例。一个是我上面描述的包含文件。第二个是“宏”的定义和使用。后者是否也可以由xinclude支持? – 2010-10-11 10:10:38

+0

我不确定你对“宏”有什么想法,所以我不确定它是否能被xinclude轻松支持。请注意,xinclude不要求包含的内容实际上是一个“文件”。它可能是由Web服务器动态生成的内容,但您也可以使用“解析器”(请参阅​​lxml文档)在xinclude处理期间请求提供内容。无论这是否适合你的宏,我无法分辨。 – Steven 2010-10-11 11:10:36