10

XslTransform大きなアプリをからコンパイル済みのxslファイルに移行しようとしていますXslCompiledTransform

アプリはを使用しXslてHTMLファイルを作成し、変換データ( )は、データベースから返された、を使用してXmlに渡されました。XslXmlDataDocument

私はそれをすべて変更したので、今は(少なくとも一時的に)変更します:

C#

 public string ProcessCompiledXsl(XmlDataDocument xml)
 {
       StringBuilder stringControl = new StringBuilder();
       XslCompiledTransform xslTran = new XslCompiledTransform();

       xslTran.Load(
           System.Reflection.Assembly.Load("CompiledXsl").GetType(dllName)
       );

       xslTran.Transform(xml, this.Arguments, XmlWriter.Create(stringControl, othersettings), null);

       return stringControl.ToString();
 }

XSL(単なる例)

...
  <xsl:output method="html" indent="yes"/>
  <xsl:template match="/">
       <xsl:for-each select="//Object/Table">
              <a href="#">
                     some text
              </a>
       </xsl:for-each>
  </xsl:template>

問題

それは機能しますが、xslは出力するタグ間の空白を取り除きます:

<a href="#">
   some text
</a><a href="#">
   some text
</a><a href="#">
   some text
</a><a...etc

私はもう試した:

  • 使用してxml:space="preserve"いますが、動作させることができませんでした
  • をオーバーライドしましたOutputSettingsが、良い結果が得られませんでした(何かを逃した可能性があります)
  • を使用するxsl:output method="xml"と、それは機能しますが、自己終了タグや他の多くの問題が発生します

だから私は何をすべきかわかりません。たぶん私は何か正しいことをしていません。

ありがとう!

編集

将来の参考のために、すべてのXSLをそのままにしてこの問題に取り組みたい場合は、私が書いた、という名前のこのC#クラスCustomHtmlWriterを試すことができます。

基本的に私がしたことは、すべてのタグのとXmlTextWriterを書き込むメソッドから拡張して変更することです。startend

この特定のケースでは、次のように使用します。

    StringBuilder sb = new StringBuilder();
    CustomHtmlWriter writer = new CustomHtmlWriter(sb);

    xslTran.Transform(nodeReader, this.Arguments, writer);

    return sb.ToString();

それが誰かを助けることを願っています。

4

4 に答える 4

5

I.解決策1

ここで最初に問題を分析しましょう

このソースXMLドキュメント(提供していないために発明されたもの)を考えると、次のようになります。

<Object>
 <Table>

 </Table>

 <Table>

 </Table>

 <Table>

 </Table>

 <Table>

 </Table>
</Object>

この変換

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" indent="yes"/>

  <xsl:template match="/">
       <xsl:for-each select="//Object/Table">
              <a href="#">
                     some text
              </a>
       </xsl:for-each>
  </xsl:template>
<!--
 <xsl:template match="Table">
   <a href="#">
    Table here
   </a>
 </xsl:template>
 -->
</xsl:stylesheet>

問題を正確に再現します-結果は次のとおりです。

<a href="#">
                     some text
              </a><a href="#">
                     some text
              </a><a href="#">
                     some text
              </a><a href="#">
                     some text
              </a>

ここで、コメント化されたテンプレートのコメントを解除し、最初のテンプレートをコメントアウトします。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" indent="yes"/>
<!--
  <xsl:template match="/">
       <xsl:for-each select="//Object/Table">
              <a href="#">
                     some text
              </a>
       </xsl:for-each>
  </xsl:template>
 -->
 <xsl:template match="Table">
   <a href="#">
    Table here
   </a>
 </xsl:template>
</xsl:stylesheet>

結果には必要なインデントがあります:

 <a href="#">
    Table here
   </a>

 <a href="#">
    Table here
   </a>

 <a href="#">
    Table here
   </a>

 <a href="#">
    Table here
   </a>

そしてこれが解決策1でした


II。解決策2

このソリューションにより、既存のXSLTコードに必要な変更を最小限に抑えることができます。

これは2パス変換です:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="ext">
 <xsl:output method="html"/>

  <xsl:template match="/">
    <xsl:variable name="vrtfPass1">
       <xsl:for-each select="//Object/Table">
              <a href="#">
                     some text
              </a>
       </xsl:for-each>
    </xsl:variable>

    <xsl:apply-templates select=
        "ext:node-set($vrtfPass1)" mode="pass2"/>
  </xsl:template>

 <xsl:template match="node()|@*" mode="pass2">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*" mode="pass2"/>
  </xsl:copy>
 </xsl:template>

  <xsl:template mode="pass2" match="*[preceding-sibling::node()[1][self::*]]">
   <xsl:text>&#xA;</xsl:text>
   <xsl:copy-of select="."/>
  </xsl:template>
</xsl:stylesheet>

アイデアは、既存のコードには触れずに、その出力をキャプチャし、数行の追加コードのみを使用して、必要な最終的な外観になるように出力をフォーマットすることです。

この変換が同じXMLドキュメントに適用されると、同じ、必要な結果が生成されます。

<a href="#">
                     some text
              </a>
<a href="#">
                     some text
              </a>
<a href="#">
                     some text
              </a>
<a href="#">
                     some text
              </a>

最後に、既存のXSLTコードにまったく触れることなく、この小さな変更を導入する方法のデモンストレーションを示します

c:\temp\delete\existing.xslこの既存のコードを:に入れましょう

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html"/>

  <xsl:template match="/">
    <xsl:for-each select="//Object/Table">
      <a href="#">
        some text
      </a>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

これを実行すると、問題のある出力が得られます

ここで、を実行する代わりに、existing.xslこの変換を実行します

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="ext">
 <xsl:import href="file:///c:/temp/delete/existing.xsl"/>
 <xsl:output method="html"/>


  <xsl:template match="/">
    <xsl:variable name="vrtfPass1">
       <xsl:apply-imports/>
    </xsl:variable>

    <xsl:apply-templates select=
        "ext:node-set($vrtfPass1)" mode="pass2"/>
  </xsl:template>

 <xsl:template match="node()|@*" mode="pass2">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*" mode="pass2"/>
  </xsl:copy>
 </xsl:template>

  <xsl:template mode="pass2" match="*[preceding-sibling::node()[1][self::*]]">
   <xsl:text>&#xA;</xsl:text>
   <xsl:copy-of select="."/>
  </xsl:template>
</xsl:stylesheet>

結果は必要なものであり、既存のコードはまったく変更されていません

<a href="#">
        some text
      </a>
<a href="#">
        some text
      </a>
<a href="#">
        some text
      </a>
<a href="#">
        some text
      </a>

説明

  1. を使用して、インポート優先順位階層の最上位にある(他のスタイルシートによってインポートされていない)既存のコードをインポートしますxsl:import

  2. 既存の変換の出力を変数にキャプチャします。悪名高いRTF(結果ツリーフラグメント)があり、さらに処理するには通常のツリーに変換する必要があります。

  3. 重要な瞬間はxsl:apply-imports、変換の出力をキャプチャするときに実行することです。これにより、既存のコードからのテンプレート(テンプレートマッチングなど、オーバーライドするものも/含む)が、既存の変換が単独で実行される場合と同様に、実行用に選択されることが保証されます。

  4. 拡張関数を使用してRTFを通常のツリーに変換します(XslCompiledTransformはEXSLTmsxsl:node-set()拡張関数もサポートしています)。node-set()

  5. そのように作成された通常のツリーに対して、外観の調整を行います。

これは、既存のコードに触れることなく、既存の変換を後処理するための一般的なアルゴリズムを表しています

于 2012-09-02T22:12:06.297 に答える
1

XML / XSLTスペースの保存の詳細を頭から覚えていませんが、空白を破棄する可能性が高いのは、空白以外のテキストがない要素間です(つまり、空白のみのテキストノードなどです。</a>との間の1つ</xsl:for-each>)。<xsl:text>要素を使用することでこれを防ぐことができます。

たとえば、

          <a href="#">
                 some text
          </a>

置く

          <xsl:text>&#10;</xsl:text>

つまり、リテラル行の終了文字です。

それはあなたの要件を満たしていますか?

于 2012-08-31T16:03:22.023 に答える
1

問題は次のとおりだと思います。

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

私が正しく覚えていれば、htmlはHTMLの表示方法にとって重要な空白だけを気にかけようとします。

試してみると:

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

次に、期待するインデントされた空白を作成する必要があります。

于 2012-08-31T16:37:01.657 に答える
1

xsl:textに含まれていない限り、スタイルシートの空白テキストノードは常に無視されます。結果ツリーに空白を出力する場合は、xsl:textを使用します。

(スタイルシートでxml:space = "preserve"を使用することもできますが、望ましくない副作用があるため、通常はお勧めできません。)

于 2012-08-31T18:36:13.140 に答える