在.NET中使用document()函数XSLT会生成错误

时间:2010-04-25 23:25:05

标签: c# xml xslt

我想在我的XSLT文件中使用嵌入式资源,但在调用'document(...)'时,C#抱怨“加载文档时出错...”

我想在XSLT文件中使用已定义的资源并通过它来获取它们:“document('')/ / my:resources / ”...

我该怎么做?

ex xsl:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:my="xslt-gruper-v1.2.xsl" exclude-result-prefixes="my">

     <my:resources>
      <one>tryb</one>
     </my:resources>

     <xsl:variable name="res" select="document('')/*/my:resources/("/>
</xsl:stylesheet>

如何在C#中无异常地访问此类结构?我将在静态转换期间通过ex添加。 Opera一切正常。

2 个答案:

答案 0 :(得分:10)

<xsl:variable name="res" select="document('')/*/my:resources/("/>

select属性的值不是语法正确的XPath表达式。每个兼容的XSLT处理器都必须引发错误。

<强>解决方案

将上述内容改为:

<xsl:variable name="vRes" select="document('')/*/my:resources"/>

如果仍有异常,请阅读XsltSettings类。

然后使用this constructor创建一个XsltSettings 实例,如下所示:

XsltSettings(true, false)

不启用脚本 - 将构造函数的第二个参数保留为false

以下是更完整的代码段

// Create the XsltSettings object with document() enabled and script disabled.
XsltSettings settings = new XsltSettings(true,false);

// Create the XslCompiledTransform object and load the style sheet.
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("sort.xsl", settings, new XmlUrlResolver());

更新:出现错误的另一个可能原因是在内存中动态创建XSLT样式表(不是来自文件)。在这种情况下,XSLT处理器通常无法解析document('')中的相对uri。

在最后一种情况下,解决方案是使有用元素成为xsl:variable的内容,并使用xxx:node-set()扩展函数来处理此元素。

答案 1 :(得分:0)

在整整一天半的时间里梳理头发后,我终于想出了解决同一问题的方法。

我的代码:

NUnit测试:

[Test]
public void Transform_WhenXslUsesTheDocumentFunction_DoesNotThrow()
{
    //Arrange
    string testOutputPath = GetTestOutputPath(
        nameof(Transform_WhenXslUsesTheDocumentFunction_DoesNotThrow)
        );
    string inputXsl = TestFilePaths.GetResource("Import\\DocumentImporter.xsl");
    XsltSettings xsltSettings = new XsltSettings(true, true);
    XmlUrlResolver resolver = new XmlUrlResolver();
    XslCompiledTransform xslCompiledTransform = new XslCompiledTransform();
    xslCompiledTransform.Load(inputXsl, xsltSettings, resolver);

    //Act
    TestDelegate testDelegate = () => xslCompiledTransform.Transform(
        TestFilePaths.MinimumValidXml
        , testOutputPath
        );

    //Assert
    Assert.DoesNotThrow(testDelegate);
}

DocumentImporter.xsl:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:variable name="DocumentPath" select="'./Document.xml'"/>
  <xsl:variable name="DocumentXML" select="document($DocumentPath)"/>

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

    <xsl:template match="@* | node()">
      <xsl:value-of select="$DocumentXML//Message"/>
    </xsl:template>
</xsl:stylesheet>

Document.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Message>Document Message</Message>

最终我找到了:

https://github.com/dotnet/runtime/issues/26969

通知我我需要使用一个新的.Net Core“功能”,该功能允许我使用代码段使用外部xml文档:

AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);

有效的最终代码:

[Test]
public void Transform_WhenXslUsesTheDocumentFunction_DoesNotThrow()
{
    AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);

    //Arrange
    string testOutputPath = GetTestOutputPath(
        nameof(Transform_WhenXslUsesTheDocumentFunction_DoesNotThrow)
        );
    string inputXsl = TestFilePaths.GetResource("Import\\DocumentImporter.xsl");
    XsltSettings xsltSettings = new XsltSettings(true, true);
    XmlUrlResolver resolver = new XmlUrlResolver();
    XslCompiledTransform xslCompiledTransform = new XslCompiledTransform();
    xslCompiledTransform.Load(inputXsl, xsltSettings, resolver);

    //Act
    TestDelegate testDelegate = () => xslCompiledTransform.Transform(
        TestFilePaths.MinimumValidXml
        , testOutputPath
        );

    //Assert
    Assert.DoesNotThrow(testDelegate);
}