2010-05-26 5 views
5

Ich habe jedesmal betrogen, wenn ich eine Zeilenzählung in XSLT mit JScript durchführen musste, aber in diesem Fall kann ich das nicht tun. Ich möchte einfach einen Zeilenzähler in eine Ausgabedatei schreiben. Dieses Grundbeispiel hat eine einfache Lösung:XSLT-Zeilenzähler - ist es so schwer?

<xsl:for-each select="Records/Record"> 
    <xsl:value-of select="position()"/> 
</xsl:for-each> 

Output wäre:

etc ...

Aber was, wenn die Struktur ist komplexer mit verschachtelter foreach ist:

<xsl:for-each select="Records/Record"> 
    <xsl:value-of select="position()"/> 
    <xsl:for-each select="Records/Record"> 
     <xsl:value-of select="position()"/> 
    </xsl:for-each> 
</xsl:for-each> 

Hier ist die innere foreach würde den Zähler nur zurückgesetzt (so erhalten Sie 1, 1, 2, 3, 2, 1, 2, 3, 1, 2 usw.). Weiß jemand, wie ich die Position in der Datei ausgeben kann (zB eine Zeilenzahl)?

+0

Ausgezeichnete Frage (1) erhalten. Siehe meine Antwort für eine Lösung, die Zeilennummern für Text erzeugt. –

Antwort

5

Eine Zeile in einer XML-Datei ist nicht wirklich dasselbe wie ein Element. In Ihrem ersten Beispiel zählen Sie nicht die Zeilen, sondern die Anzahl der Elemente.

Eine XML-Datei könnte wie folgt aussehen:

<cheeseCollection> 
<cheese country="Cyprus">Gbejna</cheese><cheese>Liptauer</cheese><cheese>Anari</cheese> 
</cheeseCollection> 

Oder genau die gleiche XML-Datei wie folgt aussehen:

<cheeseCollection> 
    <cheese 
     country="Cyprus">Gbejna</cheese> 
    <cheese>Liptauer</cheese> 
    <cheese>Anari</cheese> 
</cheeseCollection> 

die der XSLT Interpet wird genau das gleiche - es wird nicht wirklich Ärger mit den Zeilenumbrüchen.

Daher ist es schwierig, Zeilennummern in der Art, wie Sie wollen, mit XSLT zu zeigen - es ist nicht wirklich für diese Art von Parsing gedacht.

Jemand korrigiert mich, wenn ich falsch liege, aber ich würde sagen, dass Sie Javascript oder eine andere Skriptsprache benötigen würden, um zu tun, was Sie wollen.

+1

Sie sind genau richtig - "Position" (d. H. Zeilennummer) ist in XML völlig bedeutungslos, da Leerzeichen, einschließlich Zeilenumbrüche, nicht als Teil des Dokumentbaums betrachtet werden. – GalacticCowboy

+1

@GalacticCowboy: Whitespaces * werden * als Teil des Dokumentbaums betrachtet - sie sind in Textknoten enthalten. – liori

+0

@liori: Ich denke, er meinte den Raum zwischen Attributen - dieser Raum ist kein separates Objekt in der XDM und kann nicht durch einen XPath-Ausdruck zugegriffen werden –

6

Während es ganz unmöglich ist, die Zeilennummern für die Serialisierung eines XML-Dokument markieren (da diese Serialisierung per se nicht eindeutig ist), ist es durchaus möglich, und easy, die Linien des normalen Textes nummerieren.

Diese Transformation:

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

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

<xsl:template name="numberLines"> 
    <xsl:param name="pLastLineNum" select="0"/> 
    <xsl:param name="pText" select="."/> 

    <xsl:if test="string-length($pText)"> 
    <xsl:value-of select="concat($pLastLineNum+1, ' ')"/> 

    <xsl:value-of select="substring-before($pText, '&#xA;')"/> 
    <xsl:text>&#xA;</xsl:text> 

    <xsl:call-template name="numberLines"> 
    <xsl:with-param name="pLastLineNum" 
     select="$pLastLineNum+1"/> 
    <xsl:with-param name="pText" 
     select="substring-after($pText, '&#xA;')"/> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

, wenn sie auf diesem XML Dokument angewendet:

<t>The biggest airlines are imposing "peak travel surcharges" 
this summer. In other words, they're going to raise fees 
without admitting they're raising fees: Hey, it's not a $30 
price hike. It's a surcharge! This comes on the heels of 
checked-baggage fees, blanket fees, extra fees for window 
and aisle seats, and "snack packs" priced at exorbitant 
markups. Hotels in Las Vegas and elsewhere, meanwhile, are 
imposing "resort fees" for the use of facilities (in other 
words, raising room rates without admitting they're 
raising room rates). The chiseling dishonesty of these 
tactics rankles, and every one feels like another nail in 
the coffin of travel as something liberating and 
pleasurable. 
</t> 

erzeugt die gewünschte Zeilennummerierung:

1 The biggest airlines are imposing "peak travel surcharges" 
2 this summer. In other words, they're going to raise fees 
3 without admitting they're raising fees: Hey, it's not a $30 
4 price hike. It's a surcharge! This comes on the heels of 
5 checked-baggage fees, blanket fees, extra fees for window 
6 and aisle seats, and "snack packs" priced at exorbitant 
7 markups. Hotels in Las Vegas and elsewhere, meanwhile, are 
8 imposing "resort fees" for the use of facilities (in other 
9 words, raising room rates without admitting they're 
10 raising room rates). The chiseling dishonesty of these 
11 tactics rankles, and every one feels like another nail in 
12 the coffin of travel as something liberating and 
13 pleasurable. 
3

Vielen Dank für die Antworten guys - yup Sie sind völlig richtig, einige externe Funktion ist die einzige Möglichkeit, dieses Verhalten in XSLT zu bekommen.Auf der Suche sind, dann ist dies, wie ich dies tat, als mit einem in .NET 3.5-Transformation zusammengestellt:

eine Hilfsklasse erstellen für Ihre Funktion (en)

/// <summary> 
/// Provides functional support to XSLT 
/// </summary> 
public class XslHelper 
{ 
    /// <summary> 
    /// Initialise the line counter value to 1 
    /// </summary> 
    Int32 counter = 1; 

    /// <summary> 
    /// Increment and return the line count 
    /// </summary> 
    /// <returns></returns> 
    public Int32 IncrementCount() 
    { 
     return counter++; 
    } 
} 

eine Instanz in eine args Liste für XSLT

XslCompiledTransform xslt = new XslCompiledTransform(); 
xslt.Load(XmlReader.Create(s)); 
XsltArgumentList xslArg = new XsltArgumentList(); 
XslHelper helper = new XslHelper(); 
xslArg.AddExtensionObject("urn:helper", helper); 
xslt.Transform(xd.CreateReader(), xslArg, writer); 

Verwenden Sie es in Ihnen

dieses XSLT Setzen Sie in der Stylesheet-Deklaration Element:

Dann verwenden, so wie:

<xsl:value-of select="helper:IncrementCount()" /> 
1

Allgemeinen wird position() auf die gesamte Charge von Knoten zu der Anzahl der dem aktuellen Knoten relativ bezieht, die gegenwärtig verarbeitet wird.

Mit Ihrem Beispiel "verschachtelt für jedes" kann die fortlaufende Nummerierung leicht erreicht werden, wenn Sie die Verschachtelung für jedes Konstrukt beenden und alle gewünschten Elemente gleichzeitig auswählen.

Mit diesem XML:

<a><b><c/><c/></b><b><c/></b></a> 

eine Schleife konstruieren wie diese

<xsl:for-each "a/b"> 
    <xsl:value-of select="position()" /> 
    <xsl:for-each "c"> 
    <xsl:value-of select="position()" /> 
    </xsl:for-each> 
</xsl:for-each> 

führt in

11221 
bccbc // referred-to nodes 

aber man konnte einfach das tun, statt:

<xsl:for-each "a/b/c"> 
    <xsl:value-of select="position()" /> 
</xsl:for-each> 

und Sie würden

123 
ccc // referred-to nodes 
Verwandte Themen