15個のXSLスタイルシートのパイプラインを使用するアプリケーションを作成し、そのパフォーマンスの調整に取り組み始めています。ポータブルに設計されているため、Webブラウザ環境とデスクトップの両方で実行できます。デスクトップでは、スタイルシートを複数の変換のパイプラインとして分離しておくのが理にかなっていると思います。これにより、個々の変換を独自のスレッドで実行できるため、複数のコアを備えたCPUで非常に効率的になります。ただし、ブラウザー環境がシングルスレッドであるだけでなく、ほとんどのブラウザーで、JavaScriptに公開されているXSL処理APIは、個々の変換の結果をDOMオブジェクトに解析して戻す必要があります。これは非効率的です。したがって、可能であれば、ブラウザー環境のコンテキストで実行するときに、すべてのスタイルシートを1つのスタイルシートに結合することが有利だと思います。exsl:node-set(ほとんどのブラウザーがサポートしている)を使用してこれをどのように実現できるかについては考えていますが、私が想像している手法が一般化できるかどうかはわかりません。完全なパイプラインのセマンティクスが保持されるように、XSLスタイルシートのパイプラインを単一のXSLスタイルシートに変換するための一般的な手法はありますか?自動化されたソリューションが理想的です。完全なパイプラインのセマンティクスが保持されるように、XSLスタイルシートのパイプラインを単一のXSLスタイルシートに変換するための一般的な手法はありますか?自動化されたソリューションが理想的です。完全なパイプラインのセマンティクスが保持されるように、XSLスタイルシートのパイプラインを単一のXSLスタイルシートに変換するための一般的な手法はありますか?自動化されたソリューションが理想的です。
2 に答える
k番目の変換の出力が(k + 1)番目の変換の入力である場合に、独立した変換を連鎖させることができる手法があります。
簡単な例を次に示します。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="ext xsl">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="node()"/>
</xsl:variable>
<xsl:apply-templates mode="pass2"
select="ext:node-set($vrtfPass1)/node()"/>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<one/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/one" mode="pass2" >
<xsl:call-template name="identity"/>
<two/>
</xsl:template>
</xsl:stylesheet>
この変換が次のXMLドキュメントに適用される場合:
<doc/>
必要な結果(最初のパスで要素<one/>
が最上位の要素の子として追加され、次に2番目のパスで最初のパスで作成された別の子, immediately after the element
`が追加されます)が生成されます。
<doc>
<one/>
<two/>
</doc>
FXSLにはこれを行うのに非常に適したテンプレート/関数があります:これはcompose-flist
テンプレートです。これは、パラメーターとして初期データ引数とN個の関数(テンプレート)を取り、これらの関数/テンプレートの連鎖構成を生成します。
FXSLライブラリのテスト例は次のとおりです。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:myFun1="f:myFun1"
xmlns:myFun2="f:myFun2"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="xsl f ext myFun1 myFun2"
>
<xsl:import href="compose.xsl"/>
<xsl:import href="compose-flist.xsl"/>
<!-- to be applied on any xml source -->
<xsl:output method="text"/>
<myFun1:myFun1/>
<myFun2:myFun2/>
<xsl:template match="/">
<xsl:variable name="vFun1" select="document('')/*/myFun1:*[1]"/>
<xsl:variable name="vFun2" select="document('')/*/myFun2:*[1]"/>
Compose:
(*3).(*2) 3 =
<xsl:call-template name="compose">
<xsl:with-param name="pFun1" select="$vFun1"/>
<xsl:with-param name="pFun2" select="$vFun2"/>
<xsl:with-param name="pArg1" select="3"/>
</xsl:call-template>
<xsl:variable name="vrtfParam">
<xsl:copy-of select="$vFun1"/>
<xsl:copy-of select="$vFun2"/>
<xsl:copy-of select="$vFun1"/>
</xsl:variable>
Multi Compose:
(*3).(*2).(*3) 2 =
<xsl:call-template name="compose-flist">
<xsl:with-param name="pFunList" select="ext:node-set($vrtfParam)/*"/>
<xsl:with-param name="pArg1" select="2"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="myFun1:*" mode="f:FXSL">
<xsl:param name="pArg1"/>
<xsl:value-of select="3 * $pArg1"/>
</xsl:template>
<xsl:template match="myFun2:*" mode="f:FXSL">
<xsl:param name="pArg1"/>
<xsl:value-of select="2 * $pArg1"/>
</xsl:template>
</xsl:stylesheet>
この変換が任意のxmlドキュメント(使用されていない)に適用されると、必要な正しい結果が生成されます。
Compose:
(*3).(*2) 3 =
18
Multi Compose:
(*3).(*2).(*3) 2 =
36
注:XSLT 2.0以降では、xxx:node-set()
拡張は不要であり、連鎖変換のいずれも実際の関数に含めることができます。
1 つのアプローチは、モードhttp://www.w3.org/TR/xslt#modesを使用することですが、各ステップを変数に変換し、ノードセット拡張関数を使用して次のステップを適用できるようにする必要があることは正しいです。変数の内容にステップします。