2010-10-10 91 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