Lazy Tree

lua-users home
wiki

lazytree:惰性地建立 XML 樹狀結構

(此為 LazyKit 的一部分。)

LazyTree 在引用其內容時會建立一個傳統的外觀 XmlTree,並剖析更多原始文件以填補必要內容並依需求填入。

這有什麼有趣之處?樹狀結構是處理 XML 文件的自然數據模型。但簡單的樹狀結構實作會同時將整個文件讀入記憶體。對於大型文件,這可能會太花費資源。雖然回呼和事件 API 在使用記憶體時很有效,但編寫程式會很痛苦。

給定樣式化的反覆運算元,記憶體使用量就可以限制在特定子樹內。請思考一下

for i,child in xnpairs_c(tree) do
  if child.attr.href then 
    print(child.name)
    table.insert(references, child)
  end
end 

在這樣的狀況中,_c 家族的反覆運算元會在回傳其父節點之前將其設為 nil。如果迴圈的主體沒有在其他地方保留對下層節點的參照,便會在下一個運算開始時符合垃圾回收條件。請參閱 ConsumingXml

即使目前尚未實作,其他 consuming 形式可能會與 XML 剖析器互動,以節省更多資源

<document>
  <firstname>Jay</firstname>
  <lastname>Carlson</lastname>
  <bodytext>Spending too much time listening to <ref>In Utero</ref> can be [...]
  <title>I Think I'm DOM</title> 
lastname, title = xmlextract.strings_consume(tree, "lastname", "title") 
strings_consume 篩選器理論上可以停用它知道不需要的任何節點(例如 bodytext)內的所有字元資料和事件,因為對這些節點的參照不可能影響到程式的其他部分。

相依性

lazytree 相依於 lxpevent 以產生事件佇列,而 lxpevent 相依於 LuaExpat?

注意事項

對尚未完全載入的 lazytree 呼叫一般 ipairs 反覆運算元並不會執行,因為 ipairs(lz) 沒有直接參照 lz.n。請使用 XmlIter 反覆運算元 xpairs{_c} 和 xnpairs{_c};後者的使用更方便。請參閱 XmlIter

用法

lazytree.parsestring(s)

從字串 s 惰性地剖析並回傳樹狀結構。

lazytree.parsefile(file)

file 惰性地剖析並回傳樹狀結構。如果 file 是字串,系統會將之解譯為檔名並開啟;如果不是,則會將 file 視為 io 函式庫的檔案物件。

lazytree.parseevents(event_source)

lxpevent event_source 惰性地剖析並回傳樹狀結構。

lazytree.load(tree)

強制讀取 tree 的所有內容。即使對非 lazy 樹狀結構呼叫此函式,也是安全的。

lazytree.consume(tree)

表示不再需要 tree,而且可以將其刪除。tree 可以是 lazytree 也可以是一般的樹狀結構,而且應該是對其執行的最後一次參照。

雖然目前尚未實作,針對目前正在建立的 lazytree 部分呼叫 consume,可以告訴 lazy parser 不必費心填入樹的該部分。這不是作為一般使用者的工具,而是當消費型過濾反覆器(例如 xmliter.switch)注意到他們遭遇到的樹將會被略過,且在應用程式中不可見時,可以使用的一個基本元件。

lazytree.lazyprint(tree)

印出 lazytree 的目前內容而不進行進一步的剖析。這有助於示範。

實作細節

給定下列 XML

<paragraph justify='centered'>first child<b>bold</b>second child</paragraph> 
lazytree 將顯示下列內容

lz = {name="paragraph", attr={justify="centered"}, 
  "first child", 
  {name="b", "bold", n=1},
  "second child",
  n=3
} 
然而,在剖析開始時,實際的基本表格將包含

lz = {name="paragraph", attr={justify="centered"}, 
  _read_so_far=0
} 
在參考 lz[1] 之後,它將包含

lz = {name="paragraph", attr={justify="centered"}, 
  "first child",
  _read_so_far=1
} 
在參考 lz[2] 之後

lz = {name="paragraph", attr={justify="centered"}, 
  "first child",
  {name="b", _read_so_far=0}
} 
請注意,子項目也會延遲讀取。然而,對 lz[3] 的參考將強制完成所有 lz[2]

lz = {name="paragraph", attr={justify="centered"}, 
  "first child",
  {name="b", "bold", n=1}
  "second child",
  _read_so_far=3
} 
讀取 lz[4] (它是 nil)或 lz.n 都會強制完成樹。

請注意,從 lz.n 讀取會強制讀取樹的剩餘部分,因為我們不知道樹會持續多長直到結束。


最新異動 · 喜好設定
編輯 · 歷程
最後編輯於 2004 年 2 月 29 日上午 12:33 GMT (diff)