Xml Iter |
|
(这是 LazyKit 的一部分。)
此包提供了一系列工具,用于迭代 XmlTree 的子元素。
返回一个迭代器,用于遍历 tree 的属性,返回属性名和值。请注意,这只返回类型为字符串的键。(LuaExpat? 使用数字键来标记从 DTD 默认的属性。)
计算 tree 的子节点数量;大致等同于 table.getn。这是必需的,因为 table.getn(tree) 不会显式调用 tree.n,而是使用 rawget(tree, "n")。复杂的树实现可能需要使用元表调用来查找子节点数量。
返回一个迭代器,用于遍历 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
通过 ftable 中的函数定义来迭代 parent 的子节点。
ftable 中会查找 parent 的每个子节点。对于子节点“<foo/>”,会调用函数 ftable.foo(child, parent)。对于字符数据,会调用 ftable[""](str, parent)。如果找到未知标签,会调用函数 ftable[true](parent, child)。
如果 ftable 中不存在这样的条目,则该子节点将被忽略(除非设置了某些选项)。
如果处理程序返回一个真值,switch 会停止迭代并返回一个(可能不同的)真值以及任何第二个返回值。(与消耗的交互待定,可能使用第一个返回值作为要退出的层数。)
Example
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
(请注意,由于我们不关心父节点,函数可以声明为“function (entry)”。)
条目可以包含嵌套的 ftable 而不是函数;switch(或 switch_c)会使用嵌套的 ftable 递归调用。
Example
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
为了便于使用嵌套的 ftables,在处理任何子节点之前会调用 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] 处理程序时,这很有用。