流式XPath评估

16

是否有针对提供的 XML 文档进行 XPath 表达式流式计算的生产就绪库?我的调查表明,大多数现有解决方案在评估 XPath 表达式之前会将整个 DOM 树加载到内存中。


非常感谢,我之前看过你的项目。看起来很有前途。 - nixau
这个主题有一些新信息 - 请看我的答案。 - Dimitre Novatchev
7个回答

4

3

考虑到XPath语法允许以下内容,这是否适用于完整的XPath实现:

/AAA/XXX/following::*

并且

/AAA/BBB/following-sibling::*

这意味着需要向前查看的要求?也就是说,从特定节点开始,您将不得不加载整个文档。

Nux库的文档(特别是StreamingPathFilter)指出了这一点,并引用了一些依赖于XPath的子集的实现。Nux声称执行一些流查询功能,但考虑到上述限制,XPath实现方面会有一些限制。


实际上,我需要执行简单的XPath查询,以便验证给定XML文档中的多个节点。 XML文档表示一个实体,其中一些节点存储到其他实体的外键。因此,对这些特殊节点应该应用某种完整性验证。整个文档相当大,将这么多数据存储在内存中以执行几个简单的XPath查询效率很低。 - nixau
1
看起来 Nux 库可能能够在这种情况下帮助您。或者,您可以使用 Stax 库,并将 XPath 应用于从特定节点提取的本地 XML 文档? - Brian Agnew
实际上,我不能采用第二种方法,因为XML文档的结构相对简单,从文档中剥离某个节点并对其应用XPath表达式是没有意义的。 - nixau
我想现在尝试一下XOM。@Brian谢谢你的建议,我很感激。 - nixau

3

有几个选择:

  • DataDirect Technologies出售一种XQuery实现,采用投影和流式处理,可以处理多达数GB的文件 - 例如比可用内存更大。它是一个线程安全库,易于集成。仅限Java。

  • Saxon是一个开源版本,还有一个价格适中的更昂贵的版本,在某些情况下可以进行流式处理。 Java,但也有 .net 版本。

  • MarkLogiceXist是XML数据库,如果您的XML已加载到其中,将以相当智能的方式处理XPaths。


1

1

虽然我没有实际经验,但我觉得值得提一下 QuiXProc(http://code.google.com/p/quixproc/)。它是一种流式处理 XProc 的方法,使用提供 XPath 流支持等库。


0

顺便说一下,我已经使用了Nux流过滤器xpath查询来处理非常大的(> 3GB)文件,它既可以完美地工作,又几乎不占用内存。我的用例略有不同(不是验证为中心),但我强烈鼓励您尝试使用Nux。


0

我想我会选择自定义代码。如果只想读取xml文档的一些路径,.NET库可以让我们接近目标。

由于迄今为止我看到的所有解决方案都只尊重XPath子集,因此这也是这种类型的解决方案。不过,子集确实非常小。 :)

这段C#代码读取xml文件并计算给定显式路径的节点数。您还可以轻松操作属性,使用xr["attrName"]语法。

  int c = 0;
  var r = new System.IO.StreamReader(asArgs[1]);
  var se = new System.Xml.XmlReaderSettings();
  var xr = System.Xml.XmlReader.Create(r, se);
  var lstPath = new System.Collections.Generic.List<String>();
  var sbPath = new System.Text.StringBuilder();
  while (xr.Read()) {
    //Console.WriteLine("type " + xr.NodeType);
    if (xr.NodeType == System.Xml.XmlNodeType.Element) {
      lstPath.Add(xr.Name);
    }

    // It takes some time. If 1 unit is time needed for parsing the file,
    // then this takes about 1.0.
    sbPath.Clear();
    foreach(object n in lstPath) {
      sbPath.Append('/');
      sbPath.Append(n);
    }
    // This takes about 0.6 time units.
    string sPath = sbPath.ToString();

    if (xr.NodeType == System.Xml.XmlNodeType.EndElement
        || xr.IsEmptyElement) {
      if (xr.Name == "someElement" && lstPath[0] == "main")
        c++;
      // And test simple XPath explicitly:
      // if (sPath == "/main/someElement")
    }

    if (xr.NodeType == System.Xml.XmlNodeType.EndElement
        || xr.IsEmptyElement) {
      lstPath.RemoveAt(lstPath.Count - 1);
    }
  }
  xr.Close();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接