Russ Urquhart
Russ Urquhart

Reputation: 329

An attribute node (filter) cannot be created after a child of the containing element

I have the following template to pass back a filter attribute:

<xsl:template name="have_arch_attrib">
<xsl:variable name="condition_values"/>
<xsl:variable name="security_values"/>
<xsl:variable name="arch_values"/>
<xsl:choose> 
    <xsl:when test=".[@arch]"> <!-- add arch values -->
        <xsl:variable name="arch_values" select=".[@arch]" />
    </xsl:when>

    <xsl:when test=".[@condition]"> <!-- Add condition values -->
        <xsl:variable name="condition_values" select=".[@condition]" />
    </xsl:when>

    <xsl:when test=".[@security]"> <!-- Add condition values -->
        <xsl:variable name="security_values" select=".[@security]"/>
    </xsl:when>
</xsl:choose>
<xsl:attribute name="filter"><xsl:value-of select="concat($condition_values, $security_values, $arch_values)"/></xsl:attribute>

I've looked at other solutions, but i can't see how they can apply to this?

Can anyone give me a clue?

Thanks,

Russ

Upvotes: 1

Views: 2057

Answers (2)

hr_117
hr_117

Reputation: 9627

There are some problems in your template.

  • The value of variable can't be changed after initialization.
  • Your test condition are wrong. Thy should be look something like <xsl:when test="@arch">.
  • If the assigning to variable would work only the first one with existing attribute would get a value, because only the first when part with test pass will be executed.
  • It is not really clear what your goal is.

Interpreting your template as pseudo code would be: The attribute filter should get the value of the first existing attribute (out of arch, condition or security). Which would be this xlst:

<xsl:template name="have_arch_attrib">
    <xsl:attribute name="filter">
    <xsl:choose>
        <xsl:when test="@arch">
            <xsl:value-of select="@arch" />
        </xsl:when>
        <xsl:when test="@condition">
            <xsl:value-of select="@condition" />
        </xsl:when>
        <xsl:when test="@security">
            <xsl:value-of select="@security" />
        </xsl:when>
    </xsl:choose>
    </xsl:attribute>
</xsl:template>

Based on your comment to the answer from Ian Roberts:
"The only reason i was checking if the attributes existed, was that i needed to delimit any attributes with a ",". I can see how i can changes these aftwerwards"

Try something like this:

    <xsl:attribute name="filter">
            <xsl:if test="@arch">
                <xsl:value-of select="@arch" />
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:if test="@condition">
                <xsl:value-of select="@condition" />
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:if test="@security">
                <xsl:value-of select="@security" />
            </xsl:if>
    </xsl:attribute>
</xsl:template>

This is surly still not perfect, but your statements are not clear enough.
If "delimit" means separate the above template will generate a not wonted terminating comma. To avoid this you can try:

 <xsl:template name="have_arch_attrib">
    <xsl:attribute name="filter">
        <xsl:for-each select="@arch | @condition | @security ">
            <xsl:value-of select="." />
            <xsl:if test="position() != last()" >
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        </xsl:attribute>
</xsl:template>

Upvotes: 1

Ian Roberts
Ian Roberts

Reputation: 122364

The error message is pretty descriptive - you can't add attribute nodes to an element using <xsl:attribute> after you've added any child nodes (elements, text nodes, comments or processing instructions). So the problem that causes that error message is in what happens before you call the have_arch_attrib template rather than in the template itself.

That said, the template you have given here won't produce the result you want, because you can't modify the value of an XSLT variable after it has been created. You will need to re-structure the template to put the <xsl:choose> inside the <xsl:attribute>, rather than trying to use variables to carry the various values around. Or in fact just lose the choose altogether as it's not an error to ask for the value-of an attribute that doesn't exist, you simply get the empty string.

<xsl:attribute name="filter">
  <xsl:value-of select="@condition"/>
  <xsl:value-of select="@security"/>
  <xsl:value-of select="@arch"/>
</xsl:attribute>

Upvotes: 2

Related Questions