2009-08-21 19 views
1

Ich habe eine XML wie folgt aus:Conditional Autoinkrement in xsl

<V> 
    <W> 
    <X>1</X> 
    </W> 
    <W> 
    <Y>1</Y> 
    </W> 
    <W> 
    <X>1555</X> 
    </W> 
    <W> 
    <X>1</X> 
    </W> 
</V> 

Ich möchte es so etwas wie machen:

<entity ID="start"> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0002</f> 
    <f ID="NewField">0003</f> 
</entity> 

Wenn das Feld V/W/X dann NewField sollte um 1 erhöht werden, so oft das Tag V/W/X gefunden wird. Ähnlich für V/W/Y.

Die XSL, die ich verwende ist

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:template match="/"> 
<entity ID="start"> 
    <xsl:for-each select="V/W"> 
     <xsl:if test="X"> 
      <xsl:variable name="my_var"> 
       <xsl:value-of select="concat('000',position())"/> 
      </xsl:variable> 
      <f ID="NewField"><xsl:value-of select="$my_var"/></f> 
     </xsl:if> 
     <xsl:if test="Y"> 
      <xsl:variable name="my_var"> 
       <xsl:value-of select="concat('000',position())"/> 
      </xsl:variable> 
      <f ID="NewField"><xsl:value-of select="$my_var"/></f> 
     </xsl:if> 
    </xsl:for-each> 
</entity> 
</xsl:template> 
</xsl:stylesheet> 

aber es gibt mir ein falsches Ergebnis, so etwas wie dieses:

<entity ID="start"> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0002</f> 
    <f ID="NewField">0003</f> 
    <f ID="NewField">0004</f> 
</entity> 

Antwort

0

Ich glaube, du bist für so etwas wie count(preceding::X) Ausdruck. Natürlich möchten Sie es vielleicht komplexer machen und dann auf die Zahlenformatierung achten, aber das klingt nach einem Ausgangspunkt, nach dem Sie suchen.

0
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:template match="V"> 
    <entity ID="start"> 
     <xsl:apply-templates select="W/X|W/Y" /> 
    </entity> 
    </xsl:template> 

    <xsl:template match="X|Y"> 
    <f ID="NewField"> 
     <xsl:variable name="counter" select=" 
     count(
      parent::W/preceding-sibling::W/*[name() = name(current())] 
     ) + 1 
     " /> 
     <xsl:value-of select="format-number($counter, '0000')" /> 
    </f> 
    </xsl:template> 

</xsl:stylesheet> 

Dieser:

parent::W/preceding-sibling::W/*[name() = name(current())]

wählt alle vorstehenden Elemente mit dem gleichen Namen wie das aktuelle Element. Zum Beispiel, wenn der Punkt der Ausführung auf diesem Knoten ist:

<X>1555</X> 

Es geht eine Ebene nach oben (parent::W), wählt dann alle vorhergehenden <W> Geschwister und diejenigen wählt er ein Kind (*), die einen Namen hat von X - seit X ist der Name des Elements current().

Der resultierende Knotensatz wird gezählt und um eins erhöht. format-number() verwendet, um eine schöne, saubere Ausgabe zu erzeugen:

<entity ID="start"> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0002</f> 
    <f ID="NewField">0003</f> 
</entity> 
+0

Aus Neugier, ist es ein besonderer Grund, warum Sie die Verwendung ' parent :: 'achse explizit (die definitionsgemäß immer nur höchstens einen Knoten hat) anstatt' ..' - es scheint, dass es in beiden Richtungen ziemlich eindeutig ist. –

+0

Sie haben Recht, ".." ist das gleiche, und ich weiß das. Ich mache es, weil es für mich expressiver ist. Beim Lesen des XPath ist die erwartete Dokumentenstruktur sofort klar, während ".." einen Rest der Mehrdeutigkeit hinterlässt. – Tomalak

1

Wenn Sie mit XSLT Anzahl Knotet dann kann the xsl:number element helfen:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="/"> 
    <entity ID="start"> 
     <xsl:apply-templates select="descendant::X | descendant::Y"/> 
    </entity> 
    </xsl:template> 

    <xsl:template match="X | Y"> 
    <f ID="NewField"><xsl:number level="any" format="0000"/></f> 
    </xsl:template> 

</xsl:stylesheet>