问题描述
作为我们 Web 应用程序构建过程的一部分,我已经设置了要使用 微软的 xsltc.exe 编译器,每当我们运行一个完整的编译.在本地开发期间,这非常有效,因为代码是在同一位置编译和托管的.但是,一旦将其放在构建服务器上,问题就出现了.
As part of our web application's build process, I have set up our XSLT stylesheets to be built with Microsoft's xsltc.exe compiler whenever we run a full compile. During local development this has worked great, as the code is compiled and hosted in the same location. However, once this was put on the build server, problems arose.
构建服务器将像我在本地一样编译 XSLT 样式表,但随后会运行一个脚本,将编译后的代码部署到我们的内部登台 Web 服务器.一旦这些二进制文件从它们被编译的地方移开, 和
元素中的相对路径不再正确解析,从而导致异常运行 XSLT 样式表时看起来像这样.
The build server will compile the XSLT stylesheets just like I do locally, but then a script runs that deploys the compiled code to our internal staging web server. Once these binaries have moved from where they were compiled, the relative paths in <xsl:import>
and <xsl:include>
elements no longer resolve correctly, causing exceptions that look like this when the XSLT stylesheets are ran.
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)
以下是代码的总体思路:
Here's a general idea of the code as it stands now:
var xslt = new XslCompiledTransform();
xslt.Load(typeof(Namespace.XslTransforms.CompiledXsltStylesheet));
xslt.Transform("input.xml", "output.xml");
现在我使用带有单个类型"参数的 XslCompiledTransform.Load() 方法来引入基于 xsltc.exe 的预编译 XSLT 样式表.我可以从堆栈跟踪中看出 .NET 框架正在使用 XmlUrlResolver 来尝试解析这些外部样式表的实际位置,但是我没有看到提供 XmlResolver 的覆盖实现的方法,我可以在其中传入一个新的baseUri 指向这些样式表在 Web 服务器上的位置.
Right now I'm using the XslCompiledTransform.Load() method with a single 'Type' parameter to bring in the xsltc.exe-based pre-compiled XSLT stylesheets. I can tell from the stack trace that the .NET framework is using the XmlUrlResolver to try to resolve the actual location of these external stylesheets, but I don't see a way to provide an overridden implementation of XmlResolver where I could pass in a new baseUri that points to where these stylesheets live on the web server.
我想我可以通过不再使用 xsltc.exe 进行预编译并通过 XmlReaders 加载 XSLT 样式表来解决此问题,因为这将让我使用 其他 XslCompiledTransform.Load() 方法,它们有一个参数,我可以在其中提供我自己的 XmlResolver 实现.但是,我喜欢用于语法验证和性能的预编译选项,因此除非万不得已,否则我不想放弃.
I assume I can resolve this by no longer pre-compiling with xsltc.exe and loading the XSLT stylesheets via XmlReaders, since that will let me use the other XslCompiledTransform.Load() methods which have a parameter where I could provide my own XmlResolver implementation. However, I like the pre-compilation option for syntax validation and performance, so I don't want to give it up unless I absolutely have to.
有没有办法使用 xsltc.exe 来预编译这些 XSLT 样式表,但仍然提供一种方法来显式声明用于 和
元素在运行时?
Is there a way to use xsltc.exe to pre-compile these XSLT stylesheets, yet still provide a way to explicitly state the baseUri for relative path resolution of <xsl:include>
and <xsl:import>
elements at runtime?
推荐答案
经过 很多 的尝试,我发现我提供的代码自动使用了 System.Xml.XmlUrlResolver 解决 和
在运行时的相对路径.但是,XmlUrlResolver 的使用不受系统的约束.Xml.XslCompiledTransform 当它被
放入二进制文件时xsltc.exe
.XmlResolver 实际上是由 XmlResolver选择的a> 上 System.Xml.XmlReaderSettings 上的属性System.Xml.XmlReader 在 在我使用的 XsltReaderSettings 上设置我自己的自定义 XmlResolver 后,我就能够控制相对路径分辨率.
After a lot of playing around with this, I found out that I was right that the code I provided automatically uses the System.Xml.XmlUrlResolver to resolve the <xsl:include>
and <xsl:import>
relative paths at run-time. However, the use of the XmlUrlResolver is not bound to the System.Xml.XslCompiledTransform when it is placed in a binary by xsltc.exe
. The XmlResolver is actually chosen by the XmlResolver property on the System.Xml.XmlReaderSettings on the System.Xml.XmlReader that performs the transformation at run-time. Once I set my own custom XmlResolver on the XsltReaderSettings I was using, I was able to control relative path resolution.
如果你想像我一样覆盖这个XmlResolver,可以使用以下代码作为指导:
If you want to override this XmlResolver as I did, the following code can be used as a guide:
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);
}
}
我仍在使用 xsltc.exe
来编译我的 XSLT 样式表,但是当我在 Web 服务器上加载这些已编译的样式表时,注入的 SomeCustomXmlResolver
重写了覆盖的路径ResolveUri()
和 GetEntity()
方法使引用的文件位于 和
的相对路径.作为一个额外的好处,通过在
Transform()
方法的末尾添加相同的 XmlResolver,XML 中的 document()
操作也将正确解析它们的相对路径.
I am still using xsltc.exe
to compile my XSLT stylesheets, but when I load these compiled stylesheets on the web server, the injected SomeCustomXmlResolver
rewrites the paths in overridden ResolveUri()
and GetEntity()
methods so that the referenced files that live in the <xsl:include>
and <xsl:import>
-based relative paths can be found. As an added bonus, by adding the same XmlResolver to the end of the Transform()
method, document()
operations in the XML will also have their relative paths resolved correctly.
这篇关于我如何解决 <xsl:import>和 <xsl:include>使用 xsltc.exe XslCompiledTransforms 时具有相对路径的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!