使用xsltc.exe时,如何使用相对路径解析<xsl:import>和<xsl:include>元素XslCompiledTransforms?</xsl:include> </xsl:import>

时间:2012-01-24 18:03:50

标签: c# xslt xslcompiledtransform

作为Web应用程序构建过程的一部分,每当我们运行完整编译时,我都会使用Microsoft's xsltc.exe编译器设置我们的XSLT样式表。在本地开发期间,这很有效,因为代码是在同一位置编译和托管的。但是,一旦将其放在构建服务器上,就会出现问题。

构建服务器将像在本地一样编译XSLT样式表,但随后会运行一个脚本,将编译后的代码部署到我们的内部登台Web服务器。一旦这些二进制文件从编译它们的位置移开,<xsl:import><xsl:include>元素中的相对路径就不再正确解析,导致在运行XSLT样式表时看起来像这样的异常。

Could not find a part of the path 'e:\{PATH}\xslt\docbook\VERSION'.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
    at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn)
    at System.Xml.Xsl.Runtime.XmlQueryContext.GetDataSource(String uriRelative, String uriBase)

以下是现在代码的一般概念:

var xslt = new XslCompiledTransform();
xslt.Load(typeof(Namespace.XslTransforms.CompiledXsltStylesheet));
xslt.Transform("input.xml", "output.xml");

现在我正在使用带有单个“Type”参数的XslCompiledTransform.Load()方法来引入基于xsltc.exe的预编译XSLT样式表。我可以从堆栈跟踪中看出,.NET框架正在使用XmlUrlResolver来尝试解析这些外部样式表的实际位置,但我没有看到提供XmlResolver的重写实现的方法,我可以传入一个新的baseUri指向这些样式表在Web服务器上的位置。

我假设我可以通过不再使用xsltc.exe进行预编译并通过XmlReaders加载XSLT样式表来解决这个问题,因为这样我就可以使用other XslCompiledTransform.Load() methods,它有一个参数,我可以提供自己的XmlResolver实现。但是,我喜欢语法验证和性能的预编译选项,所以我不想放弃它,除非我绝对必须这样做。

有没有办法使用xsltc.exe预编译这些XSLT样式表,但仍提供一种方法来明确说明baseUri的<xsl:include><xsl:import>元素的相对路径分辨率在运行时?

3 个答案:

答案 0 :(得分:3)

经过很多的讨论之后,我发现我提供的代码自动使用System.Xml.XmlUrlResolver来解析<xsl:include>和{{ 1}}运行时的相对路径。但是,当System.Xml.XslCompiledTransform将XmlUrlResolver放入二进制文件时,它不会绑定到xsltc.exe XmlResolver实际上由XmlResolverSystem.Xml.XmlReaderSettingsSystem.Xml.XmlReader属性选择,{{3}}在运行时执行转换。一旦我设置了自己的自定义XmlResolver在我使用的XsltReaderSettings上,我能够控制相对路径分辨率。

如果你想像我一样覆盖这个XmlResolver,可以使用以下代码作为指南:

<xsl:import>

我仍在使用var customXmlResolver = new SomeCustomXmlResolver(); // Derives from XmlResolver var xmlReaderSettings = new XmlReaderSettings { XmlResolver = customXmlResolver }; var xslt = new XslCompiledTransform(); xslt.Load(typeof(Namespace.XslTransforms.CompiledXsltStylesheet)); using (var xmlReader = XmlReader.Create("input.xml", xmlReaderSettings)) { using (var xmlWriter = XmlWriter.Create("output.xml")) { xslt.Transform(xmlReader, null, xmlWriter, customXmlResolver); } } 来编译我的XSLT样式表,但是当我在Web服务器上加载这些已编译的样式表时,注入的xsltc.exe会重写覆盖的SomeCustomXmlResolver和{{}中的路径1}}方法,以便可以找到基于ResolveUri()GetEntity()的相对路径中的引用文件。作为额外的好处,通过在<xsl:include>方法的末尾添加相同的XmlResolver,XML中的 <xsl:import> 操作也将正确解析其相对路径。

答案 1 :(得分:2)

  

有没有办法使用xsltc.exe预编译这些XSLT样式表,   但仍然提供了一种明确说明baseUri为亲属的方法   运行时<xsl:include><xsl:import>元素的路径分辨率?

尝试使用

<强> XslCompiledTransform.CompileToType()

此静态方法接受的一个参数是

XmlResolver stylesheetResolver

答案 2 :(得分:0)

我不知道这是否会破坏你的系统,但是如何而不是

  1. 使用xsltc.exe
  2. 进行编译
  3. 部署二进制文件
  4. 使用this Load()
  5. 加载二进制文件

    1. 部署样式表,但import/include指令
    2. 需要很多样式表
    3. 使用this Load()加载主样式表,指定import/incldue
    4. 的解析程序

      看来你仍然可以获得“编译”样式表的好处,至少在运行时是这样。