我正在定義一個我自己的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的這個解決方案是:
- 在從流中每次讀一個字符是緩慢的。
- 這暗示了薩克斯流類如何讀取文本。
這解決了我的問題,但我仍然對更漂亮的解決方案感興趣。
我知道這不是您現在採用的方法,但XSLT允許您使用document()函數從外部源創建。因此,您可以通過XSLT樣式表解析XML來創建一個複合XML文檔,從而避免在Python端創建自己的新宏語言。 –
2010-10-10 22:18:49
這聽起來很有趣,但我必須弄清楚什麼python xml解析庫支持這一點。 – 2010-10-11 10:15:22