2010-08-25 7 views
4

J'ai quelques XML qui ressemble à ceci:Sélectionnez nœuds uniques basés sur une combinaison de deux valeurs d'attribut

<Root> 
    <Documents> 
     <Document id="1"/> 
    </Documents> 
    <People> 
     <Person id="1"/> 
     <Person id="2"/> 
    </People> 
    <Links> 
     <Link personId="1" documentId="1"/> 
     <Link personId="1" documentId="1"/> 
     <Link personId="2" documentId="1"/> 
    </Links> 
</Root> 

Je suis intéressé à obtenir que des éléments du « lien » qui ont une combinaison unique de ' PERSONID et de » de documentid, de sorte que ces deux liens:

<Root> 
    <Links> 
     <Link personId="1" documentId="1"/> 
     <Link personId="2" documentId="1"/> 
    </Links> 
</Root> 

Comment pourrais-je aller sur le faire? J'ai trouvé this question, bien que je pense que le mien est légèrement plus complexe et peut ne pas s'appliquer ... Je présume que je vais devoir utiliser la fonction key() quelque part ...

Merci d'avance.

Répondre

3

Cette feuille de style:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="kDocAndPeoById" match="Document|Person" use="@id"/> 
    <xsl:key name="kLinksByIds" match="Link" 
      use="concat(@personId,'++',@documentId)"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="Documents|People| 
    Link[count(.|key('kLinksByIds',concat(@personId,'++',@documentId))[1])!=1 
      or not(key('kDocAndPeoById',@personId)/self::Person) 
      or not(key('kDocAndPeoById',@documentId)/self::Document)]"/> 
</xsl:stylesheet> 

Sortie:

<Root> 
    <Links> 
     <Link personId="1" documentId="1"></Link> 
     <Link personId="2" documentId="1"></Link> 
    </Links> 
</Root> 

Si vous avez aucun intérêt à vérifier s'il y a un tel document ou personne @id, cette feuille de style:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="kLinksByIds" match="Link" 
       use="concat(@personId,'++',@documentId)"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="Documents|People| 
    Link[count(.|key('kLinksByIds',concat(@personId,'++',@documentId))[1])!=1]"/> 
</xsl:stylesheet> 

Sortie:

<Root> 
    <Links> 
     <Link personId="1" documentId="1"></Link> 
     <Link personId="2" documentId="1"></Link> 
    </Links> 
</Root> 
+1

Bon et élégant. (+1). Je suis venu presque avec la même chose. –

0

Vous devez filtrer les <Link> s avec quelque chose comme ça, où la fonction current() retourne <Link> s vous de vérifier l'unicité.

.[not(preceding-sibling::Link[@personId = current()/@personId and 
           @documentId = current()/@documentId])] 

L'axe preceding-sibling:: est utilisé pour trouver plus tôt <Link> éléments et la partie en contrôles carrés des supports pour faire correspondre des numéros d'identification. Le not() entourant l'expression entière signifie que toute l'expression entre crochets est vraie seulement si NON tel frère précédent correspond, c'est-à-dire qu'il n'y a pas de <Link> avec le même ID de personne et de document. Mes connaissances XSLT sont rouillées, alors je vous laisse cette partie. Ce que je pense est que vous trouvez d'abord tous les liens avec, disons, //Link, puis les filtrer dans une seconde étape avec le XPath ci-dessus. J'ai essayé dur, mais je ne pouvais pas penser à un moyen de tout faire en une seule étape, car cela dépend de la fonction current() pour fonctionner.

Questions connexes