[xsl] Passing attributes in a node-set

Subject: [xsl] Passing attributes in a node-set
From: Frank Klasens <inet.frank@xxxxxxxxx>
Date: Tue, 17 Jan 2006 10:30:06 +0100
Hi,

I have this input.xml:

<root>
    <element avalue="foo"><evalue>foo</evalue></element>
    <element avalue="bar"><evalue>bar</evalue></element>
</root>

which I transform into this output.xml:

<root>
    <element name="bar" value="foo"/>
    <element name="foo" value="foo"/>
     <element name="bar_1" value="foo"/>
    <element name="bar_2" value="bar"/>
    <element name="foo_1" value=""/>
    <element name="foo_2" value=""/>
</root>

in a generic way using the templates below. I have another xslt which
processes a table in xml and outputs xslt calls to named templates. In
this example xslt I've put four of these generated calls and two
stripped-down versions of the templates being called which gives the
output above.

If it would be working correctly the last two elements from the output
should contain foo and bar as well. Can anybody see my mistake? I've
used Xalan 2.7.0 and Saxon 6.5.5, the problem is not there. I think it
has something to do with the way I pack the attributes in the
node-set, but I have to find something general because the xpaths are
in a xml and I don't know the type of the result.

<?xml version=" 1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform " xmlns:exslt="
http://exslt.org/common";>
    <xsl:template match="/">
        <root>
            <!-- the next two calls both create only the first element
from the two selected -->
            <xsl:call-template name="create">
                <xsl:with-param select="'bar'" name="name"/>
                <xsl:with-param select="//element/evalue" name="value"/>
            </xsl:call-template>
            <xsl:call-template name="create">
                <xsl:with-param select="'foo'" name="name"/>
                <xsl:with-param select="//element/@avalue" name="value"/>
            </xsl:call-template>
            <!-- this call creates elements with both selected values,
which is good -->
            <xsl:call-template name="repeat">
                <xsl:with-param select="2" name="n"/>
                <xsl:with-param select="'bar'" name="name"/>
                <xsl:with-param name="value">
                    <root>
                        <xsl:copy-of select="//element/evalue"/>
                    </root>
                </xsl:with-param>
            </xsl:call-template>
            <!-- now I want the same for attributes, but how? -->
            <xsl:call-template name="repeat">
                <xsl:with-param select="2" name="n"/>
                <xsl:with-param select="'foo'" name="name"/>
                <xsl:with-param name="value">
                    <root>
                        <xsl:copy-of select="//element/@avalue"/>
                    </root>
                </xsl:with-param>
            </xsl:call-template>
        </root>
    </xsl:template>
    <xsl:template name="create">
        <xsl:param name="name"/>
        <xsl:param name="value"/>
        <xsl:element name="element">
            <xsl:attribute name="name"><xsl:value-of
select="$name"/></xsl:attribute>
            <xsl:attribute name="value"><xsl:value-of
select="$value"/></xsl:attribute>
            <!--<xsl:attribute name="value"><xsl:copy-of
select="$value"/></xsl:attribute>-->
        </xsl:element>
    </xsl:template>
    <xsl:template name="repeat">
        <xsl:param name="n"/>
        <xsl:param name="name"/>
        <xsl:param name="value"/>
        <xsl:param name="index" select="1"/>
        <xsl:variable name="name2"
select="concat($name,'_',string($index))"/>
        <xsl:if test="$n &gt;= $index">
            <xsl:call-template name="create">
                <xsl:with-param name="name" select="$name2"/>
                <xsl:with-param name="value"
select="exslt:node-set($value)/root/*[$index]"/>
            </xsl:call-template>
            <!-- template is recursively called with index as the
number of copies already made -->
            <xsl:call-template name="repeat">
                <xsl:with-param name="n" select="$n"/>
                <xsl:with-param name="index" select="$index + 1"/>
                <xsl:with-param name="name" select="$name"/>
                <xsl:with-param name="value" select="$value"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Frank

Current Thread