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 系列迭代器在返回节点之前将其从父节点中置空。如果循环体不在其他地方保留对子节点的引用,一旦下一个迭代开始,它将符合垃圾回收的条件。参见 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?

注意事项

对尚未完全加载的 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 的全部内容。对非懒惰树调用此函数是安全的。

lazytree.consume(tree)

指示 tree 不再需要,可以销毁。tree 可以是 lazytree 或常规树,并且应该是对其的最后一个引用。

尽管尚未实现,但对 lazytree 当前正在构建的部分调用 consume 可以告诉懒惰解析器不要去填充该部分树。这并非旨在作为通用的用户工具;相反,它是一个原始工具,可以被消耗性过滤迭代器(如 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 读取将强制读取树的剩余部分,因为我们不知道它会何时关闭。


RecentChanges · preferences
编辑 · 历史
最后编辑于 2004 年 2 月 28 日下午 6:33 GMT (diff)