2009-10-12 10 views
2

je XML quelque chose comme ceci:XSLT: supprimer tous, mais la première occurrence d'un noeud donné

<MyXml> 
    <RandomNode1> 
    <TheNode> 
     <a/> 
     <b/> 
     <c/> 
    </TheNode> 
    </RandomeNode1> 
    <RandomNode2> 
    </RandomNode2> 
    <RandomNode3> 
    <RandomNode4> 
     <TheNode> 
     <a/> 
     <b/> 
     <c/> 
     </TheNode>  
    </RandomNode4> 
    </RandomNode3> 
</MyXml> 

<TheNode> apparaît dans le XML, mais pas au même niveau, souvent profond dans d'autres nœuds. Ce que je dois faire est d'éliminer toutes les occurrences de <TheNode> SAUF le premier. Le reste est redondant et prend de la place. Quel serait le XSL qui pourrait faire cela?

J'ai quelque chose comme ceci:

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

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

    <xsl:template match="//TheNode[position()!=1]"> 
    </xsl:template> 

</xsl:stylesheet> 

Mais ce n'est pas correct. Aucune suggestion?

Répondre

4
<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="node() | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node() | @*"/> 
    </xsl:copy> 
    </xsl:template> 
    <xsl:template match="TheNode[preceding::TheNode]"/> 
</xsl:stylesheet> 
+0

Il n'y a pas besoin d'un départ ' // 'opérateur dans les modèles. –

2

//TheNode[position()!=1] ne fonctionne pas car ici, est position() par rapport au contexte parent de chaque <TheNode>. Il sélectionne tous les <TheNode> qui ne sont pas les premiers dans leur parent respectif.

Mais vous étiez sur la bonne voie. Qu'est-ce que vous vouliez dire était:

 
(//TheNode)[position()!=1] 

Notez les parenthèses - ils provoquent le prédicat à appliquer à l'ensemble du nœud ensemble sélectionné, au lieu de chaque nœud individuellement.

Malheureusement, même s'il s'agit d'une expression XPath valide, elle n'est pas valide en tant que modèle de correspondance. Un modèle de correspondance doit être significatif (applicable) à un nœud individuel, il ne peut pas être une expression sélectionnée.

Alors @ solution de Alohci,

 
//TheNode[preceding::TheNode] 

est la bonne façon d'exprimer ce que vous voulez.

0

Autre approche pour le modèle serait:

<xsl:template match="TheNode[generate-id() 
          != generate-id(/descendant::TheNode[1)]"/> 

Remarque: Il est plus probable qu'une expression absolue s'optimizated inteads d'une expression relative comme preceding::TheNode

Questions connexes