xml - xslt 1.0 consolidate empty element names -


a quick question on using xslt 1.0 might able me with.i have input xml looks below

<root>     <firstname>bob</firstname>     <lastname>marley</lastname>     <id>bm1234</id>     <songs>         <song>             <emptyelements></emptyelements>             <songname>no woman no cry</songname>             <year>1974</year>             <album></album>             <studio></studio>             <rating></rating>         </song>     </songs> </root> 

the output needs like

<root>     <firstname>bob</firstname>     <lastname>marley</lastname>     <id>bm1234</id>     <songs>         <song>             <emptyelements>album, studio, rating</emptyelements>             <songname>no woman no cry</songname>             <year>1974</year>         </song>     </songs> </root> 

so comma separated list of empty elements emptyelements tag.

or simply:

xslt 1.0

<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:strip-space elements="*"/>  <!-- identity transform --> <xsl:template match="@*|node()">     <xsl:copy>         <xsl:apply-templates select="@*|node()"/>     </xsl:copy> </xsl:template>  <xsl:template match="song">     <xsl:copy>         <emptyelements>             <xsl:for-each select="*[not(node() or self::emptyelements)]">                  <xsl:value-of select="name()"/>                  <xsl:if test="position()!=last()">                     <xsl:text>, </xsl:text>                  </xsl:if>             </xsl:for-each>          </emptyelements>         <xsl:apply-templates select="*[node()]"/>     </xsl:copy> </xsl:template>  </xsl:stylesheet> 

note:

this solution proudly uses last() function. there no performance issues related using function.

the xpath specification states:

the last function returns number equal context size expression evaluation context.

and xslt specification tells that:

expression evaluation occurs respect context. ... context consists of:

• node (the context node)
• pair of non-zero positive integers (the context position , context size)
...

the idea processor go , count nodes in current node list, again , again, each node in list preposterous. once context has been established (by calling either xsl:for-each or xsl:apply-templates), context size known , isn't going change.

this conclusion can put test: using list of 10k items, no discernible difference found when evaluating:

<xsl:for-each select="item">     <xsl:value-of select="position()!=last()"/> </xsl:for-each> 

against:

<xsl:for-each select="item">     <xsl:value-of select="not(position() = 1)"/> </xsl:for-each> 

(tested libxslt, xalan , saxon).