2010-12-07 15 views
1

Je dois tirer dans un élément <amendment/> les éléments <sectionid/>, <amendmenttext/> et <sponsor/> si disponible.obtenir le dernier groupe de frères et soeurs précédents avec XSLT

Voici un exemple:

De:

<root> 
     <amendment> 
      <id>1</id> 
      <text>some text</text> 
     </amendment> 
     <sectionid>A</sectionid> 
     <sponsor>jon</sponsor> 
     <sponsor>peter</sponsor> 
     <amendment> 
      <id>8</id> 
      <text>some text</text> 
     </amendment> 
     <sectionid>B</sectionid> 
     <sponsor>matt</sponsor> 
     <sponsor>ben</sponsor> 
     <amendmenttext>some intro text</amendmenttext> 
     <amendment> 
      <id>5</id> 
      <text>some text</text> 
     </amendment> 
     <amendment> 
      <id>4</id> 
      <text>some text</text> 
     </amendment> 
     <sponsor>max</sponsor> 
     <amendment> 
      <id>6</id> 
      <text>some text</text> 
     </amendment> 
     <amendment> 
      <id>7</id> 
      <text>some text</text> 
     </amendment> 

</root> 

à:

<root> 
     <amendment>     
      <id>1</id> 
      <text>some text</text> 
     </amendment>   
     <amendment> 
      <sectionid>A</sectionid> 
      <sponsor>jon</sponsor> 
      <sponsor>peter</sponsor> 
      <id>8</id> 
      <text>some text</text> 
     </amendment> 
     <amendment> 
      <sectionid>B</sectionid> 
      <sponsor>matt</sponsor> 
      <sponsor>ben</sponsor> 
      <amendmenttext>some intro</amendmenttext> 
      <id>5</id> 
      <text>some text</text> 
     </amendment> 
     <amendment> 
      <sectionid>B</sectionid> 
      <sponsor>matt</sponsor> 
      <sponsor>ben</sponsor> 
      <id>4</id> 
      <text>some text</text> 
     </amendment> 
     <amendment> 
      <sectionid>B</sectionid> 
      <sponsor>max</sponsor> 
      <id>6</id> 
      <text>some text</text> 
     </amendment> 
     <amendment> 
      <sectionid>B</sectionid> 
      <sponsor>max</sponsor> 
      <id>7</id> 
      <text>some text</text> 
     </amendment> 

</root> 

Note 1: l'élément <sectionid/> applique à tous les <amendments/> avant la prochaine <sectionid/>

Note 2: le <sponsor/> élément s'applique à tous les <amendments/> avant la liste suivante <sponsor/>.

Note 3: Les valeurs de //amendment/id ne sont pas séquentielles.

Remarque 4: Un <amendment/> ne peut pas avoir un <sponsor/> ou <sectionid/> comme un frère précédent.

Note 5: <amendmenttext> applique uniquement sur les points suivants <amendment/>

Comment cette transformation peut être fait avec XSLT 1.0.

+0

Modifications de la question précédente http://stackoverflow.com/questions/4096481/refactor-xml-with-xsl est une mineure. Je ne pense pas qu'il mérite une nouvelle question. –

+0

Oki. Ne sachant pas que la solution serait similaire. Je pensais que ce n'était pas juste pour les premiers intervenants de changer le contexte de la question après qu'ils aient répondu. Mais point pris. –

Répondre

2

Cette feuille de style (la même réponse que précédemment mais juste une règle):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="node()|@*"> 
     <xsl:param name="pSectionId" select="/.."/> 
     <xsl:param name="pSponsors" select="/.."/> 
     <xsl:variable name="vSectionid" select="self::sectionid"/> 
     <xsl:variable name="vSponsor" select="self::sponsor"/> 
     <xsl:variable name="vAmendment" select="self::amendment"/> 
     <xsl:if test="not($vSectionid|$vSponsor)"> 
      <xsl:copy> 
       <xsl:apply-templates select="@*"/> 
       <xsl:copy-of select="$pSectionId[$vAmendment]"/> 
       <xsl:copy-of select="$pSponsors[$vAmendment]"/> 
       <xsl:apply-templates select="node()[1]"/> 
      </xsl:copy> 
     </xsl:if> 
     <xsl:apply-templates select="following-sibling::node()[1]"> 
      <xsl:with-param name="pSectionId" 
          select="$pSectionId[not($vSectionid)]|$vSectionid"/> 
      <xsl:with-param name="pSponsors" 
          select="$pSponsors[not($vSponsor) or 
               current() 
                /preceding-sibling::node()[1] 
                /self::sponsor] | 
            $vSponsor"/> 
     </xsl:apply-templates> 
    </xsl:template> 
</xsl:stylesheet> 

Sortie:

<root> 
    <amendment> 
     <id>1</id> 
     <text>some text</text> 
    </amendment> 
    <amendment> 
     <sectionid>A</sectionid> 
     <sponsor>jon</sponsor> 
     <sponsor>peter</sponsor> 
     <id>8</id> 
     <text>some text</text> 
    </amendment> 
    <amendment> 
     <sectionid>B</sectionid> 
     <sponsor>matt</sponsor> 
     <sponsor>ben</sponsor> 
     <id>5</id> 
     <text>some text</text> 
    </amendment> 
    <amendment> 
     <sectionid>B</sectionid> 
     <sponsor>matt</sponsor> 
     <sponsor>ben</sponsor> 
     <id>4</id> 
     <text>some text</text> 
    </amendment> 
    <amendment> 
     <sectionid>B</sectionid> 
     <sponsor>max</sponsor> 
     <id>6</id> 
     <text>some text</text> 
    </amendment> 
    <amendment> 
     <sectionid>B</sectionid> 
     <sponsor>max</sponsor> 
     <id>7</id> 
     <text>some text</text> 
    </amendment> 
</root> 

Remarque: La diference de réponse précédente est l'expression de valeur par défaut du noeud vide pour les paramètres de ces règles qui sont nécessaires.

+0

@Alejandro, je viens d'ajouter à l'exemple XML. –

+0

@Benjamin Ortuzar: À ce stade, vous devez savoir comment modifier cette réponse ou une réponse précédente en conséquence. Permet de voir les modifications dans cette feuille de style: ajouter le paramètre 'pAmendmentText' avec un ensemble de nœuds vide'/.. 'comme valeur de défaut, ajouter la variable' vAmendmentText' comme 'self :: amendmenttest', ajouter cette variable à la' xsl: if/@ test' pour ignorer la copie, ajouter une instruction 'xsl: copy-of' avec' pAmendmentText [$ vAmendment] ', passer un paramètre' pAmendmentText' avec 'pAmendmentText [$ (non $ vAmendment)] | $ vAmendmentText' –