2017-09-13 76 views
1

我目前使用XSLT文件將XML文件(很多標記語言)轉移到另一個XML文件(純文本)。處理時間太長。如何加快XSLT處理時間

我想這是因爲我使用的是for-each內的另一個for-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

我的猜測是因爲你正在使用'count(./ preceding-sibling :: *)'而不是'position()'。但沒有[mcve]這只是一個猜測。另請注意,性能是針對處理器的。 –

回答

5

這段代碼有很多低效率,我會從小的開始。

ONE

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

切勿使用一個xsl:用包含變量的xsl:value-of的,除非你真的想創建一個臨時的XML樹結構。這是更有效的寫

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

做你的方式,你計算的整數值(以計數()),將其轉換爲字符串,字符串轉換爲文本節點,創建文檔節點,並將文本節點附加到文檔節點;當您在謂詞[position()=$ROW_]中使用變量時,您將通過查找並連接其所有文本節點並將結果轉換爲整數來獲取文檔節點的字符串值。首先將變量綁定到一個整數更好!

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

這似乎是一個外部XSL中:對,每次,所以它的重複執行,但/Header/*[starts-with (text(), 'Car')]結果是每一次一樣,它不依賴於任何循環。智能優化器將把表達式移出循環(這不是微不足道的,因爲它依賴於認識到「/」每次都會選擇相同的根節點,這是唯一的,因爲外部的for-each選擇了一個 - 文檔節點集)。不要依賴優化器的智能,而要將表達式/Header/*[starts-with (text(), 'Car')]綁定到變量。

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

這可能是關鍵的一年:一個循環,處理所有的行內,你有一個循環,處理所有的行,讓你立刻起身爲O(n^2)性能:將輸入大小加倍,執行時間增加四倍。

再一次,像Saxon-EE這樣的智能優化器可能會對此進行分類(構造就像是SQL中的連接,並且連接的優化是一種成熟的技術)。但是,如果你使用的是開源處理器,那麼它的優化器可能不是那麼聰明,所以你必須手動優化它,這並不難:它在我看來就像是你的行正在選擇將是每個目前正在處理的外部對象。

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> 

(什麼是下劃線在變量名末尾的意義那種不必要的混淆讓我真的很惱火......)