2010-07-12 66 views
0

我有一個系列中型XML文檔,其中主要是文本與代表宏的幾個節點中展開,如:優化<xsl:choose>許多<xsl:when>

<foo>Some text <macro>A1</macro> ... <macro>B2</macro> ...etc...</foo> 

我的目標是,以取代每個宏相應的XML。通常這是一個具有不同屬性的單個<img>標籤,但它也可以是其他一些HTML。

樣式表被編程產生,而要做到這將是有每個宏模板,例如單程

<xsl:template match="macro[.='A1']"> 
    <!-- content goes here --> 
</xsl:template> 
<xsl:template match="macro[.='A2']"> 
    <!-- other content goes here --> 
</xsl:template> 
<xsl:template match="macro[.='B2']"> 
    <!-- etc... --> 
</xsl:template> 

它工作得很好,但它最多可以有一百個宏,它不是很高性能的(我用的libxslt)。我試過一對夫婦的替代,如:

<xsl:template match="macro"> 
    <xsl:choose> 
     <xsl:when test=".='A1'"> 
      <!-- content goes here --> 
     </xsl:when> 
     <xsl:when test=".='A2'"> 
      <!-- other content goes here --> 
     </xsl:when> 
     <xsl:when test=".='B2'"> 
      <!-- etc... --> 
     </xsl:when> 
    </xsl:choose> 
</xsl:template> 

它的性能稍高一些。我曾嘗試加入分支的另一個層面,如:

<xsl:template match="macro"> 
    <xsl:choose> 
     <xsl:when test="substring(.,1,1) = 'A'"> 
      <xsl:choose> 
       <xsl:when test=".='A1'"> 
        <!-- content goes here --> 
       </xsl:when> 
       <xsl:when test=".='A2'"> 
        <!-- other content goes here --> 
       </xsl:when> 
      </xsl:choose> 
     </xsl:when> 
     <xsl:when test=".='B2'"> 
      <!-- etc... --> 
     </xsl:when> 
    </xsl:choose> 
</xsl:template> 

它加載速度稍慢(在XSL是更大,更復雜一點),但它稍快(每個分支可以消除幾種情況。)執行

現在我想知道,有沒有更好的方法來做到這一點?我有大約50-100宏。通常,轉換是使用libxslt執行的,但我不能使用其他XSLT引擎的專有擴展。

任何投入都是歡迎的。

回答

1

這將是另一種方式:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl"> 
    <xsl:variable name="dummy"> 
      <mac id="A1">success</mac> 
      <mac id="A2">fail</mac> 
      <mac id="B1">This <b>fail</b></mac> 
      <mac id="B2">This <b>success</b></mac> 
    </xsl:variable> 
    <xsl:key name="macro" match="mac" use="@id"/> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="macro"> 
     <xsl:variable name="me" select="."/> 
     <xsl:for-each select="document('')"> 
      <xsl:copy-of select="key('macro',$me)/node()"/> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

注意:這是性能:XML解析1,805ms,XSL解析0,483ms,變換0,215ms

+0

奇怪的是,我已經嘗試過類似的東西,但它不起作用,因爲'document('')'返回了源文檔的根,而不是樣式表的根。我剛剛檢查過XSLT規範,實際上,它應該返回樣式表的根目錄,所以無論是我發現了一個錯誤還是我在某處都搞砸了。我會再試一次,並保持更新,謝謝。 – 2010-07-13 00:45:12

+0

確實,這是一個我知道的libxslt錯誤(https://bugzilla.gnome.org/show_bug.cgi?id=549552)雖然我得到了它的工作,並且性能似乎與第二種方法相當上市。如果重複使用相同的宏,看起來它會更好地縮放。 – 2010-07-13 01:14:16

1

如果宏是固定的XML,你可以有一個macros.xml文件是這樣的:

<?xml version="1.0"?> 
<macros> 
    <macro name="A1"><!-- content goes here --></macro> 
    <macro name="A2"><!-- content goes here --></macro> 
</macros> 

然後,您可以:

<xsl:template match="macro"> 
    <xsl:variable name="name" select="text()"/> 
    <xsl:apply-templates select="document(macros.xml)/macros/macro[@name=$name]" mode="copy"/> 
</xsl:template> 

<xsl:template match="*" mode="copy"> 
    <xsl:copy><xsl:copy-of select="*"/> 
     <xsl:apply-templates mode="copy"/> 
    </xsl:copy> 
</xsl:template> 

這會提高性能嗎?

+0

我已經試過'的'但性能更差,這是預期的,因爲它必須訪問外部資源並在其上運行一些XPath。也許我可以在某處使用xsl:key再試一次...感謝雖然:) – 2010-07-12 23:56:40

+0

你有沒有嘗試加載文件到一個變量,並使用它 - 你需要使用擴展來支持變量作爲節點集,但。這將只會載入一次文檔。 – reece 2010-07-13 00:00:22

1

嘗試將所有的macro處理提取到單獨的模板模式中,並且僅針對macro元素的內容運行它。即:

<xsl:template match="macro"> 
    <xsl:apply-templates mode="macro"/> 
</xsl:template> 

<xsl:temlate match="text()[. = 'A1']" mode="macro"> 
    ... 
</xsl:template> 

我懷疑你的情況的放緩是因爲你的規則得到遏制,一個一個,在輸入的每一個節點。這樣,你會得到一張支票,看看它是否是macro,並且只有這樣才能讓內容進一步匹配。

+0

這種方法與我的第一個方法有着相同的性能,由於額外的'而帶來了小小的損失。無論哪種方式,它實際上並不慢,或至少不會比預期的XSL轉換慢。 libxslt做了一個體面的工作,我只是想看看我能否擠出更多的性能。 – 2010-07-13 00:14:49