My understanding is that the usage of <xsl:template />
and <xsl:for-each>
almost serve the same purpose and <xsl:for-each >
is a sort of "anonymous inline template".
Question: However, considering the below scenario, i think using <xsl:for-each>
is more appropriate. Please validate my understanding, or is there a way the output can be achieved through <xsl:template>
as well?
Input XML:
<?xml version="1.0" encoding="UTF-8"?> <books> <book.child.1> <title>charithram</title> <author>sarika</author> </book.child.1> <book.child.2> <title>doublebell</title> <author>psudarsanan</author> </book.child.2> </books>
Expected output:
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="book1"> <title>charithram</title> <author>sarika</author> </book> <book id="book2"> <title>doublebell</title> <author>psudarsanan</author> </book> </books>
XSLT1 [using <xsl:for-each >
] - This gives the expected output
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" /> <xsl:template match="/"> <newbooks> <xsl:for-each select="books/*"> <newbook id="book{position()}"> <title><xsl:value-of select="title" /></title> <author> <xsl:value-of select="author" /></author> </newbook> </xsl:for-each> </newbooks> </xsl:template> </xsl:stylesheet>
XSLT2 [using <xsl:template >
]
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" /> <xsl:template match="/"> <newbooks> <xsl:apply-templates/> </newbooks> </xsl:template> <xsl:template match="books/*" > <newbook id="book{position()}"> <title><xsl:value-of select="title" /></title> <author> <xsl:value-of select="author" /></author> </newbook> </xsl:template> </xsl:stylesheet>
This does not give the expected output, Instead, the output obtained is,
<?xml version="1.0" encoding="UTF-8"?> <newbooks> <newbook id="book2"> <title>charithram</title> <author>sarika</author> </newbook> <newbook id="book4"> <title>doublebell</title> <author>psudarsanan</author> </newbook> </newbooks>
The only reason i can think of getting 2 and 4, could be the position of id
node inside the context.
"The position()
function returns the position of the context node in a selected set of nodes". As per this definition, it works in the case of for-each
as the context is each <book>
element. But why it is not applicable in the case of template?
I also tried with <xsl:number>
, but cannot make it to work as expected
<xsl:template match="/"> <newbooks> <xsl:apply-templates/> </newbooks> </xsl:template> <xsl:template match="books/*" > <newbook > <xsl:attribute name="id"> <xsl:text>book</xsl:text><xsl:number/> </xsl:attribute> <title><xsl:value-of select="title" /></title> <author> <xsl:value-of select="author" /></author> </newbook> </xsl:template>
I am getting the output of book1, book1 [not incrementing]
Please help.
Note: I use XSLT to transform into output XML which has complete different set of tags compared to input XML, so I don't use a template to copy.