Xml Iter |
|
(這是 LazyKit 的一部分。)
這個套件提供許多工具來重複 XmlTree 的子元素。
傳回 tree
的屬性之迭代器,傳回屬性名稱和值。請注意,這只會傳回字串類型的金鑰。(LuaExpat? 使用數值金鑰來標記從 DTD 預設的屬性。)
計算 tree
的子元素數量;大致等同於 table.getn
。這是必要的,因為 table.getn(tree)
沒有明確呼叫 tree.n
,而是使用 rawget(tree, "n")
。花俏的樹實作可能需要使用 metatable 呼叫來尋找子元素的數量。
傳回 tree
的迭代器,傳回每個索引及子元素。範例
parent = lazytree.parsestring("<p>a<z>cdef</z>b</p>") for i,x in xpairs(parent) do if type(x) == "string" then print("string:", x) else print("tag:", x.name) end end
列印
string: a tag: z string: b
請注意,它不會下降到子元素(因為未列印「cdef」)。
傳回 tree
的迭代器,忽略字元資料元素。它傳回索引、子樹和元素名稱(可以略過)
for i,x in xnpairs(parent) do print("tag:", x.name) end for i,x,name in xnpairs(parent) do print("tag:", name) end
上述任一列印
tag: z
重複 parent
的子元素,使用 ftable
中的函式定義。
在 ftable
中檢索 parent
的每個子元素。對於子元素「<foo/>
」,會呼叫函式 ftable.foo(child, parent)
。(對於字元資料,會呼叫 ftable[""](str, parent)
。)如果找到未知標籤,會呼叫函式 ftable[true](parent, child)
。
如果 ftable 中不存在此類分錄,則忽略子元素(除非設定某些選項)。
如果處理常式傳回 true 值,switch
會停止重複並傳回(可能是不同的)true 值以及任何第二個傳回值。(與消耗互動待定,並可能使用第一個傳回值作為逃離幾層的計數。)
範例
s = '<log><entry time="12:30"/><checkpoint/><entry time="12:35"/></log>' parent = lazytree.parsestring(s) ftable = { entry=function (entry, parent) print (entry.attr.time) end } xmliter.switch(parent, ftable)
列印
12:30 12:35
(請注意,由於我們不關心 parent,因此可以宣告這個函式為「function (entry)
」。)
分錄可以包含巢狀的 ftable
,而不是函式;switch
(或 switch_c
)會以巢狀 ftable 遞迴呼叫。
範例
s = [[ <log> <entry id='0'> <time clock="12:50"/> <msg text="foo"/> <extra/> </entry> </log>]] parent = lazytree.parsestring(s) ftable = { entry={ time=function (time) print (time.attr.clock) end; msg=function (msg) print (msg.attr.text) end; } } xmliter.switch(parent, ftable)
列印
12:50 foo
作為使用巢狀 ftable 的輔助,ftable[0](parent, [previous_parent])
會在處理任何子元素之前呼叫,而 ftable[-1](parent, [previous_parent])
會在處理所有子元素之後呼叫。
parent = lazytree.parsestring(s) ftable = { entry={ [0]=function (entry) print("id ", entry.attr.id) entry.message_txt = "(no message)" entry.time_txt = "(no time)" entry.level_txt = "(no level)" end; time=function (time, entry) entry.time_txt = time.attr.clock end; msg=function (msg, entry) entry.message_txt = msg.attr.text end; [-1]=function (entry) print("message", entry.message_txt, entry.time_txt, entry.level_txt) end; } } xmliter.switch(parent, ftable)
列印
id 0 message foo 12:50 (no level)
這利用了 XML 樹不介意額外的表格分錄(只要避免「n
」、「attr
」和「name
」以及以底線開頭的金鑰即可)。
不過,巢狀表格可能不是表達程式碼最簡潔的方式。寫入前述函式更簡單的方式為
parent = lazytree.parsestring(s) ftable = { entry=function (entry) print("id", entry.attr.id) local v = xmlview.element(entry) local message_txt = "(no message)" local time_txt = "(no time)" local level_txt = "(no level)" if v.time then time_txt = v.time.attr.clock end if v.msg then message_txt = v.msg.attr.text end print("message", message_txt, time_txt, level_txt) end } xmliter.switch(parent, ftable)
任何使用 [0]
和 [-1]
的情況都可以改寫為一個函數,執行 [0]
動作,遞迴呼叫 switch
,並執行 [-1]
動作。
設定 [true]
動作為該 ftable 本身,就可以執行尋找元素的遞迴處理。例如
parent = lazytree.parsefile("xhtml-spec.xml") local count = 0 local ftable ftable = { a=function (a) if a.attr.href then count = count + 1 end -- uncomment to search for <a> elements inside other <a> elements -- xmliter.switch(a, ftable) end } ftable[true] = ftable xmliter.switch(parent, ftable) print(count)
(請注意,我們無法寫成 "local ftable={... switch(ftable)
}",因為 ftable
本身不會在範圍內。)
opts
表格控制各種處理選項。
如果設定了 opts.no_chardata
,任何意外的字元資料(亦即 ftable[""]
項目未處理的)都會導致錯誤。
如果設定了 opts.no_tags
,任何意外的子元素(ftable
未提及或 ftable[true]
項目未處理的)都會導致錯誤。
如果設定了 opts.parent
,它會作為 parent
參數的父節點傳遞給函數。如果 switch
遞迴呼叫時,新的 ftable 包含 [0]
或 [-1]
處理常式,這時會很有用。