2010-08-24 7 views
6

Je voudrais obtenir des noeuds distincts de mon xml sur plusieurs niveaux. Quelqu'un peut-il s'il vous plaît me donner quelques conseils sur la façon de faire cela? Les méthodes que j'ai googlé (méthode de Muenchian, pour chaque groupe) ont été expliquées avec des clés de groupement simples et une hiérarchie simple.Nœuds distincts sur plusieurs clés avec XSLT

Voici un exemple de mon xml:

<persons> 
<person> 
    <name>Tom</name> 
    <age>20</age> 
    <mails> 
    <mail>[email protected]</mail> 
    <mail>[email protected]</mail> 
    </mails> 
</person> 
<person> 
    <name>Tom</name> 
    <age>20</age> 
    <mails> 
    <mail>[email protected]</mail> 
    <mail>[email protected]</mail> 
    </mails> 
</person> 
</persons> 

Je voudrais avoir des nœuds personnes distinctes en fonction du nom et de l'âge, et aussi un ensemble distinct de messagerie nœuds. Ainsi, pour l'exemple, la sortie désirée serait:

<persons> 
<person> 
    <name>Tom</name> 
    <age>20</age> 
    <mails> 
    <mail>[email protected]</mail> 
    <mail>[email protected]</mail> 
    <mail>[email protected]</mail> 
    </mails> 
</person> 
</persons> 

Y a-t-il un moyen de le faire? Merci beaucoup d'avance.

+0

Peut-on utiliser XSLT2 ou êtes-vous coincé avec XSLT1? –

+0

@Jim: Comme il mentionne 'for-each-group', je suppose que nous pouvons utiliser XSLT 2.0 en toute sécurité. –

+0

XSLT 2 est bien. – Mork0075

Répondre

11

I. solution XSLT 1.0:

Cette transformation:

<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="kPersByNameAndAge" match="person" 
    use="concat(name, '+', age)"/> 

<xsl:key name="kmailByNameAndAge" match="mail" 
    use="concat(../../name, '+', ../../age)"/> 

<xsl:key name="kmailByNameAndAgeAndVal" match="mail" 
    use="concat(../../name, '+', ../../age, '+', .)"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/*"> 
    <persons> 
    <xsl:apply-templates select= 
    "person[generate-id() 
      = 
      generate-id(key('kPersByNameAndAge', 
          concat(name, '+', age) 
         ) 
          [1] 
        ) 
      ] 
    "/> 
    </persons> 
</xsl:template> 

<xsl:template match="mails"> 
    <mails> 
    <xsl:apply-templates select= 
    "key('kmailByNameAndAge', concat(../name, '+', ../age)) 
     [generate-id() 
     = 
     generate-id(key('kmailByNameAndAgeAndVal', 
         concat(../../name, '+', ../../age, '+', .) 
         ) 
          [1] 
        ) 
     ] 
    "/> 
    </mails> 
</xsl:template> 
</xsl:stylesheet> 

lorsqu'il est appliqué sur le document XML fourni:

<persons> 
<person> 
    <name>Tom</name> 
    <age>20</age> 
    <mails> 
    <mail>[email protected]</mail> 
    <mail>[email protected]</mail> 
    </mails> 
</person> 
<person> 
    <name>Tom</name> 
    <age>20</age> 
    <mails> 
    <mail>[email protected]</mail> 
    <mail>[email protected]</mail> 
    </mails> 
</person> 
</persons> 

produit le désiré, correct res ULT:

<persons> 
    <person> 
     <name>Tom</name> 
     <age>20</age> 
     <mails> 
      <mail>[email protected]</mail> 
      <mail>[email protected]</mail> 
      <mail>[email protected]</mail> 
     </mails> 
    </person> 
</persons> 

II. XSLT 2.0 solution

<xsl:stylesheet version="2.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="kmailByNameAndAge" match="mail" 
    use="concat(../../name, '+', ../../age)"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/*"> 
    <persons> 
    <xsl:for-each-group select="person" group-by="concat(name, '+', age)"> 
    <xsl:apply-templates select="."/> 
    </xsl:for-each-group> 
    </persons> 
</xsl:template> 

<xsl:template match="mails"> 
    <mails> 
    <xsl:for-each-group select= 
    "key('kmailByNameAndAge', concat(../name, '+', ../age))" 
    group-by="concat(../../name, '+', ../../age, '+', .)" 
    > 
    <xsl:apply-templates select="."/> 
    </xsl:for-each-group> 
    </mails> 
</xsl:template> 
</xsl:stylesheet> 
+0

+ 1 solution de Beatifull. À propos du modèle 'mails': Je pense que' for-each-group/group' pourrait être simplement '". "'. J'ai travaillé dans une solution XSLT 2.0 mais c'était un modèle "brique" ... –

+0

Merci beaucoup, c'est tout. – Mork0075

Questions connexes