7

Web アプリケーションのビルド プロセスの一環として、フル コンパイルを実行するたびにMicrosoft の 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");

現在、xsltc.exe ベースのプリコンパイル済み XSLT スタイルシートを取り込むために、単一の「Type」パラメーターを指定して XslCompiledTransform.Load() メソッドを使用しています。スタック トレースから、.NET フレームワークが XmlUrlResolver を使用してこれらの外部スタイルシートの実際の場所を解決しようとしていることがわかりますが、新しいこれらのスタイルシートが存在する Web サーバー上の場所を指す baseUri。

これは、xsltc.exe で事前にコンパイルせず、XmlReaders を介して XSLT スタイルシートをロードすることで解決できると思います。これにより、独自の XmlResolver 実装を提供できるパラメーターを持つ他の XslCompiledTransform.Load() メソッドを使用できるようになるからです。 . ただし、構文の検証とパフォーマンスのためにプリコンパイル オプションが気に入っているので、絶対に必要でない限り、これを放棄したくありません。

<xsl:include>xsltc.exe を使用してこれらの XSLT スタイルシートをプリコンパイルする方法はありますか?実行時に<xsl:import>要素の相対パス解決のために baseUri を明示的に指定する方法を提供しますか?

4

3 に答える 3

5

これをいろいろいじってみたところ、私が提供したコードはSystem.Xml.XmlUrlResolverを自動的に使用して、実行時に<xsl:include>との相対パスを解決するという私の考えが正しかったことがわかりました。<xsl:import>ただし、XmlUrlResolver の使用は、System.Xml.XslCompiledTransformによってバイナリに配置された場合にバインドされませんxsltc.exeXmlResolver は、実行時に変換を実行するSystem.Xml.XmlReaderSystem.Xml.XmlReaderSettingsのXmlResolverプロパティによって実際に選択されます。使用していた XsltReaderSettings に独自のカスタム XmlResolver を設定すると、相対パスの解決を制御できるようになりました。

私が行ったように、この XmlResolver をオーバーライドする場合は、次のコードをガイドとして使用できます。

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.exeXSLT スタイルシートをコンパイルするために使用していますが、これらのコンパイル済みスタイルシートを Web サーバーにロードすると、挿入されたメソッドによってオーバーライドされたおよびメソッドSomeCustomXmlResolverのパスが書き換えられ、およびベースの相対パスに存在する参照ファイルが検出されます。おまけとして、メソッドの最後に同じ XmlResolver を追加することで、XML 内の操作の相対パスも正しく解決されます。ResolveUri()GetEntity()<xsl:include><xsl:import>Transform()document()

于 2012-04-04T03:59:51.537 に答える
2

<xsl:include>xsltc.exeを使用してこれらのXSLTスタイルシートをプリコンパイルする方法はありますが、実行時に<xsl:import>要素の相対パス解決のためにbaseUriを明示的に指定する方法を提供しますか?

使用してみてください

XslCompiledTransform.CompileToType()

この静的メソッドが受け入れる引数の1つは、次のとおりです。

XmlResolver stylesheetResolver
于 2012-01-25T03:15:09.763 に答える
0

これがあなたのシステムを壊すかどうかはわかりませんが、代わりにどうですか

  1. コンパイルxsltc.exe
  2. バイナリのデプロイ
  3. これでバイナリをロードするLoad()

あなた

  1. スタイルシートを展開しますが、多くはimport/includeディレクティブで必要です
  2. これLoad()でメインのスタイルシートをロードし、リゾルバーを指定しますimport/incldue

少なくとも実行時には、「コンパイルされた」スタイルシートの利点が得られるようです。

于 2012-01-24T22:36:36.650 に答える