sanjay
sanjay

Reputation: 1020

Overwrite attribute with XSLT

I have XML:

<doc>
    <p id="123" sec="abc"></p>
</doc>

Using XSLT, I need to:

1) add new attribute name with value 'myname'

2) copy same sec value

3) overwrite id attribute to new value

I've written the following XSLT to do that,

<xsl:template match="p">
    <p name="myname" id="999">
        <xsl:apply-templates select="node()|@*"/>
    </p>
</xsl:template>

It gives me following result:

<doc>
   <p name="myname" id="123" sec="abc"></p>
</doc>

The desired result is:

<doc>
   <p name="myname" id="999" sec="abc"></p>
</doc>

It seems it does not overwrite id attribute value. How can I overwrite this value from XSLT?

Upvotes: 1

Views: 1655

Answers (4)

Michael Kay
Michael Kay

Reputation: 163458

The key thing is that if you add several attributes with the same name to an element, the last one wins. Your explicit id="999" is considered to precede the attribute that you copy using the xsl:apply-templates call, so it has no effect.

There are several solutions. You can avoid applying templates to the @id attribute (using a select in the apply-templates); you can have a template rule for the @id attribute that does not cause it to be copied; or you could add the id="999" attribute AFTER doing the apply-templates, by means of an xsl:attribute instruction that appears after the xsl:apply-templates instruction.

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 117073

Or simply:

<xsl:template match="p">
    <p name="myname" id="999" sec="{@sec}"/>
</xsl:template>

--

In case the p element can contain other nodes (unlike the example shown), use:

<xsl:template match="p">
    <p name="myname" id="999" sec="{@sec}">
        <xsl:apply-templates/>
    </p>    
</xsl:template>

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167691

Change the template

<xsl:template match="p">
        <p name="myname" id="999">
            <xsl:apply-templates select="node()|@*"/>
        </p>
</xsl:template>

to

<xsl:template match="p">
        <p name="myname" id="999">
            <xsl:apply-templates select="@* except @id, node()"/>
        </p>
</xsl:template>

or write a template for the id attribute:

<xsl:template match="p">
  <p name="myname">
     <xsl:apply-templates select="@* , node()"/>
  </p>
</xsl:template>

<xsl:template match="p/@id">
  <xsl:attribute name="id" select="999"/>
</xsl:template>

Upvotes: 6

Andr&#233; R.
Andr&#233; R.

Reputation: 1647

i can't try it myself at the moment ... please try to NOT copy 'id' attribute since this will overrule your 'id' attribute in the xslt.

<xsl:template match="p">
        <p name="myname" id="999">
            <xsl:apply-templates select="node()|@*[local-name() != 'id']"/>
        </p>
</xsl:template>

Upvotes: 2

Related Questions