2

我需要处理一堆非常大的 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>

在上述每个文件中,<Level N-1>需要单独读取元素(每个都包括所有相应的<value>元素)。深度 ,N在每个文件中和文件之间都不同,因此它本质上是未知的,XML标签名称也是如此。<value>由于元素也存在于更高级别(即,它们不构成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(即,到<value>元素),则上述内容没有帮助。

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

有任何想法吗?

4

2 回答 2

3

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

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

Saxon 具有流模板形式的流扩展,这些模板处于“可流模式”:

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

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

于 2012-09-19T13:03:32.300 回答
1

<value>如果我正确理解了您的问题,那么当您到达标签并完成关卡标签时,您将难以区分

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

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

如果你真正想要的是这之前的最后一个关卡,当然你必须坚持下去。

于 2012-09-19T13:45:36.027 回答