sanjay
sanjay

Reputation: 1020

XSLT - add attribute to node dynamically

I have xml like follows,

<doc>
<p type="Foot">
    <link ref="http://www.facebook.com">
        <c type="Hyperlink">www.facebook.com</c>
    </link>
</p>
 <p type="End">
    <link ref="http://www.google.com">
        <c type="Hyperlink">www.google.com.com</c>
    </link>
</p>
</doc>

what I need to do is add dynamic id attributes to <p> node which has attribute "Foot" and "End". SO I have written following xsl,

<xsl:template match="p[@type='Foot' or @type='End']" priority="1">
     <xsl:copy>
        <xsl:attribute name="id">
            <xsl:value-of select="'foot-'"/> 
            <xsl:number count="p[@type='Foot' or @type='End']" level="any"/>
        </xsl:attribute>
        <xsl:next-match/>
    </xsl:copy>
    </xsl:template>

it gives me following result

<doc>
<p id="foot-1"><p type="Foot">
    <link ref="http://www.facebook.com">
        <c type="Hyperlink">www.facebook.com</c>
    </link>
</p></p>
 <p id="foot-2"><p type="End">
    <link ref="http://www.google.com">
        <c type="Hyperlink">www.google.com.com</c>
    </link>
</p></p>
</doc>

as above result xml, it add duplicate

node and add new attribute. but what I need is this,

<doc>
<p id="foot-1 type="Foot">
    <link ref="http://www.facebook.com">
        <c type="Hyperlink">www.facebook.com</c>
    </link>
</p></p>
 <p id="foot-2 type="End">
    <link ref="http://www.google.com">
        <c type="Hyperlink">www.google.com.com</c>
    </link>
</p></p>
</doc>

How can I get this output from changing mu xsl?

Upvotes: 0

Views: 456

Answers (1)

Flynn1179
Flynn1179

Reputation: 12075

I think your problem is likely to be something we can't see from your question- you're calling xsl:next-match, in a template that's already outputting a p tag from the xsl:copy instruction. If the next match, whatever that happens to be also does xsl:copy, you're going to get a second p tag inside the first, like you're seeing.

It sounds like what you need to do is have another template with higher priority that matches only p, have this do the <xsl:copy>, call <xsl:next-match> inside that then process subnodes, and remove the <xsl:copy> from the lower-priority templates that match specific cases.

<xsl:template match="p" priority="2">
  <xsl:copy>
    <xsl:next-match/>
    <xsl:apply-templates select="node() | @*"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="p[@type='Foot']" priority="1">
  <xsl:attribute name="id">
    <xsl:value-of select="'foot-'"/> 
    <xsl:number count="p[@type='Foot' or @type='End']" level="any"/>
  </xsl:attribute>
  <xsl:next-match/>
</xsl:template>

etc..

Incidentally, you don't need <xsl:value-of select="'foot-'"/>- if it's just a constant, then <xsl:text>foot-</xsl:text> will do.

Upvotes: 3

Related Questions