【问题标题】:"Execution of the 'document()' function was prohibited." where EnableDocumentFunction set to true?“禁止执行‘document()’函数。” EnableDocumentFunction 在哪里设置为 true?
【发布时间】:2011-11-22 23:38:45
【问题描述】:

尝试 xslt 转换时,我在生产环境中遇到间歇性 System.Xml.Xsl.XslTransformException 异常,遗憾的是我无法在开发环境中复制此异常。

异常吐出更多细节:

禁止执行“document()”函数。使用 XsltSettings.EnableDocumentFunction 属性来启用它。一个错误 发生在 C:\path\to\file\CDS.xsl(16,3)。

然而处理代码中的 EnableDocumentFunction 属性设置为 true:

private void Transform()
{
    var keepTrying = true;
    var tryCount = 0;
    const int maxRetrys = 3;

    while (keepTrying)
    {
        try
        {
            var xmlResolver = new XmlUrlResolver();

            using (var xmlFile = new XmlNodeReader(_xDoc))
            {
                var settings = new XmlReaderSettings
                                   {
                                       XmlResolver = xmlResolver,
                                       ProhibitDtd = false,
                                       DtdProcessing = DtdProcessing.Ignore
                                   };

                using (var xsl = XmlReader.Create(_xslPath, settings))
                {
                    var xslt = new XslCompiledTransform(true);
                    xslt.Load(xsl, new XsltSettings { EnableDocumentFunction = true }, xmlResolver);

                    var sb = new StringBuilder();
                    using (var writer = XmlWriter.Create(sb, xslt.OutputSettings))
                    {
                        xslt.Transform(xmlFile, null, writer, xmlResolver); // errors out here.
                    }

                    var xhtml = sb.ToString();
                    _transformedXml = xhtml;
                    _isTransformed = true;

                    xsl.Close();
                }
            }

            keepTrying = false;
        }
        catch (System.Xml.Xsl.XsltException ex)
        {
            ExceptionPolicy.HandleException(ex, "ExceptionLogging");

            tryCount++;
            if (tryCount > maxRetrys)
            {
                keepTrying = false;
                throw;
            }
        }
    }
}

xslt 文件由第三方提供并自动更新,因此不可重写。这是它的顶部,出于隐私原因略有修改:

<?xml version="1.0"?>

<!--
     Interaction_550.xsl : 20110916
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:example="http://www.example.com" version="1.0">
  <xsl:param name="D2DSeverityFilter"></xsl:param>
  <xsl:param name="D2HSeverityFilter"></xsl:param>
  <xsl:param name="DocumentationFilter"></xsl:param>
  <xsl:output method="html"/>
  <xsl:key name="d2d_sev_level-lookup" match="example:d2d_sev_level" use="@name"/>
  <xsl:key name="d2h_sev_level-lookup" match="example:d2h_sev_level" use="@name"/>
      <xsl:key name="d2l_sev_level-lookup" match="example:d2l_sev_level" use="@name"/>
      <xsl:key name="preg_cat-lookup" match="example:preg_cat" use="@cat"/>
  <xsl:key name="doc_level-lookup" match="example:doc_level" use="@name"/>
  <xsl:variable name="d2d_sev_level-top" select="document('')/*/example:d2d_sev_levels"/>
  <xsl:variable name="d2h_sev_level-top" select="document('')/*/example:d2h_sev_levels"/>
      <xsl:variable name="d2l_sev_level-top" select="document('')/*/example:d2l_sev_levels"/>

  <xsl:variable name="doc_level-top" select="document('')/*/example:doc_levels"/>
      <xsl:variable name="preg_cat-top" select="document('')/*/example:preg_cats"/>
  <xsl:template match="/">
    <head>
      <style type="text/css">
body {
font-family : arial,sans serif,helvetica;
}
...

我该怎么做:

  • 解决这个问题,让它根本不会发生?
  • 如果做不到这一点,我该如何在 dev 中复制它?

【问题讨论】:

  • 如果样式表在内存中(缓存)或者解析器不知道如何处理空字符串 URL,document('') 函数可能会失败。如果您在生产版本中有缓存,可能就是这种情况。您可以以编程方式将样式表处理为另一个样式表,该样式表不包含document() 调用,并且将使用 XslCompiledTransform 成功执行。如果您对这样的解决方案感兴趣,请告诉我,我可以在回复中描述它。
  • 谢谢 Dimitre,我将从验证缓存情况开始 - 但如果您能进一步描述处理样式表以删除 document() 调用,那就太好了。
  • @_CamM:是的,我发布了一个答案,其中包含执行此所需转换的一般转换。

标签: c# .net xml c#-4.0 xslt


【解决方案1】:

或者使用 MS XslCompiledTransform 类,您可以使用 XsltSettings 类来避免此错误,因为它由错误本身描述。 from MSDN

【讨论】:

  • 如原问题“However the EnableDocumentFunction property is set to true in the processing code:”中所述,已尝试过。
【解决方案2】:

这是摆脱document('')/*/someName 表达式的一般方法

原始转换使用特殊转换进行处理,该转换生成不包含document('') 函数调用的等效转换。

那么你只需要使用生成的转换即可。

示例

这个转换(命名为tA),包含document('')

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:paramDoc1>
  <x>123</x>
  <y>37</y>
 </my:paramDoc1>

 <my:paramDoc2>
  <x>456</x>
  <y>79</y>
 </my:paramDoc2>

 <xsl:variable name="vpDoc1" select="document('')/*/my:paramDoc1"/>
 <xsl:variable name="vpDoc2" select="document('')/*/my:paramDoc2"/>

 <xsl:template match="/*">
     <xsl:value-of select="$vpDoc1/x"/>
     <xsl:text>|</xsl:text>
     <xsl:value-of select="$vpDoc2/y"/>
 </xsl:template>
</xsl:stylesheet>

当应用于任何文档时,会产生

123|79

现在我们用这个 (tGen) 处理上述转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="a:a" exclude-result-prefixes="x">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:namespace-alias stylesheet-prefix="x"
      result-prefix="xsl"/>

 <xsl:variable name="vApos">'</xsl:variable>

 <xsl:variable name="vSelectPrefix" select=
  "concat('document(', $vApos,$vApos, ')/*/')"/>

 <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="xsl:stylesheet">
  <x:stylesheet xmlns:ext="http://exslt.org/common">
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
  </x:stylesheet>
 </xsl:template>

 <xsl:template match="xsl:variable">
  <xsl:variable name="vSelattr" select="@select"/>
  <xsl:choose>
      <xsl:when test="not(starts-with(@select, $vSelectPrefix))">
        <xsl:call-template name="identity"/>
      </xsl:when>
      <xsl:otherwise>
      <x:variable name="vrtf{@name}">
        <xsl:copy-of select=
        "/*/*[name()
             = substring-after($vSelattr, $vSelectPrefix)
             ]"/>
      </x:variable>

      <x:variable name="{@name}" select=
           "ext:node-set($vrtf{@name})/*"/>
      </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

</xsl:stylesheet>

结果是一个新的转换 (tRes),它不包含像 document('') 这样的表达式:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:ext="http://exslt.org/common">
    <xsl:output omit-xml-declaration="yes" 
         indent="yes" xmlns:my="my:my" />
    <xsl:strip-space elements="*" xmlns:my="my:my" />
    <my:paramDoc1 xmlns:my="my:my">
        <x>123</x>
        <y>37</y>
    </my:paramDoc1>
    <my:paramDoc2 xmlns:my="my:my">
        <x>456</x>
        <y>79</y>
    </my:paramDoc2>
    <xsl:variable name="vrtfvpDoc1">
        <my:paramDoc1 xmlns:my="my:my">
            <x>123</x>
            <y>37</y>
        </my:paramDoc1>
    </xsl:variable>
    <xsl:variable name="vpDoc1" select="ext:node-set($vrtfvpDoc1)/*" />
    <xsl:variable name="vrtfvpDoc2">
        <my:paramDoc2 xmlns:my="my:my">
            <x>456</x>
            <y>79</y>
        </my:paramDoc2>
    </xsl:variable>
    <xsl:variable name="vpDoc2" select="ext:node-set($vrtfvpDoc2)/*" />
    <xsl:template match="/*" xmlns:my="my:my">
        <xsl:value-of select="$vpDoc1/x" />
        <xsl:text>|</xsl:text>
        <xsl:value-of select="$vpDoc2/y" />
    </xsl:template>
</xsl:stylesheet>

如果我们现在将此动态生成的转换 (tRes) 应用于任何 XML 文档,结果与将原始转换 (tA) 应用于此文档时完全相同

123|79

因此,我们可以使用tGen 将包含document('') 表达式的转换转换为不包含此类表达式的等效转换

【讨论】:

  • 感谢 Dimitre,您提供的转换已修复 document() 问题。它还暴露了完整的 xslt 正在生成一个无效的 xml 文档(两个根元素),我们现在也已修复它 - 但我不禁想知道这两者是否在内部相关。
  • @CamM:很高兴我的回答有帮助。至于您的问题,错误消息和未生成格式正确的文档这一事实 - 这些似乎没有很强的相关性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多