2010-11-15 8 views
1

J'essaye de trier un document XML en utilisant XSLT, et je veux garder les commentaires. Jusqu'ici tout va bien, car il y a déjà quelques réponses à cette question (voir connexe ..). Mais! aucune de ces réponses (excellent) se rapportent à un fichier XML qui ressemble à ceci:Trier XML en utilisant XSLT, tout en gardant plusieurs commentaires

<xml> 
    <beatles> 
     <!-- comment(1): john is actually my favourite --> 
     <!-- comment(2): John died tragically in 1980 --> 
     <beatle name="John"/> 

     <beatle name="Ringo"/> 

     <beatle name="George"/> 

     <!-- comment(1): Paul still does live concerts to this day --> 
     <!-- comment(2): contrary to common folklore, Paul is NOT dead! --> 
     <beatle name="Paul"/> 
    </beatles> 
</xml> 

Qu'est-ce qui se passe maintenant? Je veux trier les Beatles (Que Dieu bénisse les) par nom, et aussi garder tous les commentaires de chaque Beatle en place, afin d'obtenir ce résultat:

<xml> 
    <beatles> 
     <beatle name="George"/> 

     <!-- comment(1): john is actually my favourite --> 
     <!-- comment(2): John died tragically in 1980 --> 
     <beatle name="John"/> 

     <!-- comment(1): Paul still does live concerts to this day --> 
     <!-- comment(2): contrary to common folklore, Paul is NOT dead! --> 
     <beatle name="Paul"/> 

     <beatle name="Ringo"/> 
    </beatles> 
</xml> 

Bonne vieille preceding-sibling :: commentaire () [1] ne fonctionnera pas ici. Dans le code normal, je ferais simplement une boucle inverse sur tous les commentaires précédents, et je m'arrêterais quand j'atteindrais un nœud sans commentaire; mais comme nous le savons tous, de XSLT pour chaque ne peut pas être échappé.

Des pensées?

TIA!

DF.

+0

Bonne question, +1. Je pense que @ Tim-C ​​vous a donné la réponse parfaite. –

Répondre

0

Lors de la copie du nœud beatle correspondant, vous devez également appliquer ses commentaires. C'est tout ce que vous devez faire.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="beatles"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*"/> 
      <xsl:apply-templates select="beatle"> 
       <xsl:sort select="@name" data-type="text"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="beatle"> 
     <xsl:variable name="current" select="."/> 
     <xsl:apply-templates 
       select="preceding-sibling::comment()[generate-id(following-sibling::beatle[1]) = generate-id($current)]"/> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 


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

Sortie:

<?xml version="1.0" encoding="windows-1251"?> 
<xml> 
    <beatles> 
     <beatle name="George"/> 
     <!-- comment(1): john is actually my favourite --> 
     <!-- comment(2): John died tragically in 1980 --> 
     <beatle name="John"/> 
     <!-- comment(1): Paul still does live concerts to this day --> 
     <!-- comment(2): contrary to common folklore, Paul is NOT dead! --> 
     <beatle name="Paul"/> 
     <beatle name="Ringo"/> 
    </beatles> 
</xml> 
+0

C'est l'approche que je prendrais, même si elle commencera à mal tourner s'il y a 11 000 Beatles. –

+0

Bonne forme, tout le monde! J'ai fini par utiliser la solution de @Alex Nikolaenkov, car mon problème était un peu plus compliqué que de commander les mêmes nœuds - j'ai plusieurs nœuds différents, avec des groupes de nœuds à commander, donc la solution fournie par Alex correspondait mieux. @ Tim-C ​​- merci pour votre réponse, car j'ai appris un peu plus sur XSLT (que j'ai commencé à apprendre hier). Merci encore tout !! – deebugger

+0

@Robert Rossney - probablement, mais mon problème n'implique pas autant de nœuds, donc je m'en sers joyeusement .. – deebugger

1

Je pense que cela peut être réalisé au moyen d'une clé qui énumère tous les commentaires pour un élément « » beatle donné. Donc, pour chaque commentaire, il est indexé par le premier élément beatle successif.

Vous pouvez ensuite utiliser ceci comme suit pour lister tous les commentaires pour n'importe quel élément de beatle.

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

    <xsl:key name="comments" match="comment()" use="following-sibling::beatle[1]/@name" /> 

    <xsl:template match="/xml/beatles"> 
     <beatles> 
     <xsl:for-each select="beatle"> 
      <xsl:sort select="@name" /> 

      <!-- Loop through all comments for the beatle element --> 
      <xsl:for-each select="key('comments', @name)"> 
       <xsl:comment> 
        <xsl:value-of select="." /> 
       </xsl:comment> 
      </xsl:for-each> 

      <!-- Copy the beatle element --> 
      <xsl:copy> 
       <xsl:copy-of select="@*" /> 
      </xsl:copy> 
     </xsl:for-each> 
     </beatles> 
    </xsl:template> 

</xsl:stylesheet> 
+0

IMO utilisant des touches pour une tâche aussi simple est une exagération. BTW lors de l'utilisation de XSLT style impératif, vous obtenez un couplage plus serré et les modifications de ce code deviennent de plus en plus difficile avec le temps. –

+0

+1 pour une réponse parfaite! –

+0

@ Alex-Nikolaenkov: Les clés sont le bon instrument pour la bonne situation - et * cette * situation est la bonne pour l'utilisation des clés. –

Questions connexes