2010-09-22 5 views
9

J'ai XMLvariable d'incrément XSLT

<data> 
<records> 
    <record name="A record"> 
    <info>A1</info> 
    <info>A2</info> 
    </record> 
    <record name="B record"/> 
    <record name="C record"> 
    <info>C1</info> 
    </record> 
    </records> 
</data> 

comment puis-je transformer en sortie suivante, le problème est de savoir comment puis-je compter entre le dossier et enregistrement/informations suivantes?

<div id="1"> 
    <p>A record</p> 
    <span id="1">A1</span> 
    <span id="2">A2</span> 
</div> 
<div id="2"> 
    <p>C record</p> 
    <span id="3">C1</span> 
</div> 
+0

Bonne question (+1). Voir ma réponse pour une solution courte qui utilise XSLT au maximum. :) –

+0

Oh, et @Alejandro dit que c'était le seul correct! –

Répondre

7

Solution 1. Traversal à grain fin. Cette feuille de style:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="records"> 
     <xsl:apply-templates select="*[1]"/> 
    </xsl:template> 
    <xsl:template match="record"/> 
    <xsl:template match="record[node()]"> 
     <xsl:param name="pRecordNum" select="1"/> 
     <xsl:param name="pInfoNum" select="1"/> 
     <div id="{$pRecordNum}"> 
      <xsl:apply-templates select="@*|*[1]"> 
       <xsl:with-param name="pInfoNum" select="$pInfoNum"/> 
      </xsl:apply-templates> 
     </div> 
     <xsl:apply-templates select="following-sibling::record[node()][1]"> 
      <xsl:with-param name="pRecordNum" select="$pRecordNum +1"/> 
      <xsl:with-param name="pInfoNum" select="$pInfoNum + count(info)"/> 
     </xsl:apply-templates> 
    </xsl:template> 
    <xsl:template match="info"> 
     <xsl:param name="pInfoNum"/> 
     <span id="{$pInfoNum}"> 
      <xsl:value-of select="."/> 
     </span> 
     <xsl:apply-templates select="following-sibling::info[1]"> 
      <xsl:with-param name="pInfoNum" select="$pInfoNum +1"/> 
     </xsl:apply-templates> 
    </xsl:template> 
    <xsl:template match="@name"> 
     <p> 
      <xsl:value-of select="."/> 
     </p> 
    </xsl:template> 
</xsl:stylesheet> 

Sortie:

<div id="1"> 
    <p>A record</p> 
    <span id="1">A1</span> 
    <span id="2">A2</span> 
</div> 
<div id="2"> 
    <p>C record</p> 
    <span id="3">C1</span> 
</div> 

Solution 2: hache preceding. Cette feuille de style:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="record"/> 
    <xsl:template match="record[node()]"> 
     <div id="{count(preceding-sibling::record[node()])+1}"> 
      <xsl:apply-templates select="@*|*"/> 
     </div> 
    </xsl:template> 
    <xsl:template match="info"> 
     <span id="{count(preceding::info)+1}"> 
      <xsl:value-of select="."/> 
     </span> 
    </xsl:template> 
    <xsl:template match="@name"> 
     <p> 
      <xsl:value-of select="."/> 
     </p> 
    </xsl:template> 
</xsl:stylesheet> 

Solution 3: Avec la hache fn:position() et preceding. Cette feuille de style:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="records"> 
     <xsl:apply-templates select="record[node()]"/> 
    </xsl:template> 
    <xsl:template match="record"> 
     <div id="{position()}"> 
      <xsl:apply-templates select="@*"/> 
      <xsl:apply-templates/> 
     </div> 
    </xsl:template> 
    <xsl:template match="info"> 
     <span id="{count(preceding::info)+1}"> 
      <xsl:value-of select="."/> 
     </span> 
    </xsl:template> 
    <xsl:template match="@name"> 
     <p> 
      <xsl:value-of select="."/> 
     </p> 
    </xsl:template> 
</xsl:stylesheet> 

Remarque: Vous avez besoin d'un style de traction explict.

Édition: Numérotation de niveau manquée pour span/@ id.

+0

@Alejandro: Bon effort. Vous pouvez être intéressé de voir encore une autre solution :) –

+0

@Alejandro: Félicitations pour avoir dépassé la barre des 4000! –

+0

@Dimitre: Merci! –

4

Il existe un moyen court de le faire dans XSLT. Utilisez l'instruction <xsl:number>:

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

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

<xsl:template match="record[info]"> 
    <xsl:variable name="vPos"> 
    <xsl:number count="record[info]"/> 
    </xsl:variable> 

    <div id="{$vPos}"> 
    <xsl:apply-templates/> 
    </div> 
</xsl:template> 

<xsl:template match="info"> 
    <xsl:variable name="vPos"> 
    <xsl:number from="/" level="any" count="info" /> 
    </xsl:variable> 
    <span id="{$vPos}"><xsl:apply-templates/></span> 
</xsl:template> 
<xsl:template match="record[not(info)]"/> 
</xsl:stylesheet> 

Lorsque cette transformation est appliquée sur le document XML fourni:

<data> 
<records> 
    <record name="A record"> 
    <info>A1</info> 
    <info>A2</info> 
    </record> 
    <record name="B record"/> 
    <record name="C record"> 
    <info>C1</info> 
    </record> 
    </records> 
</data> 

le désiré, résultat correct est produit:

<data> 
    <records> 
     <div id="1"> 
      <span id="1">A1</span> 
      <span id="2">A2</span> 
     </div> 
     <div id="2"> 
      <span id="3">C1</span> 
     </div> 
    </records> 
</data> 
+2

+1 Pour la seule solution correcte (j'ai manqué que span/@ id devrait être de n'importe quel niveau, je vais éditer) et pour 'xsl: number', l'instruction faite pour cette tâche dans XSLT. –