【问题标题】:XslCompiledTransform fails with stack overflowXslCompiledTransform 因堆栈溢出而失败
【发布时间】:2013-07-08 21:33:14
【问题描述】:

我有一个包含 805 个模板的大型 XSLT 文件,根据系统和环境,该文件会因堆栈溢出而失败。

开发环境为 Windows 7、InfoPath 2010 和 C#。虽然安装了 .NET 4.0,但此版本的 InfoPath 使用 .NET 2.0。

正在使用的例程是:

private void TransformXML(String inputFileName, String transformFileName, String outputFileName)
{
    CorralLog(String.Concat("Transform with ", transformFileName, ": ", inputFileName, " -> ", outputFileName));

    using (XmlReader inputFile = XmlReader.Create(inputFileName, null))
    {
        XslCompiledTransform transform = new XslCompiledTransform(true);
        XsltSettings settings = new XsltSettings(true, false);

        transform.Load(transformFileName, settings, null);

        using(XmlWriter outputFile = XmlWriter.Create(outputFileName))
        {
            filesToDelete.Add(outputFileName);
            transform.Transform(inputFile, outputFile);
        }
    }
}

我可以看到一些可能性:

  1. 增加“transform.Load”命令可用的内存
  2. 用更多内存启动一个单独的线程
  3. 启动一个单独的线程并使用“msxsl.exe”执行转换(始终有效)
  4. 将 XSLT 文件拆分成更小的部分并多次进行转换

有人对选择哪个选项有建议吗?或者有什么其他建议?

保罗


有问题的 XLST 文件从 XML 文件中获取一些元素,更改一些元素的名称,然后生成另一个 XML 文件。大约有 800 个元素,每个元素都有自己的模板。

这段代码显示了 XSLT 文件开头的三个模板和两个用于复制元素的模板:一个用于按原样复制元素,另一个用于更改元素的名称。所有后续模板都以这两种方式之一进行格式化。

是这个语法导致了递归,还是模板的数量导致了堆栈溢出。 (通过在新线程中运行此转换,我们已经避免了这个问题,但可能没有解决它。)

<?xml version="1.0"?>

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2011-03-16T10:53:27">

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates select="*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*">
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template match="/SAN/ClientProfiles/ClientProfile">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/SAN/ClientProfiles/ClientProfile/Name">
        <CompanyName>
            <xsl:apply-templates/>
        </CompanyName>
    </xsl:template>

【问题讨论】:

  • 大量信息丢失。在什么特定条件下会失败?你自己有没有尝试过任何东西(如果没有,为什么不)?如果你给它足够的内存(比如 12GB),它总是能成功运行吗?根据目前提供的信息,任何答案都将是疯狂的猜测。
  • 不知道您为什么说“多次转换”与“将 XSLT 文件拆分成更小的部分”相一致。是多阶段转型吗?
  • 我们已经进行了五次转换,因为每一次转换的工作类型不同。因此,将大的变小可能会有所帮助,在不止一次变换中进行。但我们似乎已经成功地将转换扔到一个单独的线程中。

标签: xslt xslcompiledtransform


【解决方案1】:

【讨论】:

  • MSDN 文章非常好。尽管我们没有使用提到的特定结构,但可以通过更改 XSLT 文件来解决大多数堆栈溢出问题。在我们的例子中,我们已经启动了一个新线程来进行转换,这似乎有效。从长远来看,如果可能的话,更改 XSLT 可能是一个好主意。
  • 马丁,感谢您的参考。它表明魔鬼在细节中;我当然不会想到仅仅拥有数千个模板规则就足以导致堆栈溢出。
【解决方案2】:

堆栈溢出最可能的原因是 XSLT 代码中的深度递归。我会看看相关的模板,看看它们是否可以用其他方式编写,例如使用分治递归而不是头尾递归,或者利用 XSLT 2.0 - .NET 有几个很好的 XSLT 2.0 处理器。

【讨论】:

  • 我希望 XSLT 代码中没有递归。因为我们只从源 XML 中获取一些元素,所以我们有 805 个模板,它们只是将该元素复制到目标 XML。这么多模板会导致递归吗?
  • 谁知道?迈克尔·凯在前面的陈述中是正确的。您甚至没有提供一点 XSL 来进行诊断,但是您对解决方案的想法是询问增加内存等等……您的 XSLT 很可能是问题所在,但您没有提出任何问题来要求其他人评估可能的问题
  • 一开始我没有发布 XSLT 代码,因为我认为这是 Windows 或 .NET 的问题。鉴于原因可能是 XSLT 文件的错误设计,我已将 XSLT 代码添加到我的问题中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
  • 2019-05-18
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
相关资源
最近更新 更多