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>
</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>
</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>
説明:
を使用して、インポート優先順位階層の最上位にある(他のスタイルシートによってインポートされていない)既存のコードをインポートしますxsl:import
。
既存の変換の出力を変数にキャプチャします。悪名高いRTF(結果ツリーフラグメント)があり、さらに処理するには通常のツリーに変換する必要があります。
重要な瞬間はxsl:apply-imports
、変換の出力をキャプチャするときに実行することです。これにより、既存のコードからのテンプレート(テンプレートマッチングなど、オーバーライドするものも/
含む)が、既存の変換が単独で実行される場合と同様に、実行用に選択されることが保証されます。
拡張関数を使用してRTFを通常のツリーに変換します(XslCompiledTransformはEXSLTmsxsl:node-set()
拡張関数もサポートしています)。node-set()
そのように作成された通常のツリーに対して、外観の調整を行います。
注:
これは、既存のコードに触れることなく、既存の変換を後処理するための一般的なアルゴリズムを表しています。