XSLT line counter - is it difficult?

I cheated every time I needed to do line counting in XSLT using JScript, but in this case I cannot do this. I just want to write a line counter in the output file. This basic example has a simple solution:

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

Output:

1

2

3

4

etc...

But what if the structure is more complicated with a nested foreach:

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

Here, the internal foreach will simply reset the counter (so that you get 1, 1, 2, 3, 2, 1, 2, 3, 1, 2, etc.). Does anyone know how I can infer a position in a file (i.e. Number of lines)?

+5
source share
4 answers

The line in the XML file does not actually match the element. In your first example, you really don't count the rows, but the number of elements.

An XML file might look like this:

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

XML :

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

XSLT - .

, , XSLT - , .

- , , , Javascript - , , .

+5

XML- ( ), , easy, .

:

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

XML-:

<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 not a $30
 price hike. It 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>

:

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 not a $30
4  price hike. It 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.
+6

, , - , - - XSLT. , , .Net 3.5:

.

/// <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++;
    }
}

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

XSLT

:

 xmlns:helper="urn:helper"   

:

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

, position() node , .

With your “nested for each” example, sequential numbering can be easily achieved when you stop nesting for each design and immediately select all the elements you need.

Using this XML:

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

loop building like this

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

will result in

11221
bccbc  // referred-to nodes

but you can just do this:

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

and you will get

123
ccc    // referred-to nodes
+1
source