2009-06-18 9 views
1
<statisticItems> 
    <statisticItem id="1" frontendGroupId="2336" caseId="50264" /> 
    <statisticItem id="2" frontendGroupId="2336" caseId="50264" /> 
    <statisticItem id="3" frontendGroupId="2337" caseId="50265" /> 
    <statisticItem id="4" frontendGroupId="2337" caseId="50266" /> 
    <statisticItem id="5" frontendGroupId="2337" caseId="50266" /> 
</statisticItems> 

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

    <xsl:key name="statistic-by-frontendGroupId" match="statisticItem" use="@frontendGroupId" /> 

    <xsl:for-each select="statisticItems/statisticItem[count(.|key('statistic-by-frontendGroupId', @frontendGroupId)[1]) = 1]"> 
     <xsl:value-of select="@frontendGroupId"/> 
    </xsl:for-each> 

Ce que j'ai fait, c'est de parcourir tous les frontendGroupId distict. Qu'est-ce que je voudrais faire maintenant est de faire un compte de tous les cas de distict pour chaque distend frontendGroupId mais je ne peux pas sembler faire ce travail. Quelqu'un peut-il m'aider ici plz?Xslt distinct select/Group par

Répondre

0

Vous essayez de trier via la méthode redoutée 'MUENCHIAN' - quelque chose que j'ai trouvé si confus que cela ne vaut pas la peine d'essayer - alors j'ai élaboré ma propre méthode.

Il utilise deux transformations au lieu d'une seule.

Les premières trie les données dans le bon ordre en fonction de vos besoins de regroupement - vos données d'échantillon est déjà dans le bon ordre pour que je vais laisser sortir de cette explication (demandez si vous voulez de l'aide ici)

la deuxième transformation fait le groupement simplement en comparant un nœud à l'autre:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 


    <xsl:template match="statisticItems"> 
     <groupedItem> 
      <xsl:apply-templates select="statisticItem"></xsl:apply-templates> 
     </groupedItem> 
    </xsl:template> 

    <xsl:template match="statisticItem"> 
     <xsl:choose> 

      <xsl:when test="position()=1"> 
       <xsl:apply-templates select="@frontendGroupId" /> 
      </xsl:when> 

      <xsl:when test="@frontendGroupId!=preceding-sibling::statisticItem[1]/@frontendGroupId"> 
       <xsl:apply-templates select="@frontendGroupId" /> 
      </xsl:when> 

     </xsl:choose> 

     <xsl:apply-templates select="@caseId" /> 


    </xsl:template> 

<xsl:template match="@frontendGroupId"> 
    <group> 
     <xsl:variable name="id" select="." ></xsl:variable> 
     <xsl:attribute name="count"> 
      <xsl:value-of select="count(//statisticItem/@frontendGroupId[.=$id])"/> 
     </xsl:attribute>   
     <xsl:value-of select="." /> 
    </group> 
</xsl:template> 

    <xsl:template match="@caseId"> 
     <value> 
      <xsl:value-of select="." /> 
     </value> 
    </xsl:template> 

</xsl:stylesheet> 

Avec cette méthode, vous pouvez aller plusieurs groupes de profondeur et ont encore du code maintenable.

+1

"Quelque chose que j'ai trouvé si déroutant qui ne vaut pas la peine d'essayer" Quelle attitude étrange. – Tomalak

+0

vous avez raison ma grammaire est fausse - j'ai essayé - beaucoup, j'ai eu besoin de grouper les niveaux multiples (4 ou 5 si rappelez-vous correctement). J'ai réussi à le faire fonctionner mais les définitions clés étaient très confuses, surtout lorsque les groupements imbriqués deviennent profonds. Mais la méthode de deux passes que j'ai essayé de montrer ci-dessus est beaucoup plus facile à expliquer et à lire – Adrian

+0

Je recommande de lire ma réponse à: http: // stackoverflow.com/questions/948218/xslt-3-level-grouping-on-attributes - peut-être que cela vous aide :-) – Tomalak

6

Vous étiez près:

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

    <xsl:output method="text" /> 

    <xsl:key 
    name="statistic-by-frontendGroupId" 
    match="statisticItem" 
    use="@frontendGroupId" 
    /> 

    <xsl:template match="statisticItems"> 
    <xsl:for-each select=" 
     statisticItem[ 
     count(
      . | key('statistic-by-frontendGroupId', @frontendGroupId)[1] 
     ) = 1 
     ] 
    "> 
     <xsl:value-of select="@frontendGroupId"/> 
     <xsl:value-of select="' - '"/> 
     <!-- simple: the item count is the node count of the key --> 
     <xsl:value-of select=" 
     count(
      key('statistic-by-frontendGroupId', @frontendGroupId) 
     ) 
     "/> 
     <xsl:value-of select="'&#10;'"/> 
    </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

Il en résulte:

 
2336 - 2 
2337 - 3 

EDIT - Oh, je vois que vous voulez le compte distinct au sein du groupe. Ce serait:

<!-- the other key from the above solution is still defined --> 

<xsl:key 
    name="kStatisticItemByGroupAndCase" 
    match="statisticItem" 
    use="concat(@frontendGroupId, ',', @caseId)" 
/> 

<xsl:template match="statisticItems"> 
    <xsl:for-each select=" 
    statisticItem[ 
     count(
     . | key('kStatisticItemByGroup', @frontendGroupId)[1] 
    ) = 1 
    ] 
    "> 
    <xsl:value-of select="@frontendGroupId"/> 
    <xsl:value-of select="' - '"/> 
    <xsl:value-of select=" 
     count(
     key('kStatisticItemByGroup', @frontendGroupId)[ 
      count(
      . | key('kStatisticItemByGroupAndCase', concat(@frontendGroupId, ',', @caseId))[1] 
     ) = 1 
     ] 
    ) 
    "/> 
    <xsl:value-of select="'&#10;'"/> 
    </xsl:for-each> 
</xsl:template> 

Qui semble (certes) un peu effrayant. Il produit:

 
2336 - 1 
2337 - 2 

L'expression principale:

count(
    key('kStatisticItemByGroup', @frontendGroupId)[ 
    count(
     . | key('kStatisticItemByGroupAndCase', concat(@frontendGroupId, ',', @caseId))[1] 
    ) = 1 
    ] 
) 

se résume à:

Compter les nœuds de "key('kStatisticItemByGroup', @frontendGroupId)" qui remplissent les conditions suivantes: Ils sont les premiers dans leurs " kStatisticItemByGroupAndCase "groupe.

En y regardant de plus près, vous constaterez que ce n'est pas plus compliqué que ce que vous faites déjà. :-)


EDIT: Un dernier indice. Personnellement, je trouve cela beaucoup plus expressif que les expressions ci-dessus, car il met l'accent sur l'égalité des noeuds beaucoup plus que la « count(.|something) = 1 » approche:

count(
    key('kStatisticItemByGroup', @frontendGroupId)[ 
    generate-id() 
    = 
    generate-id(
     key('kStatisticItemByGroupAndCase', concat(@frontendGroupId, ',', @caseId))[1] 
    ) 
    ] 
) 

Le résultat est le même.