2015-05-29 58 views
1

我有那些不以任何特定的排序順序條目的CD列表:獲取上一個元素在XSLT 1.0排序順序,而不是DOM爲了

<?xml version="1.0" encoding="UTF-8"?> 
<catalog> 
    <cd> 
     <title>Empire Burlesque</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Hide your heart</title> 
     <artist>Bonnie Tyler</artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    <cd> 
     <title>Greatest Hits</title> 
     <artist>Dolly Parton</artist> 
     <country>USA</country> 
     <company>RCA</company> 
     <price>9.90</price> 
     <year>1982</year> 
    </cd> 
    <cd> 
     <title>Still got the blues</title> 
     <artist>Gary Moore</artist> 
     <country>UK</country> 
     <company>Virgin records</company> 
     <price>10.20</price> 
     <year>1990</year> 
    </cd> 
</catalog> 

我想輸出HTML中的列表中,由分組標題的第一個字母。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" version="1.0"> 
    <xsl:output method="xml" indent="yes" /> 
    <xsl:template match="catalog"> 
     <catalog> 
      <xsl:apply-templates select="cd"><xsl:sort select="title"/></xsl:apply-templates> 
     </catalog> 
    </xsl:template> 
    <xsl:template match="cd"><xsl:copy-of select="."/></xsl:template> 
</xsl:stylesheet> 

,然後讓我用preceding-sibling檢查標題字母的變化:由於躲避我怎麼了,我先通過一個簡單的排序跑了XML。所得片材是這樣的:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
    <html> 
     <head> 
     <title> Booklist with books <xsl:value-of select="count(/catalog/cd)"/> 
     </title> 
     <style type="text/css"> 
      table.main {width : 100%} 
      table.main td {padding : 2px; border-bottom : 1px solid gray} 
      th {text-align : left} 
      tr.header {background-color : #9acd32} 
      table.bar {border: 1px solid gray; background-color #CACACA} 
      table.bar td {border-left : 1px solid gray; padding : 4px; margin : 2px; font-size : x-large} 
      tr.firstbook {background-color : #CACACA} 
      td.firstbook {font-size : xx-large} 
      td.firstbook a.up {text-decoration: none; font-size : normal} 
     </style> 
     </head> 
     <body> 
     <xsl:apply-templates mode="header"/> 
     <xsl:apply-templates/> 
     </body> 
    </html> 
    </xsl:template> 

    <xsl:template match="catalog"> 
    <table class="main"> 
     <tr class="header"> 
     <th> Title </th> 
     <th> Artist </th> 
     <th> Country </th> 
     <th> Company </th> 
     <th> Price </th> 
     <th> Year </th> 
     </tr> 
     <xsl:apply-templates select="cd"> 
     <xsl:sort select="title"/> 
     </xsl:apply-templates> 
    </table> 
    </xsl:template> 

    <xsl:template match="cd"> 
    <xsl:variable name="firstLetter" select="substring(title,1,1)"/> 
    <xsl:variable name="oldLetter" select="substring(preceding-sibling::*[1]/title,1,1)"/> 

    <xsl:if test="not($firstLetter=$oldLetter)"> 
     <tr class="firstbook"> 
     <td class="firstbook" colspan="5"> 
      <a name="{$firstLetter}"> 
      <xsl:value-of select="$firstLetter"/> 
      </a> 
     </td> 
     <td class="firstbook"> 
      <a class="up" href="#">&#11014;</a> 
     </td> 
     </tr> 
    </xsl:if> 

    <tr> 
     <td> 
     <xsl:value-of select="title"/> 
     </td> 
     <td> 
     <xsl:value-of select="artist"/> 
     </td> 
     <td> 
     <xsl:value-of select="country"/> 
     </td> 
     <td> 
     <xsl:value-of select="company"/> 
     </td> 
     <td> 
     <xsl:value-of select="price"/> 
     </td> 
     <td> 
     <xsl:value-of select="year"/> 
     </td> 
    </tr> 
    </xsl:template> 

    <!-- Header link handling --> 
    <xsl:template match="catalog" mode="header"> 
    <table class="bar"> 
     <tr> 
     <xsl:apply-templates mode="header" 
      select="cd[not(substring(title,1,1)=substring(preceding-sibling::*[1]/title,1,1))]"> 
      <xsl:sort select="title"/> 
     </xsl:apply-templates> 
     </tr> 
    </table> 
    </xsl:template> 

    <xsl:template mode="header" match="cd"> 
    <xsl:variable name="firstLetter" select="substring(title,1,1)"/> 
    <td> 
     <a href="#{$firstLetter}"> 
     <xsl:value-of select="$firstLetter"/> 
     </a> 
    </td> 
    </xsl:template> 

</xsl:stylesheet> 

的關鍵部分是該比較:not(substring(title,1,1)=substring(preceding-sibling::*[1]/title,1,1))看起來在DOM和不排序操作的結果。

我正在尋找的是在XSLT-1.0的方式來結合兩個轉變的效果,所以我有一個樣式,一個未排序的輸入列表,並且看起來像兩個樣式目前生產的結果:

Screenshot from the XSLT result

我該怎麼辦呢?

+3

對於XSLT 1.0中的*分組*,請參閱http://www.jenitennison.com/xslt/grouping/muenchian.html以及SO上的許多許多示例。 –

回答

1

您可以先對變量進行排序(然後在XSLT中是一個結果樹片段),那麼您可以使用擴展功能,如exsl:node-set將結果樹片段轉換爲一個節點集,以便與您的現有進一步處理碼。

所以,你需要兩個變化,catalog模板必須是

<xsl:template match="catalog"> 
    <table class="main"> 
     <tr class="header"> 
     <th> Title </th> 
     <th> Artist </th> 
     <th> Country </th> 
     <th> Company </th> 
     <th> Price </th> 
     <th> Year </th> 
     </tr> 
     <xsl:variable name="sorted-cds"> 
     <xsl:for-each select="cd"> 
      <xsl:sort select="title"/> 
      <xsl:copy-of select="."/> 
     </xsl:for-each> 
     </xsl:variable> 
     <xsl:apply-templates select="exsl:node-set($sorted-cds)/cd"/> 
    </table> 
    </xsl:template> 

和樣式表根有權宣佈exsl命名空間:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:exsl="http://exslt.org/common" 
    exclude-result-prefixes="exsl"> 

請注意,並非所有的XSLT處理器支持exsl:node-set而他們通常在專有名稱空間中至少支持一個類似的擴展函數。因此,假如你想使用微軟的MSXML(例如Internet Explorer的內部),那麼你需要使用<xsl:apply-templates select="ms:node-set($sorted-cds)/cd"/>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ms="urn:schemas-microsoft-com:xslt" 
    exclude-result-prefixes="ms"> 
1

THX來提供的鏈接我的@ michael.hor我又不得不看看Muenchian。我不知道你實際上可以在substring()上使用這種技術。另外我不是for-each的大粉絲。

原來,我可以使用模板匹配和功能的鍵。因此,解決辦法,運行的擴展函數,獨立於當前的XSLT引擎(從來沒有在IE瀏覽器進行測試,沒有那個在我的Linux或Mac)看起來是這樣的:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="html"/> 
    <xsl:key name="cd-by-letter" match="cd" use="substring(title,1,1)"/> 

    <xsl:template match="/"> 
    <html> 
     <head> 
     <title> Booklist with books <xsl:value-of select="count(/catalog/cd)"/> 
     </title> 
     <style type="text/css"> 
      table.main {width : 100%} 
      table.main td {padding : 2px; border-bottom : 1px solid gray} 
      th {text-align : left} 
      tr.header {background-color : #9acd32} 
      table.bar {border: 1px solid gray; background-color #CACACA} 
      table.bar td {border-left : 1px solid gray; padding : 4px; margin : 2px; font-size : x-large} 
      tr.firstbook {background-color : #CACACA} 
      td.firstbook {font-size : xx-large} 
      td.firstbook a.up {text-decoration: none; font-size : normal} 
     </style> 
     </head> 
     <body> 
     <xsl:apply-templates mode="header"/> 
     <xsl:apply-templates/> 
     </body> 
    </html> 
    </xsl:template> 

    <xsl:template match="catalog"> 
    <table class="main"> 
     <tr class="header"> 
     <th> Title </th> 
     <th> Artist </th> 
     <th> Country </th> 
     <th> Company </th> 
     <th> Price </th> 
     <th> Year </th> 
     </tr> 

     <xsl:apply-templates select="cd[count(. | key('cd-by-letter', substring(title,1,1))[1]) = 1]"> 
     <xsl:sort select="title"/> 
     </xsl:apply-templates> 
    </table> 
    </xsl:template> 

    <xsl:template match="cd"> 
    <xsl:variable name="firstLetter" select="substring(title,1,1)"/> 

    <tr class="firstbook"> 
     <td class="firstbook" colspan="5"> 
     <a name="{$firstLetter}"> 
      <xsl:value-of select="$firstLetter"/> 
     </a> 
     </td> 
     <td class="firstbook"> 
     <a class="up" href="#">&#11014;</a> 
     </td> 
    </tr> 

    <xsl:apply-templates select="key('cd-by-letter',$firstLetter)" mode="group"> 
     <xsl:sort select="title"/> 
    </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="cd" mode="group"> 
    <tr> 
     <td> 
     <xsl:value-of select="title"/> 
     </td> 
     <td> 
     <xsl:value-of select="artist"/> 
     </td> 
     <td> 
     <xsl:value-of select="country"/> 
     </td> 
     <td> 
     <xsl:value-of select="company"/> 
     </td> 
     <td> 
     <xsl:value-of select="price"/> 
     </td> 
     <td> 
     <xsl:value-of select="year"/> 
     </td> 
    </tr> 
    </xsl:template> 

    <!-- Header link handling --> 
    <xsl:template match="catalog" mode="header"> 
    <table class="bar"> 
     <tr> 
     <xsl:apply-templates mode="header" 
      select="cd[count(. | key('cd-by-letter', substring(title,1,1))[1]) = 1]"> 
      <xsl:sort select="title"/> 
     </xsl:apply-templates> 
     </tr> 
    </table> 
    </xsl:template> 

    <xsl:template mode="header" match="cd"> 
    <xsl:variable name="firstLetter" select="substring(title,1,1)"/> 
    <td> 
     <a href="#{$firstLetter}"> 
     <xsl:value-of select="$firstLetter"/> 
     </a> 
    </td> 
    </xsl:template> 

</xsl:stylesheet> 

THX大家的幫助!