2012-04-10 40 views
1

我有一個問題,在使用XSLT通過屬性對xml entrys進行分組。缺少第一個元素在for-each循環與前兄弟在xslt

這裏是我的XML源:

<chron> 
<chronEntry type="education" order="1" blockorder="1"> 
    <foo>bar</foo> 
</chronEntry> 
    <chronEntry type="education" order="2" blockorder="1"> 
<foo>bar</foo> 
    </chronEntry> 
<chronEntry type="education" order="3" blockorder="1"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="communityservice" order="1" blockorder="2"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="experience" order="1" blockorder="3"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="experience" order="2" blockorder="3"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="experience" order="3" blockorder="3"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="experience" order="4" blockorder="3"> 
    <foo>bar</foo> 
</chronEntry> 
</chron> 

我想要得到的是屬性「類型」的所有可用值的列表。在這種情況下,它應該是: - 教育 - communityservice - 經驗

我tryed它是這樣的:

<xsl:for-each select="/foobar/chron/chronEntry"> 
      <xsl:sort select="@blockorder"/> 
       <xsl:if test ="@blockorder != preceding-sibling::chronEntry[1]/@blockorder"> 
        <fo:table-row> 
         <fo:table-cell> 
          <fo:block><xsl:value-of select="@type"/></fo:block> 
         </fo:table-cell> 
        </fo:table-row> 
       </xsl:if> 
      </xsl:for-each> 

什麼,我得到的是: - communityservice - 經驗

我缺少「教育」(第一個)

我能做些什麼來得到它?

Thaks爲您提供幫助!

格爾茨

戴夫

+0

你使用XSLT 1.0或XSLT 2.0? – 2012-04-10 12:30:33

回答

1

的問題是,雖然你正在創建一個排序的節點列表中,preceding-sibling::(或軸)只可以用來表達節點之間關係的文件中(而不是在一個節點列表)。

因此,preceding-sibling:: chronEntry [1]在當前文檔在上下文節點selects the first preceding sibling chronEntry` - 未在分類節點列表。

  1. 在XSLT 1.0捕獲在變量中xsl:for-each的結果。由於這是臭名昭着的RTF類型,因此必須使用正在使用的XSLT 1.0處理器支持的xxx:node-set()擴展函數將其轉換爲常規樹。然後,在這個常規樹中,包含preceding-sibling::的座標軸具有所需的含義。

  2. 推薦的解決方案。使用Muenchian分組的:

這樣的:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kType" match="@type" use="."/> 

<xsl:template match= 
    "chronEntry 
    [generate-id(@type) 
    = 
    generate-id(key('kType', @type)[1]) 
    ]"> 
    <xsl:value-of select="concat(@type, ' ')"/> 
</xsl:template> 
<xsl:template match="text()"/> 
</xsl:stylesheet> 

當這種轉變是在所提供的XML文檔應用:

<chron> 
    <chronEntry type="education" order="1" blockorder="1"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="education" order="2" blockorder="1"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="education" order="3" blockorder="1"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="communityservice" order="1" blockorder="2"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="experience" order="1" blockorder="3"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="experience" order="2" blockorder="3"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="experience" order="3" blockorder="3"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="experience" order="4" blockorder="3"> 
     <foo>bar</foo> 
    </chronEntry> 
</chron> 

想要的,正確的結果產生

education communityservice experience 
0

你是否真的需要xsl:sort?還是你用它來分組?如果是這樣,你可以刪除了xsl:排序和糾正你的xsl:如果測試:

 <xsl:for-each select="/foobar/chron/chronEntry"> 
      <xsl:if test ="not(@blockorder = preceding-sibling::chronEntry/@blockorder)"> 
       <fo:table-row> 
        <fo:table-cell> 
         <fo:block><xsl:value-of select="@type"/></fo:block> 
        </fo:table-cell> 
       </fo:table-row> 
      </xsl:if> 
     </xsl:for-each> 

如果您需要在xsl:排序,你可以這樣做:

 <xsl:variable name="types" select="/foobar/chron/chronEntry[not(preceding-sibling::*/@[email protected])]"/> 
     <xsl:for-each select="$types"> 
      <xsl:sort select="@blockorder"/> 
      <fo:table-row> 
       <fo:table-cell> 
        <fo:block> 
         <xsl:value-of select="@type"/> 
        </fo:block> 
       </fo:table-cell> 
      </fo:table-row> 
     </xsl:for-each>