Title: Adding an index on tag value with XSLT: `position()` returning double the expected value
Tags: xml;xslt;xslt-1.0
Question: I have an input XML:
<root&gt;
<child&gt;somevalue</child&gt;
<child&gt;othervalue</child&gt;
</root&gt;
And a need this output:
<root&gt;
<child&gt;item1_somevalue</child&gt;
<child&gt;item2_othervalue</child&gt;
</root&gt;
I'm using this template:
<xsl:template match="*[local-name()='root' and namespace-uri()='']/*[local-name()='child' and namespace-uri()='']"&gt;
<xsl:element name="{local-name()}"&gt;
<xsl:text&gt;item</xsl:text&gt;
<xsl:value-of select="position()"/&gt;
<xsl:text&gt;_</xsl:text&gt;
<xsl:value-of select="."/&gt;
</xsl:element&gt;
</xsl:template&gt;
And getting this result:
<child&gt;item2_somevalue</child&gt;
<child&gt;item4_othervalue</child&gt;
Why is position() returning double the expected value?
I'm not worried about the root tag right now.
Must use XSLT 1.0.
Comment: ... but *the question*, as presented, is too broad.

Comment: I edited the question with an example.

Comment: This seems to be a trivial task: use the `position()` function.

Here is the accepted answer: Explaining what's going on
The position() function can return unexpected results sometimes.  At first glance, it sounds like it should return the position of the context element with respect to its parent container.  So for our sample input XML:
<root&gt;
<child&gt;somevalue</child&gt;
<child&gt;othervalue</child&gt;
</root&gt;
... we would expect to see that the position() for the first child element would be 1, and the position() for the second child element would be 2.
But when we run our sample XSL against that code, we get the following output:
<child&gt;item2_somevalue</child&gt;
<child&gt;item4_othervalue</child&gt;
The key is that we need to pay special attention to the wording.  The position() element doesn't just count elements, it counts nodes -- and that includes text nodes.  So in the sample input XML above, the first child element is actually the second node under root, because it's preceded by a text node (the newline and leading whitespace).  And, for the same reason, the second child element is actually the fourth node under root.  So position() is returning exactly what it should.
Fixing the behavior
There are a couple ways of fixing this.  One is to explicitly count child elements, as jpmo22's post does.  Another approach, which is more flexible, is to tell the XSL processor to ignore whitespace-only text nodes.  We can do this by adding a top-level element to our XSLT code:
<xsl:strip-space elements="*"/&gt;
We can customize the list of elements if needed, by replacing the * with a list of element names.
If we just add that strip-space directive before the template in our sample XSL code, we can get the expected result:
<child&gt;item1_somevalue</child&gt;
<child&gt;item2_othervalue</child&gt;
Other considerations
The XPath in the match statement is convoluted.
<xsl:template match="*[local-name()='root' and namespace-uri()='']/*[local-name()='child' and namespace-uri()='']"&gt;
In cases where element names have no prefixes, local-name and name return identical results.  Our sample input XML has no prefixes, so there's no reason to use local-name.  In fact, we could simply use the desired element names rather than *.  Moreover, our sample input XML has no namespace declarations at all, so there's no reason to use namespace-uri.
A suggested simplification:
<xsl:template match="root/child"&gt;
The use of element is also a bit convoluted.
<xsl:element name="{local-name()}"&gt;
We already know that we're working with child elements, since that's what we just matched in this template.  We could more simply just use the element name in a literal element declaration, like this:
<child&gt;
If we wanted to genericize our code, we could also just copy over the context element:
<xsl:copy&gt;
Comment for this answer: Thank you for a very complete answer and explanation. About "Other consideration" topic I simplified my actual XSLT wicth I need to use an especific name-space and thats why the match seens to be convoluted. On my real XSLT I don't know if the name of the tag is "child" but your consideration is valid for the example I gave. Use the strip-space directive didn't work on my real XSLT I'm assuming is because it's more complex and have another templates running.

Here is another answer: I found the solution. I changed the position() to count(preceding75b5:f2c1:f5d7:b954:8dc3:cee9:baf:a8c0*[local-name()='child']) + 1
<xsl:template match="*[local-name()='child']"&gt;
<xsl:element name="{local-name()}"&gt;
<xsl:text&gt;item</xsl:text&gt;
<xsl:value-of select="count(preceding75b5:f2c1:f5d7:b954:8dc3:cee9:baf:a8c0*[local-name()='child']) + 1"/&gt;
<xsl:text&gt;_</xsl:text&gt;
<xsl:value-of select="."/&gt;
</xsl:element&gt;
</xsl:template&gt;
Gives the right result:
<child&gt;item1_somevalue</child&gt;
<child&gt;item2_othervalue</child&gt;
Comment for this answer: Repeatedly counting preceding siblings is expensive. A better solution is to control the selected node-set, for example by stripping white-space-only nodes or by applying templates only to `child` elements from the context of a template matching `root`.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 2, 'CommentCount': 3, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2017:00:06/16/17', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<xml><xslt><xslt-1.0>', 'Title': 'Adding an index on tag value with XSLT: `position()` returning double the expected value', 'ViewCount': 1173, 'id': 44595164, 'user_AboutMe': '', 'user_AccountId': 1731960.0, 'user_DisplayName': 'jpmo22', 'user_Reputation': 77.0, 'user_Views': 9.0, 'user_id': 1585385.0}}