用于转换大型 XML 文件的内存高效 XSLT

Memory efficient XSLT for transforming large XML files

此问题与 michael.hor257k, which is in-turn related to Dimitre Novatchev有关。

当使用上面提到的答案中的样式表时(michael.hor257k),对于一个大的 XML(大约 60MB,样本 XML 是如下所示),改造成功。

当尝试另一个样式表时,它与 michael.hor257k 的有点不同,目的是将元素(带有子元素 sectPr)及其后续兄弟元素(直到下一个带有子元素的后续兄弟元素)分组sectPr), 递归地(即,将元素分组到输入的深度 XML)。

样本输入XML:

<body>
    <p/>
    <p>
        <sectPr/>
    </p>
    <p/>
    <p/>
    <tbl/>
    <p>
        <sectPr/>
    </p>
    <p/>
</body>

我试过的样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="*[1] | *[sectPr]"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::*[1][not(sectPr)]"/>
    </xsl:template>

    <xsl:template match="*[sectPr]">
        <myTag>
            <xsl:copy>
                <xsl:apply-templates select="*[1] | *[sectPr]"/>
            </xsl:copy>
            <xsl:apply-templates select="following-sibling::*[1][not(sectPr)]"/>
        </myTag>
    </xsl:template>

</xsl:stylesheet>

出于好奇,我遇到了 OutOfMemoryError 转换一个大约 60MB 的 XML。

我想知道,我想我不明白 michael.hor257k 和 Dimitre Novatchev 提供的 XSLT 背后的技巧,它不会导致内存异常。

我的样式表和上面提到的我得到 OutOfMemoryError 的答案之间的最大区别是什么。以及如何更新样式表以提高内存效率。

根据我的经验,XSLT 很容易使内存效率低下。它对于较小的转换(甚至是很多文件的较小转换)非常有效,但是当您开始进行复杂的分组或轴遍历时,它对于大型 (15mb+) XML 文件变得低效。是否可以将您的大文件拆分成小文件?我以前用这种技术解决过类似的问题。

由于您使用的是 Windows,您还有一些其他选择(特别是因为您只使用 XSLT 1.0)。一种可能有效的方法是尝试使用 .NET XslCompiledTransform class,它将 XSLT 编译为 IL。这可能无法解决内存问题,但它可能在您的平台上表现更好。

另一种选择是使用 .NET XmlReaderXmlWriter class,根据您的要求,这可能不会很难实施。这些是仅向前 XML 读取和写入 classes。使用流式处理可以提高内存效率。

林加穆尔西 CS,

请添加您从原始解决方案中删除的 <xsl:strip-space elements="*"/> 声明。这从源 XML 文档中删除任何纯空白文本节点。

不剥离这些节点可能会显着增加节点数量和保存它们的内存——在您的情况下,保存 XML 文档所需的内存几乎是所需内存的两倍内存来保存 XML 文档,这些节点被剥离。

我 运行 你的 t运行sformation OK,但是随着节点被剥离它 运行s 快了 20% -- 在 MS XslCompiledT运行sform.

然后我 运行 你的 t运行sformation -- 一次是在问题中发布的,第二次是添加 <xsl:strip-space elements="*"/> with Saxon 9.1J -- 因为它显示还有 t运行sformation 的内存消耗。两个 运行 都成功了。在第一种情况下,处理的节点数为 9525004 并且使用了 340MB RAM。 t运行 形成花费了 5.3 秒。在第二种情况下,节点数为 4336366 并且使用了 215MB RAM。 5.06sec

中的 t运行 形成 运行