用于转换大型 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 XmlReader
和 XmlWriter
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.06
sec
中的 t运行 形成 运行
此问题与
当使用上面提到的答案中的样式表时(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 XmlReader
和 XmlWriter
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.06
sec