2010-09-22 8 views
9

Ich habe die folgende XML-XSLT Schritt Variable

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

wie kann ich in folgende Ausgabe verwandeln, ist das Problem, wie kann ich zwischen den Akten zählen und Aufzeichnung/Informationen?

<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

Gut Frage (+1). Siehe meine Antwort für eine kurze Lösung, die XSLT am meisten nutzt. :) –

+0

Oh, und @ Alejandro sagt, es war der einzig richtige! –

Antwort

7

Lösung 1. Feinkörnige Traversierung. Dieses Stylesheet:

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

Ausgang:

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

Lösung 2: preceding Axt. Dieses Stylesheet:

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

Lösung 3: Mit fn:position() und preceding Axt. Dieses Stylesheet:

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

Hinweis: Sie benötigen einen explict Pull-Stil.

Bearbeiten: Verpasste keine Level-Nummerierung für span/@ ID.

+0

@ Alejandro: Gute Leistung. Es könnte Sie interessieren, eine andere Lösung zu sehen :) –

+0

@Alejandro: Herzlichen Glückwunsch zum Überschreiten der Marke von 4000! –

+0

@Dimitre: Danke! –

4

Es gibt einen kurzen Weg, dies in XSLT zu tun. Verwenden Sie die <xsl:number> Anweisung:

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

Wenn diese Transformation auf der mitgelieferten XML-Dokument angelegt wird:

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

das gewünschte, wird richtige Ergebnis erzeugt:

<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 Für die einzig richtige Lösung (ich habe verpasst, dass span/@ id von jeder Ebene sein sollte. Ich werde bearbeiten) und für "xsl: number", die Anweisung für diese Aufgabe in XSLT. –