2010-09-22 15 views
9

Tengo el siguiente XMLXSLT variable de incremento

<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> 

cómo puedo transformar en siguiente salida, el problema es cómo puedo contar entre en el registro, y el registro/información?

<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

Buena pregunta (+1) Vea mi respuesta para una solución corta que usa XSLT al máximo. :) –

+0

¡Ah, y @Alejandro dice que fue la única correcta! –

Respuesta

7

Solución 1. Travesía de grano fino. Esta hoja de estilo:

<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> 

Salida:

<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> 

Solución 2: preceding hacha. Esta hoja de estilo:

<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> 

Solución 3: Con fn:position() y preceding hacha. Esta hoja de estilo:

<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> 

Nota: Es necesario un estilo tirón explict.

Editar: Ha omitido cualquier numeración de nivel para span/@ id.

+0

@Alejandro: Buen esfuerzo. Quizás le interese ver otra solución :) –

+0

@Alejandro: ¡Felicitaciones por haber superado la marca 4000! –

+0

@Dimitre: ¡Gracias! –

4

Hay una forma corta de hacer esto en XSLT. Usar la <xsl:number> instrucción:

<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> 

Cuando se aplica esta transformación en el documento previsto XML:

<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> 

el resultado deseado, correcta se produce:

<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 Para la única solución correcta (me he perdido que span/@ id debe ser de cualquier nivel. Editaré) y para 'xsl: number', las instrucciones hechas para esta tarea en XSLT. –