I have cheated every time I've needed to do a line count in XSLT by using JScript, but in this case I can't do that. I simply want to write out a line counter throughout an output file. This basic example has a simple solution:
<xsl:for-each select="Records/Record">
<xsl:value-of select="position()"/>
</xsl:for-each>
Output would be:
1
2
3
4
etc...
But what if the structure is more complex with nested foreach's :
<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 inner foreach would just reset the counter (so you get 1, 1, 2, 3, 2, 1, 2, 3, 1, 2 etc). Does anyone know how I can output the position in the file (ie. a line count)?
While it is quite impossible to mark the line numbers for the serialization of an XML document (because this serialization per se is ambiguous), it is perfectly possible, and
easy
, to number the lines of regular text.This transformation:
when applied on this XML document:
produces the desired line-numbering:
A line in an XML file is not really the same as an element. In your first example you don't really count the lines - but the number of elements.
An XML file could look like this:
Or the exact same XML file can look like this:
which the XSLT will interpet exactly the same - it will not really bother with the line breaks.
Therefore it's hard to show line numbers in the way you want using XSLT - it's not really meant for for that kind of parsing.
Someone correct me if I'm wrong, but I'd say you would need Javascript or some other scripting language to do what you want.
Generally,
position()
is referring to the number of the current node relative to the entire batch of nodes that is being processed currently.With your "nested for-each" example, consecutive numbering can easily be achieved when you stop nesting for-each constructs and just select all desired elements at once.
With this XML:
a loop construct like this
will result in
but you could simply do this instead:
and you would get
Thanks for the responses guys - yup you're totally correct, some external function is the only way to get this behaviour in XSLT. For those searching, this is how I did this when using a compiled transform in .Net 3.5:
Create a helper class for your function(s)
Add an instance to an args list for XSLT
Use it in you XSLT
Put this in the stylesheet declaration element:
Then use like so: