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.
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");
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.
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.
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?