Reputation: 1020
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
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