1

我目前必须修复现有应用程序以使用libxml2的DOM 接口以外的其他东西,因为事实证明它传递的 XML 文件太大以至于无法加载到内存中。

我已经重写了数据加载,从遍历 DOM 树到现在大部分都使用xmlTextReader,没有太多问题。(我xmlNewTextReaderFilename用来打开本地文件。)

然而事实证明,大数据所在的子树必须不按顺序读取,但我必须先收集一些(少量)数据。(而问题正是这个子树包含大量数据,因此仅将这个子树加载到内存中也没有多大意义。)

最简单的方法是“克隆”/“复制”我当前的阅读器,提前阅读,然后返回到原始实例继续阅读。(似乎我不是第一个......甚至在 C# 端实现了一些东西:XML Reader with Bookmarks。)

但是似乎没有任何方法可以“复制” xmlTextReader 的状态。

如果我不能重新读取文件的一部分,我也可以重新读取整个文件,虽然很浪费,但在这里还可以,但我仍然需要记住我之前在哪里?

是否有一种简单的方法可以记住 xmlTextReader 它在当前文档中的位置,以便我以后可以在第二次读取文档/文件时再次找到该位置?

这是一个问题示例:

<root>
  <cat1>
    <data attrib="x1">
      ... here goes up to one GB in stuff ...
    </data>
    <data attrib="y2"> <!-- <<< Want to remember this position without having to re-read the stuff before -->
      ... even more stuff ...
    </data>
    <data attrib="z3">
       <!-- I need (part of) the data here to meaningfully interpret the data in [y2] that 
            came before. The best approach would seem to first skip all that data
            and then start back there at <data attrib="y2"> ... not having to re-read
            the whole [x1] data would be a big plus! -->
    </data>
  </cat1>
  ...
</root>
4

1 回答 1

1

我想根据我在 XML 邮件列表中学到的内容给出一个解决方法:

没有简单的方法可以“克隆” xmlReader 上的状态,但是应该可能并且也应该很容易的是计算对文档所做的读取。

也就是说,要使用 xmlReader 读取文档,您可能必须调用以下命令:

// looping ...
status = ::xmlTextReaderRead(pReader);

如果您以结构化的方式执行此操作(例如,我最终编写了一个小包装类来封装我对 xmlReader 的使用模式),那么添加一个计数器相对容易:

// looping ...
status = ::xmlTextReaderRead(pReader);
if (1 == status) { // success
  ++m_ReadCounter;
}

对于重新阅读文档(到达某个位置),您只需调用xmlTextReaderRead多次m_ReadCounter,丢弃结果,直到您到达要重新开始的位置。

是的,您必须重新解析整个文档,但这可能已经足够快了。(实际上可能比缓存文档的很大一部分更好/更快。)

于 2013-04-04T11:42:14.823 回答