2017-09-13 17 views
1

私は現在、XSLTファイルを使用してXMLファイル(多くのマークアップ言語)を別のXMLファイル(純粋なテキスト)に転送しています。処理時間が長すぎます。XSLT処理時間を短縮する方法

私は、このような別のfor-eachfor-eachを使用していますので、これは推測: element&attribute

<xsl:for-each select="/data/row"> 
    <xsl:variable name="ROW_"> 
    <xsl:value-of select="count(./preceding-sibling::*) + 1"/> 
    </xsl:variable> 
    <xsl:for-each select='/Header/*[starts-with (text(), 'Car')] '> 
    <xsl:variable name="COLUMN_"> 
     <xsl:value-of select="count(./preceding-sibling::*) + 1"/> 
    </xsl:variable> 
    <xsl:value-of select="/data/row[position()=$ROW_]/@*[position()=$COLUMN_]"/> 
    <xsl:value-of select ="$Delimiter"/> 
    </xsl:for-each> 
</xsl:for-each> 

だから私は、処理時間を改善するために何ができるのでしょうか?

+1

あなたが 'position()'の代わりに 'count(./ preceding-sibling :: *)'を使っているからです。しかし、[mcve]がなければ、それは唯一の推測です。パフォーマンスはプロセッサ固有であることにも注意してください。 –

答えて

5

このコードには多くの非効率性があり、私は小さなものから始めます。

ONE

<xsl:variable name="ROW_"> 
    <xsl:value-of select="count(./preceding-sibling::*) + 1"/> 
    </xsl:variable> 

XSL絶対に使用しないでください:あなたは本当に一時的なXMLのツリー構造を作成する場合を除き、価値の:含まれるXSLを持つ変数を。これは、文字列に変換テキストノードに文字列を変換し、ドキュメントノードを作成し、それをあなたが(数()付き)整数値を計算している、あなたの方法をやって

<xsl:variable name="ROW_" select="count(./preceding-sibling::*) + 1"/> 

を書くためにはるかに効率的ですテキストノードを文書ノードに追加するステップと、述語[position()=$ROW_]で変数を使用すると、すべてのテキストノードを見つけて連結し、その結果を整数に変換することによって、文書ノードの文字列値を取得します。変数を最初に整数にバインドする方が良いでしょう!

TWO

<xsl:for-each select='/Header/*[starts-with (text(), 'Car')] '> 

これは、外側のxsl以内に表示されますのために、それぞれ、それが繰り返し実行されますが、/Header/*[starts-with (text(), 'Car')]の結果は毎回同じであるので、それはで何かに依存しませんループ。スマート・オプティマイザは、式をループから外します(これは、「/」が毎回同じルート・ノードを選択することに依存するため、これは自明ではありません。これは、for-eachの外側が単一-documentノード集合)。そのスマートなオプティマイザに頼るのではなく、式/Header/*[starts-with (text(), 'Car')]を変数にバインドします。

THREE

<xsl:value-of select="/data/row[position()=$ROW_]/@*[position()=$COLUMN_]"/> 

これはおそらく重要なものです:すべての行を処理ループ内で、あなたはすべての行を処理ループを持っているので、あなたはすぐにOを持っている(nは^ 2)パフォーマンス:入力サイズを2倍にすると、実行時間は4倍になります。

また、Saxon-EEのようなスマートなオプティマイザはこれを並べ替えるでしょう(コンストラクトはSQLのジョインのようなものであり、ジョインの最適化は十分に確立された技術です)。しかし、オープンソースのプロセッサを使用している場合は、オプティマイザがスマートではない可能性があるので、手動で最適化する必要があります。これはやりにくいことではありません。選択されているのは、外側のfor-eachが現在処理中のものになります。

FOUR

@*[position()=$COLUMN_] 

あなたはここでの問題を持っている、それがパフォーマンスの問題ではありません。特定の順序で配信される属性(対応するHEADER要素と同じ順序)に依存しており、それは安全ではありません。あなたは単に属性の順序に頼ることができないので、出力の順序を制御する他の方法を見つける必要があります。その問題を無視

は、私はあなたのコードがに削減思う:

<xsl:variable name="headers" 
    select='/Header/*[starts-with (text(), 'Car')] '/> 
<xsl:for-each select="/data/row"> 
    <xsl:variable name="thisRow" select="."/> 
    <xsl:for-each select='$headers'> 
    <xsl:variable name="COLUMN_" 
     select="count(./preceding-sibling::*) + 1"/> 
    <xsl:value-of select="$thisRow/@*[position()=$COLUMN_]"/> 
    <xsl:value-of select ="$Delimiter"/> 
    </xsl:for-each> 
</xsl:for-each> 

(変数名の末尾にアンダースコアの意義何不要な難読化のそのようなものは、私は本当にイライラを取得します...?)

関連する問題