【问题标题】:Depth First Reading of large XML Files大型 XML 文件的深度优先读取
【发布时间】:2012-09-19 12:39:27
【问题描述】:

我需要处理一堆非常大的 XML 文件并深度优先读取每个元素。由于大小的原因,任何DOM 解决方案都是毫无疑问的,而且由于实际需要的元素不是“叶子”而是它的父元素,事情变得更加复杂。

更具体地说,文件的结构类似于

    <Level 1>
        ...
        <Level 2>
            ...
            <Level N-1>
                <value>...</value>
                <value>...</value>
                ...
                <value>...</value>
            </Level N-1>
            <Level N-1>
                <value>...</value>
                <value>...</value>
                ...
                <value>...</value>
            </Level N-1>
            ...
            <Level N-1>
                <value>...</value>
                <value>...</value>
                ...
                <value>...</value>
            </Level N-1>
            ...
        </Level 2>
    </Level 1>

在上述每个文件中,&lt;Level N-1&gt; 元素需要单独读取(每个都包括所有对应的&lt;value&gt; 元素)。深度,N,在每个文件中和文件之间都不同,所以它本质上是未知的,XML 标记名称也是如此。由于&lt;value&gt; 元素也存在于更高级别(即,它们不能保证已达到Level N),事情变得更加复杂。

在特定深度以字符串形式读取整个 XML 元素的快速解决方案类似于

int level = 0;  // The base level of the element, could be at any depth
Reader in = ... // The reader to the input
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
PrintStream out = new PrintStream(outStream);
XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(in);
XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(out);
XMLEvent event;

while ((level > 0) && reader.hasNext());
{
    event = reader.nextEvent();

    if (event.isStartElement())
    {
        level++;
    }
    else if (event.isEndElement())
    {
        level--;
    }

    writer.add(event);
}

writer.flush();

String element = new String(outStream.toByteArray());

但是,如果调用代码不知道已到达 Level N-1 元素并前进到 Level N(即到 &lt;value&gt; 元素),则上述内容没有帮助。

SAX 解决方案是理想的,但即使通过 XSLT 模板预处理文件也是可以接受的。

有什么想法吗?

【问题讨论】:

  • 你能稍微澄清一下需求吗,也许有一个示例输入和所需的输出?
  • 上面的数据描述没什么可补充的,只是标签名称会改变。本质上,这个想法是将每个 Level-1 标记处的所有 元素组合在一起。

标签: xml xslt sax depth-first-search


【解决方案1】:

所需的 XSLT 预处理在纯 XSLT 1.0 或 XSLT 2.0 中是不可能的,因为 XSLT 处理器(1.0 或 2.0)通常会在内存中生成整个 XML 文档的表示(不一定是 DOM)。

XSLT 3.0(仍然是 WD)中,流将作为语言的一部分,但 W3C XSLT WG 仍在积极开发中,规范还不稳定。

Saxon 有 streaming extensions 形式为处于“可流式传输模式”的流式模板:

<xsl:mode name="s" streamable="yes"/>

使用它可以生成 XML 文档,每个文档只包含以“N-1 级”元素为根的子树。

【讨论】:

  • 好吧,XSLT 意味着预处理,所以它不是这里的最佳选择。但即使是这样,考虑到您的顶级 XSLT 技能,我从上面的描述中假设没有办法做到这一点。不过谢谢你的回答! :-)
  • @PNS,如果您使用 Saxon 的流媒体扩展程序,今天就可以完成。任何 XSLT 3.0 流处理器都可以在一年内完成。
【解决方案2】:

如果我正确理解了您的问题,那么当您到达 &lt;value&gt; 标记并完成关卡标记时,您将难以区分

当您识别出一个事件时,您可以从中获取更多信息,例如名称:

  if (event.isStartElement()) {
    StartElement element = (StartElement) event;
    System.out.println("Start Element: " + element.getName());
  }

如果你真正想要的是之前的最后一关,那你当然要坚持下去。

【讨论】:

  • 当然可以,但问题是我需要读取整个 标记,而仅读取 元素并不能保证已达到
猜你喜欢
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多