2012-06-15 102 views
4

嗨,我是Xslt/Xml中的新成員。從XML中對具有相同值的節點進行分組

我有XML這樣的:

<entry> 
<attribute1>A</attribute1> 
<attribute2>B</attribute2> 
</entry> 
<entry> 
<attribute1>A</attribute1> 
<attribute2>B</attribute2> 
</entry> 
<entry> 
<attribute1>C</attribute1> 
<attribute2>D</attribute2> 
</entry> 
<entry> 
<attribute1>E</attribute1> 
<attribute2>F</attribute2> 
</entry> 
... 

我需要的表格輸出:

一個

Attribute1 Attribute2 Qty 
    A   B  2 
    C   D  1 
    E   F  1 

我需要你們的幫助,我不知道怎麼算的唯一條目和顯示它作爲一個表。

我使用XSLT 1.0

回答

3

I.簡單XSLT 1.0轉化

<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="kEntryByChildren" match="entry" use="."/> 

<xsl:template match= 
"entry[not(generate-id() = generate-id(key('kEntryByChildren', .)[1]))]"/> 

<xsl:template match="entry"> 
    <tr> 
    <xsl:apply-templates/> 
    <td><xsl:value-of select="count(key('kEntryByChildren', .))"/></td> 
    </tr> 
</xsl:template> 

<xsl:template match="entry/*"> 
    <td><xsl:value-of select="."/></td> 
</xsl:template> 

<xsl:template match="/*"> 
    <table> 
    <xsl:apply-templates/> 
    </table> 
</xsl:template> 
</xsl:stylesheet> 

當所提供的XML施加(該片段被包裹ITO單個頂部元件以獲得良好的XML文檔) :

<t> 
    <entry> 
     <attribute1>A</attribute1> 
     <attribute2>B</attribute2> 
    </entry> 
    <entry> 
     <attribute1>A</attribute1> 
     <attribute2>B</attribute2> 
    </entry> 
    <entry> 
     <attribute1>C</attribute1> 
     <attribute2>D</attribute2> 
    </entry> 
    <entry> 
     <attribute1>E</attribute1> 
     <attribute2>F</attribute2> 
    </entry> 
</t> 

產生想要的,正確的結果

<table> 
    <tr> 
     <td>A</td> 
     <td>B</td> 
     <td>2</td> 
    </tr> 
    <tr> 
     <td>C</td> 
     <td>D</td> 
     <td>1</td> 
    </tr> 
    <tr> 
     <td>E</td> 
     <td>F</td> 
     <td>1</td> 
    </tr> 
</table> 

當這個棘手的XML文檔上應用(如果我們用孩子們的值的簡單拼接,我們會錯誤地得出這樣的結論前三entry元素是「相同」):

<t> 
    <entry> 
     <attribute1>AB</attribute1> 
     <attribute2>C</attribute2> 
    </entry> 
    <entry> 
     <attribute1>A</attribute1> 
     <attribute2>BC</attribute2> 
    </entry> 
    <entry> 
     <attribute1>A</attribute1> 
     <attribute2>BC</attribute2> 
    </entry> 
    <entry> 
     <attribute1>C</attribute1> 
     <attribute2>D</attribute2> 
    </entry> 
    <entry> 
     <attribute1>E</attribute1> 
     <attribute2>F</attribute2> 
    </entry> 
</t> 

正確的結果產生:

<table> 
    <tr> 
     <td>AB</td> 
     <td>C</td> 
     <td>1</td> 
    </tr> 
    <tr> 
     <td>A</td> 
     <td>BC</td> 
     <td>2</td> 
    </tr> 
    <tr> 
     <td>C</td> 
     <td>D</td> 
     <td>1</td> 
    </tr> 
    <tr> 
     <td>E</td> 
     <td>F</td> 
     <td>1</td> 
    </tr> 
</table> 

說明

正確使用Muenchian grouping method

請注意

  1. 該解決方案不依賴於一個entry元素的子元素的名稱和數量,從而可以應用,如果有兩個以上的孩子,或不同數量的未知名稱的兒童。

  2. 在這裏,我們假設只有當相同的孩子具有相同的值時,所有兒童的字符串值的連接纔是相同的。


II。全XSLT 1.0溶液

在殼體上面的假設2不能保證,這是一種可能的XSLT 1.0溶液:

<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:template match="entry"> 
    <xsl:variable name="vChildrenFp"> 
    <xsl:for-each select="*"> 
    <xsl:value-of select="concat(., '+')"/> 
    </xsl:for-each> 
    </xsl:variable> 

    <xsl:variable name="vPrecedingSame"> 
    <xsl:for-each select="preceding-sibling::entry"> 
    <xsl:variable name="vthisFP"> 
     <xsl:for-each select="*"> 
     <xsl:value-of select="concat(., '+')"/> 
     </xsl:for-each> 
    </xsl:variable> 

    <xsl:if test="$vthisFP = $vChildrenFp">1</xsl:if> 
    </xsl:for-each> 
    </xsl:variable> 

    <xsl:if test="not(string($vPrecedingSame))"> 
     <xsl:variable name="vFollowingSame"> 
     <xsl:for-each select="following-sibling::entry"> 
     <xsl:variable name="vthisFP"> 
      <xsl:for-each select="*"> 
      <xsl:value-of select="concat(., '+')"/> 
      </xsl:for-each> 
     </xsl:variable> 

     <xsl:if test="$vthisFP = $vChildrenFp">1</xsl:if> 
     </xsl:for-each> 
     </xsl:variable> 

     <tr> 
     <xsl:apply-templates/> 
     <td><xsl:value-of select="string-length($vFollowingSame)+1"/></td> 
     </tr> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="entry/*"> 
    <td><xsl:value-of select="."/></td> 
</xsl:template> 

<xsl:template match="/*"> 
    <table> 
    <xsl:apply-templates/> 
    </table> 
</xsl:template> 
</xsl:stylesheet> 

當在同一個XML文檔(以上)應用中,相同的正確的結果產生:

<table> 
    <tr> 
     <td>A</td> 
     <td>B</td> 
     <td>2</td> 
    </tr> 
    <tr> 
     <td>C</td> 
     <td>D</td> 
     <td>1</td> 
    </tr> 
    <tr> 
     <td>E</td> 
     <td>F</td> 
     <td>1</td> 
    </tr> 
</table> 

說明

  1. 對於每個entry元素,我們產生了兒童和過程的「指紋」(FP),如果沒有它的前置兄弟entry元素具有相同的孩子的指紋此entry元素。

  2. 「相同」entry元素的計數以類似的方式完成 - 對於具有相同子女FP值的任何後續兄弟entry元素,我們輸出單個字符('1')。總計數是(「1」或多個),從而生成的字符串的字符串長度加1。


III。 XSLT 2.0溶液

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:my="my:my" exclude-result-prefixes="my xs"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:param name="pExoticString" select="'+'"/> 

<xsl:template match="/*"> 
    <table> 
    <xsl:for-each-group select="entry" group-by="my:fingerprint(.)"> 
     <tr> 
      <xsl:apply-templates/> 
      <td><xsl:value-of select="count(current-group())"/></td> 
     </tr> 
    </xsl:for-each-group> 
    </table> 
</xsl:template> 

<xsl:template match="entry/*"> 
    <td><xsl:value-of select="."/></td> 
</xsl:template> 

<xsl:function name="my:fingerprint" as="xs:string"> 
    <xsl:param name="pParent" as="element()"/> 

    <xsl:sequence select="string-join($pParent/*, $pExoticString)"/> 
</xsl:function> 
</xsl:stylesheet> 

這個簡單的解決方案很容易地處理複雜情況。當最後一個XML文檔應用,通緝,正確的結果產生

<table> 
    <tr> 
      <td>AB</td> 
      <td>C</td> 
     <td>1</td> 
    </tr> 
    <tr> 
      <td>A</td> 
      <td>BC</td> 
     <td>2</td> 
    </tr> 
    <tr> 
      <td>C</td> 
      <td>D</td> 
     <td>1</td> 
    </tr> 
    <tr> 
      <td>E</td> 
      <td>F</td> 
     <td>1</td> 
    </tr> 
</table> 

說明

正確使用xsl:for-each-groupxsl:functioncurrent-group()string-join()

+0

這就是我在找的。非常感謝 ! – user1458987

+0

@ user1458987:不客氣。 –

4

就拿這短短的,只是爲出發點:

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

    <xsl:key name="keys" match="entry" use="concat(attribute1,'|',attribute2)"/> 

    <xsl:template match="/test"> 
     <xsl:apply-templates select="entry[ 
      generate-id() 
      = generate-id(key('keys',concat(attribute1,'|',attribute2))[1])]"/> 
    </xsl:template> 

    <xsl:template match="entry"> 
     <xsl:value-of select="concat(
      attribute1,' ', 
      attribute2,' ', 
      count(key('keys',concat(attribute1,'|',attribute2))),'&#10;')"/> 
    </xsl:template> 

</xsl:stylesheet> 

如果你是新來的XSLT,瞭解這種轉變,您需要了解:

  • XSLT輸出方法
  • 的xsl:關鍵元件
  • Meunchi分組
  • xpath連續和計數功能
  • xpath |工會
相關問題