延迟树

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 迭代器族在返回节点之前将其从父节点中删除。如果循环体没有在其他地方保留对子节点的引用,它将在下一次迭代开始时立即有资格进行垃圾回收。参见 ConsumingXml

虽然目前尚未实现,但其他消耗形式可能会与 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?

注意事项

对尚未完全加载的延迟树调用正常的 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)

lxpeventevent_source 中返回一个延迟解析的树。

lazytree.load(tree)

强制读取 tree 的所有内容。在非延迟树上调用此方法是安全的。

lazytree.consume(tree)

指示不再需要 tree 并且可以销毁。tree 可以是延迟树或传统树,并且应该是对它的最后一个引用。

虽然目前尚未实现,但对正在构建的延迟树部分调用 consume 可以告诉延迟解析器不要费心填充树的该部分。这不是一个通用的用户工具;相反,它是一个原始工具,可以由消耗过滤迭代器(如 xmliter.switch)使用,当它们注意到它们遇到的树将被跳过并且在应用程序中没有可见性时。

lazytree.lazyprint(tree)

在不进行进一步解析的情况下打印延迟树的当前内容。对演示目的很有用。

实现细节

给定以下 XML

<paragraph justify='centered'>first child<b>bold</b>second child</paragraph> 
延迟树将显示具有以下内容

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 (差异)