5 Stimmen

Wie kann man die Aufrufe einer Vorlage in XSLT zählen?

Ich habe ein XSLT-Skript, mit dem ich bei jedem Aufruf einer Vorlage eine fortlaufende Nummerierung vornehmen möchte. Also eine sehr verkürzte Version davon sieht ein bisschen wie:

<xsl:call-template name="insertHeader" />
<xsl:for-each ...>  
    <xsl:call-template name="insertHeader" />
    ...
</xsl:for-each>
<xsl:call-template name="insertHeader" />

<xsl:template name="insertHeader>
    This is item number <xsl:value-of select="$numberOfInvocations />
</xsl:template>

So offensichtlich, dass $numberOfInvocations Sache nicht funktioniert, und in XSLT können Sie nicht eine globale Zähler-Variable, die wie ein offensichtlicher Ansatz in einer prozeduralen Sprache scheinen würde inkrementieren. Ich möchte, dass beim ersten Aufruf der Vorlage die Zahl 1 ausgegeben wird, beim zweiten Aufruf die Zahl 2, usw. Wie soll ich das anstellen? Ist dies in XSLT auch nur annähernd möglich?

Danke :)

Edit: Es gab also einige Kommentare, dass dies nicht klar genug definiert ist. Ich möchte eine Reihe von Tabellen in der (HTML-)Ausgabe beschriften. Die naheliegendste Möglichkeit, dies zu tun, ist der Aufruf einer Funktion (Sie können wahrscheinlich erkennen, dass ich hier kein XSLT-Assistent bin), die die Zahl jedes Mal automatisch hochzählt. Ich denke, der Grund, warum dies so schwierig erscheint, liegt darin, dass es die XSLT selbst ist, die definiert, wo diese Tabellen erscheinen, und nicht die Eingabe.

Diese zusätzlichen Informationen sind vielleicht nicht so nützlich, da Dimitres Antwort eher so klingt, als würde das nie funktionieren. Trotzdem danke :)

1 Stimmen

Wie Sie geschrieben haben, bedeutet Variable im deklarativen Paradigma nicht dasselbe. Sie müssen (und können es meistens auch) die Logik hinter dieser Zahl erklären. Wenn Sie gesperrt sind, geben Sie bitte ein Eingabebeispiel und die gewünschte Ausgabe an, damit wir Ihnen helfen können.

0 Stimmen

Gute Frage (+1). In meiner Antwort finden Sie eine ausführliche Erklärung.

6voto

Dimitre Novatchev Punkte 234995

In einer funktionalen Sprache wie XSLT gibt es keine definierte "Reihenfolge der Berechnung". .

Daher ist der Versuch, die "Berechnungen" nach ihrer "zeitlichen" Abfolge zu nummerieren, nicht sinnvoll und führt oft zu überraschenden Ergebnissen.

Zum Beispiel schränkt nichts ein <xsl:apply-templates> um Schablonen in der gleichen zeitlichen Reihenfolge anzuwenden wie die Dokumentreihenfolge der Knoten in der ausgewählten Knotenliste. Dies könnte parallel geschehen, was bedeutet in beliebiger Reihenfolge .

Viele XSLT-Prozessoren führen lazy evaluation was bedeutet, dass eine bestimmte XSLT-Anweisung nur dann ausgewertet wird, wenn sie wirklich benötigt wird, und nicht entsprechend ihrer textlichen Reihenfolge im XSLT-Stylesheet. Oft werden einige Anweisungen überhaupt nicht ausgeführt.

Manchmal wird der Optimierer eine bestimmte XSLT-Anweisung ausführen zweimal weil es beschlossen hat, das erste Ergebnis zu verwerfen, um die Platzausnutzung zu optimieren.

Die gewünschte Nummerierung kann hergestellt werden mit Rekursion (allgemein) und Weitergabe-Stil CPS oder Monaden (genauer gesagt).

Die FXSL-Bibliothek (sowohl Version 1 -- für XSLT 1.0 als auch Version 2 -- für XSLT 2.0) enthält Vorlagen, die zur Organisation einer solchen Nummerierung verwendet werden können: foldl, foldr, iter, iterUntil, scanl, scanr, ..., etc.

Wenn das Problem genau definiert ist (was derzeit nicht der Fall ist), kann eine solche Nummerierung vorgenommen werden, aber seien Sie gewarnt, was die Ergebnisse betrifft .

4voto

Dagg Nabbit Punkte 72150

Haben Sie die position() Funktion?

Hier ist ein Ausschnitt aus einem meiner Projekte, vielleicht ist es hilfreich:

<xsl:variable name="count" select="count(../ownedParameter[@name])" />
$<xsl:value-of select="@name" />=null
<xsl:if test="$count > 1 and position()!=last()">,</xsl:if>

Sie sollten in der Lage sein, etwas zu tun wie:

<xsl:template name="insertHeader>
    This is item number <xsl:value-of select="position()" />
</xsl:template>

...zumindest denke ich, dass das funktionieren wird. Wenn nicht, müssen Sie den Aufruf an count() innerhalb einer for-each Block.

2voto

Per T Punkte 1948

In XSLT 1.0 konnten Sie dies durch Verwendung einer rekursiven Vorlage erreichen.

Pero und das ist ein großes Aber, der Name der Vorlage, insertHeader lässt mich vermuten, dass Sie versuchen, etwas zu tun, das in XSLT auf eine ganz andere Weise gelöst werden sollte.

Welche Absichten verfolgen Sie damit? Vielleicht können wir mit einer mehr XSLTish Lösung für Sie kommen. Ich glaube, Sie könnten Ihr Problem (wenn es das ist, von dem ich denke, dass es das ist...) lösen, indem Sie xsl:number und durch die Verwendung eines geeigneten Musters in der @count Attribut.

XSLT 1.0:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="/">
    <xsl:call-template name="insertHeader"/>
  </xsl:template>

  <xsl:template name="insertHeader">
    <xsl:param name="num" select="1"/>
    <xsl:value-of select="concat('This is item number ', $num, '&#x0a;')"/>
    <xsl:if test="$num &lt; 10">
      <xsl:call-template name="insertHeader">
        <xsl:with-param name="num" select="$num + 1"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

Das wird ausgegeben:

This is item number 1
This is item number 2
This is item number 3
This is item number 4
This is item number 5
This is item number 6
This is item number 7
This is item number 8
This is item number 9
This is item number 10

2voto

dolmen Punkte 7171

En numberOfInvocations muss außerhalb der Vorlage berechnet und als Parameter angegeben werden. Innerhalb einer for-each können Sie die Iterationsnummer abrufen, indem Sie position() .

In dem folgenden Stylesheet habe ich eine pos Parameter zu insertHeader .

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:s="uri:sample">
  <xsl:output type="text"/>

  <s:sample>
    <table>Table A</table>
    <table>Table B</table>
  </s:sample>

  <xsl:template match="/">
    <xsl:apply-templates select="document('')//s:sample"/>
  </xsl:template>

  <xsl:template match="s:sample">
    <xsl:call-template name="insertHeader">
      <xsl:with-param name="pos" select="1"/>
    </xsl:call-template>

    <xsl:variable name="node-set" select="table"/>
    <xsl:variable name="node-set-count" select="count($node-set)"/>
    <xsl:for-each select="$node-set">
      <xsl:call-template name="insertHeader">
        <xsl:with-param name="pos" select="1+position()"/>
      </xsl:call-template>
      <xsl:value-of select="."/>
      <xsl:text>
</xsl:text>
    </xsl:for-each>

    <xsl:call-template name="insertHeader">
      <xsl:with-param name="pos" select="2+$node-set-count"/>
    </xsl:call-template>

  </xsl:template>

  <xsl:template name="insertHeader">
    <xsl:param name="pos"/>
    <xsl:text>This is item number </xsl:text><xsl:value-of select="$pos" />
    <xsl:text>
</xsl:text>
  </xsl:template>

</xsl:stylesheet>

Nota: Das Beispieldokument ist in das Stylesheet eingebettet; wenden Sie also das Stylesheet auf sich selbst an, um das Ergebnis zu sehen.

$ xsltproc 3663349.xslt 3663349.xslt
This is item number 1
This is item number 2
Table A
This is item number 3
Table B
This is item number 4

0voto

user2864681 Punkte 1

<xsl:number /> sieht sich die Baumstruktur an und nummeriert sie von oben nach unten

xslt: <h2><xsl:number />.<xsl:value-of select="/t/tittel" /></h2>

von xml:
<tittel>e</tittel>
<tittel>ex</tittel>
<tittel>exa</tittel>
<tittel>example</tittel>

verwandelt sich in:

<h2>1. e</h2>
<h2>2. ex</h2>
<h2>3. exa</h2>
<h2>4. example</h2>

Mehr Informationen: http://www.xml.com/pub/a/2002/12/11/autocount.html

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X