2011-09-27 64 views
3

我有類似這樣的XML:如何使用XSLT對值進行排序?

<Test> 
    <grapes> 
    <a>TypeA</a> 
    <b>value1</b> 
    </grapes> 
    <oranges> 
    <a>TypeB</a> 
    <b>value2</b> 
    </oranges> 
    <apples> 
    <a>TypeA</a> 
    <b>value3</b> 
    </apples> 
</Test> 

其中的值是唯一的,但類型,可能是相同的。

我想,這樣的輸出與此類似對它進行排序:

<group type="TypeA"> 
    <value v="value1" /> 
    <value v="value3" /> 
</group> 
<group type="TypeB"> 
    <value v="value2" /> 
</group> 

我有一個很難確保各組都在輸出獨特的價值觀是正確的小組。

我的XSL應該如何構造?

+1

由於我沒有看到標題分組,我只是想澄清:你想組_and then_排序? – btlachance

+0

非常有用的問題(和很好的答案)。我同意標題應該改寫,因爲這是一個常見問題,如果他們能夠更好地發現這個問題是他們的問題,那麼答案會對許多人感興趣。 –

回答

1

XSLT 1.0:

您可以通過使用muenchian方法的類型創造獨特的羣體開始。谷歌它找出它是什麼。然後,它只是一個通過他們迭代的物質和printint出你想要什麼,你想要的:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output method="xml" indent="yes"/> 
<xsl:key name="types" match="a" use="text()"/> 
<xsl:template match="/"> 
<result> 
    <xsl:for-each select="//a[generate-id(.) = generate-id(key('types', text())[1])]"> 
    <group type="{current()/text()}"> 
     <xsl:for-each select="//a[text() = current()/text()]"> 
     <xsl:variable name="values" select="following-sibling::b | preceding-sibling::b"/> 
     <xsl:for-each select="$values"> 
      <value v="{current()}"/> 
     </xsl:for-each> 
     </xsl:for-each> 
    </group> 
    </xsl:for-each> 
</result> 
</xsl:template> 
</xsl:stylesheet> 

你會發現,輸出等同於你所期望的。

+0

謝謝,就是這樣。 – deken

+1

確保你明白這裏寫的是什麼。如果你有任何問題隨時問。 – FailedDev

+0

你能解釋一下這裏發生了什麼嗎? //生成id(。)= generate-id(key('types',text())[1])] – deken

0

我的建議是從FailedDev的略有不同:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" /> 

    <xsl:template match="/Test"> 
    <root> 
     <xsl:for-each select="*[a != following::a]"> 
     <xsl:sort select="a" data-type="text" /> 
     <group type="{a}"> 
      <xsl:for-each select="/Test/*[a = current()/a]"> 
      <xsl:sort select="b" data-type="text" /> 
      <value v="{b}" /> 
      </xsl:for-each> 
     </group> 
     </xsl:for-each> 
    </root> 
    </xsl:template> 
</xsl:stylesheet> 

<xsl:for-each select="*[a != following::a]" /> 

選擇所有獨特類型,即。 TypeATypeB。 的

<xsl:sort select="a" data-type="text" /> 

這些根據名稱,確保類型A上方會出現的TypeB排序。 內

<xsl:for-each select="/Test/*[a = current()/a]" /> 

選擇用於每種類型的唯一值的列表,即。對於TypeAvalue1value3被提取。再次,結果列表被排序以在值3之前列出值1

+0

非常錯誤 - 當其中一個操作數是節點集時,不要使用「!=」運算符。 -1。另外,在發佈之前,請始終運行/測試您提出的解決方案! –

+0

這是測試似乎沒有問題的工作。 雖然我會同意你的解決方案與Muenchian分組可能是要走的路。 – Malibak

+2

@_Mace:你的回答是錯誤的 - 你只是很幸運,它在提供的XML文檔上「起作用」。與此XML文檔嘗試一下,看看它產生*兩組*爲 「類型A」:' 類型A 值1 的TypeB 值2 TypeA value3 的TypeB VALUE4 ' –

2

這裏是一個更簡單的解決(完全 「推式」,沒有<xsl:for-each>,沒有嵌套,沒有<xsl:variable>,沒有current(),沒有//,無軸):

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

<xsl:key name="kGoodsByType" match="/*/*" use="a"/> 

<xsl:template match= 
    "/*/*[generate-id() 
     = 
     generate-id(key('kGoodsByType', a)[1]) 
     ] 
    "> 
    <group type="{a}"> 
     <xsl:apply-templates select="key('kGoodsByType', a)/b"/> 
    </group> 
</xsl:template> 

<xsl:template match="b"> 
    <value v="{.}"/> 
</xsl:template> 

<xsl:template match="*/* | text()" priority="-1"/> 
</xsl:stylesheet> 

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

<Test> 
    <grapes> 
     <a>TypeA</a> 
     <b>value1</b> 
    </grapes> 
    <oranges> 
     <a>TypeB</a> 
     <b>value2</b> 
    </oranges> 
    <apples> 
     <a>TypeA</a> 
     <b>value3</b> 
    </apples> 
</Test> 

通緝,協rrect結果產生

<group type="TypeA"> 
    <value v="value1"/> 
    <value v="value3"/> 
</group> 
<group type="TypeB"> 
    <value v="value2"/> 
</group> 

說明:使用爲重點的a孩子的字符串值/*/*Muenchian grouping

二, XSLT 2.0溶液

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

<xsl:template match="/*"> 
    <xsl:for-each-group select="*/a" group-by="."> 
    <group type="{current-grouping-key()}"> 
    <xsl:sequence select="current-group()/../b"/> 
    </group> 
    </xsl:for-each-group> 
</xsl:template> 
</xsl:stylesheet> 

當在同一個XML文檔(上文)中進行這種轉化,相同的正確的結果產生

<group type="TypeA"> 
    <b>value1</b> 
    <b>value3</b> 
</group> 
<group type="TypeB"> 
    <b>value2</b> 
</group> 

說明

  1. <xsl:for-each-group>

  2. current-group()

  3. current-grouping-key()

相關問題