0
votes

I have xml like follows,

<doc>
    <session>
        <a type="abc">
            <b>contetnt</b>
            <c>contetnt</c>
        </a>
        <a type="abc">
            <b>contetnt</b>
            <c>contetnt</c>
        </a>
        <a type="abc">
            <b>contetnt</b>
            <c>contetnt</c>
        </a>
        <d></d>
        <e></e>
        <f></f>
    </session>
</doc>

my requirements are,

1) add node just before the end of node

2) nodes which are in current document should place under the newly created node

3) add dynamically increment id to node

so the output should be

<doc>
    <session>
        <d></d>
        <e></e>
        <f></f>
        <end>
            <a idNo="1" type="abc">
                <b>contetnt</b>
                <c>contetnt</c>
            </a>
            <a idNo="2" type="abc">
                <b>contetnt</b>
                <c>contetnt</c>
            </a>
            <a idNo="3" type="abc">
                <b>contetnt</b>
                <c>contetnt</c>
            </a>
        </end>
    </session>
</doc>

I wrote following xsl to do this task,

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

    <!-- add dynamic id -->
    <xsl:template match="a">
        <xsl:copy>
            <xsl:attribute name="idNo">
                <xsl:number count="a"/>
            </xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- create <end> node and copy <a> nodes -->
    <xsl:template match="session">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
            <end>endNode</end>
            <xsl:copy-of select="a"/>
        </xsl:copy>
    </xsl:template>

    <!-- remove original <a> nodes-->
    <xsl:template match="a"/>

when I run these xsl separately they run fine but when I run them all I get an ambiguous template matching error.

My xsl codes are correct but I'm having a problem of organize them in right order to achieve my task.

can anyone suggest an method to organize these code in correct manner to achieve my task?

1

1 Answers

3
votes

You have two templates matching a exactly, which is considered an error. XSLT will either flag the error, or may pick the last template.

One way to resolve this, is the use of the mode attribute. Change you xsl:copy select="a" /> to use xsl:apply-templates instead (which you should be doing anyway as you want to transform them)

 <xsl:apply-templates select="a" mode="end"/>

Then, change the first template match to also use this mode. Then you XSLT will look like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes" />

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

    <!-- add dynamic id -->
    <xsl:template match="a" mode="end">
        <xsl:copy>
            <xsl:attribute name="idNo">
                <xsl:number count="a"/>
            </xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- create <end> node and copy <a> nodes -->
    <xsl:template match="session">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
            <end>
                <xsl:apply-templates select="a" mode="end"/>
            </end>
        </xsl:copy>
    </xsl:template>

    <!-- remove original <a> nodes-->
    <xsl:template match="a"/>
</xsl:stylesheet>

Alternatively, in the session template, rather than process all the child nodes, add code to ignore the a elements at that point

 <xsl:apply-templates select="@*|node()[not(self::a)]"/>

This means you wouldn't need the template to remove them anymore.

Try this XSLT too

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes" />

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

    <!-- add dynamic id -->
    <xsl:template match="a">
        <xsl:copy>
            <xsl:attribute name="idNo">
                <xsl:number count="a"/>
            </xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- create <end> node and copy <a> nodes -->
    <xsl:template match="session">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()[not(self::a)]"/>
            <end>
                <xsl:apply-templates select="a"/>
            </end>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>