sanjay
sanjay

Reputation: 1020

XSLT - template match conflicts

I have a xml like follows,

<doc>
  <a ref="style1"></a>
  <a ref="style1"></a>
  <a ref="style1" ></a>
  <a ref="style2"></a>
  <a ref="style2"></a>
<doc>

I need to add separate stuff from xslt to <a ref="style1"> nodes and <a ref="style2"> nodes. I can write those required logic within <xsl:template match ="a[@ref = 'style1']"> and <xsl:template match ="@ref = 'style2'"> templates.

I also need to add dynamic id's to <a> nodes. so I wrote following templte for add required ids

//adds dynamic id's to `<a>` nodes
<xsl:template match="a[@ref='style1' or @ref='style2']">
    <a ref="style">
        <xsl:attribute name="id">
            <xsl:number count="a[@ref='style1' or a[@ref='style2']"/>
        </xsl:attribute>
    </a>
</xsl:template>

my expected output is follows,

<doc>
      <a ref="style" id="1"></a>
      <a ref="style" id="2"></a>
      <a ref="style" id="3"></a>
      <a ref="style" id="4"></a>
      <a ref="style" id="5"></a>
 <doc>

but since i'm using same template in two places (<xsl:template match ="a[@ref = 'style1']"> and <xsl:template match="a[@ref='style1' or @ref='style2']">) it gives me an "Ambiguous rule match" error in oxygen editor. how can I organize my code structure to avoid this error in this scenario ?

Upvotes: 0

Views: 475

Answers (1)

Daniel Haley
Daniel Haley

Reputation: 52858

One option is to make the template that handles both style1 and style2 a moded template.

XML Input

<doc>
    <a ref="style1"/>
    <a ref="style1"/>
    <a ref="style1"/>
    <a ref="style2"/>
    <a ref="style2"/>
</doc>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="a[@ref='style1' or @ref='style2']" mode="addId">
        <xsl:apply-templates select="@*"/>
        <xsl:attribute name="ref" select="'style'"/>
        <xsl:attribute name="id">
            <xsl:number count="a[@ref=('style1','style2')]"/>
        </xsl:attribute>       
    </xsl:template>

    <xsl:template match="a[@ref='style1']">
        <xsl:copy>
            <xsl:apply-templates select="." mode="addId"/>
            <xsl:apply-templates select="node()"/>
            <special>processed style1</special>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="a[@ref='style2']">
        <xsl:copy>
            <xsl:apply-templates select="." mode="addId"/>
            <xsl:apply-templates select="node()"/>
            <special>processed style2</special>
        </xsl:copy>
    </xsl:template>    

</xsl:stylesheet>

Output

<doc>
   <a ref="style" id="1">
      <special>processed style1</special>
   </a>
   <a ref="style" id="2">
      <special>processed style1</special>
   </a>
   <a ref="style" id="3">
      <special>processed style1</special>
   </a>
   <a ref="style" id="4">
      <special>processed style2</special>
   </a>
   <a ref="style" id="5">
      <special>processed style2</special>
   </a>
</doc>

Depending on what processing your individual templates for style1 and style2 do you could add a higher priority to the common template and use xsl:next-match to then match the lower priority templates (the individual processing)...

XSLT 2.0 (produces same output using input above)

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="a[@ref='style1' or @ref='style2']" priority="1">
        <a ref="style">
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="id">
                <xsl:number count="a[@ref=('style1','style2')]"/>
            </xsl:attribute>
            <xsl:next-match/>
        </a>
    </xsl:template>

    <xsl:template match="a[@ref='style1']">
        <special>processed style1</special>
    </xsl:template>

    <xsl:template match="a[@ref='style2']">
        <special>processed style2</special>
    </xsl:template>    

</xsl:stylesheet>

Upvotes: 1

Related Questions