Xml Iter

lua-users home
wiki

xmliter:重複 Xml 樹

(這是 LazyKit 的一部分。)

這個套件提供許多工具來重複 XmlTree 的子元素。

xattrpairs(tree)

傳回 tree 的屬性之迭代器,傳回屬性名稱和值。請注意,這只會傳回字串類型的金鑰。(LuaExpat? 使用數值金鑰來標記從 DTD 預設的屬性。)

xmliter.getn(tree)

計算 tree 的子元素數量;大致等同於 table.getn。這是必要的,因為 table.getn(tree) 沒有明確呼叫 tree.n,而是使用 rawget(tree, "n")。花俏的樹實作可能需要使用 metatable 呼叫來尋找子元素的數量。

xpairs(tree)

傳回 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」)。

xnpairs(tree)

傳回 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 

一般濾出

xmliter.switch(parent, ftable, [opts])

重複 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] 處理常式,這時會很有用。


最近變更 · 喜好設定
編輯 · 歷史記錄
最後編輯時間為 2004 年 2 月 29 日 上午 12:30 GMT (差異)