NewtoXSLT
NewtoXSLT

Reputation: 41

Problem with COPY Apply Template XSLT

I have started learning XSLT just recently and have come up with a scenario.The source and target structure are exactly the same this am able to accomplish with the code below:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

</xsl:stylesheet>

But my requirement is to create the target node only if one of the conditions is met.

Example if

VNum eq 999

source and target should look like this:

Source

 <POExt>
    <SD>01</SD>
    <PODet>
        <PNum schemeAgencyID="TEST">12345678</PNum>
        <VNum>999</VNum>
    </PODet>
    <PODet>
        <PNum schemeAgencyID="">45654654</PNum>
        <VNum>001</VNum>
    </PODet>
 </POExt>

Target

 <POExt>
    <SD>01</SD>
    <PODet>
        <PNum schemeAgencyID="TEST">12345678</PNum>
        <VNum>999</VNum>
    </PODet>
 </POExt>

<PODet> is repeated everytime it meets the VNum criteria, if none of the <PODet> meets the criteria it is OK to have

 <POExt>
    <SD>01</SD>
 </POExt>

Want to accomplish this using Copy and apply-templates, any help would be much appreciated.

Thanks..

Upvotes: 4

Views: 1123

Answers (1)

Emiliano Poggi
Emiliano Poggi

Reputation: 24836

When working with the identity rule you need to override the elements by matching templates.

In your case, you want not to copy the PODet elements which do not met a certain condition. According to a negative logic, you have just to 'shut up' the nodes that do not match your condition. For instance:

<xsl:stylesheet version="1.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="PODet[not(VNum/text()=999)]"/>

</xsl:stylesheet>

If your VNum is variable, say an input parameter for your transform, in XSLT 2.0 you can simply do:

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output indent="yes"/>

    <xsl:param name="VNum" select="999"/>

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

    <xsl:template match="PODet[not(VNum/text()=$VNum)]"/>

</xsl:stylesheet>

In XSLT 1.0 variables are not allowed in the template match pattern so that you have to include the condition check inside the template. For example, you can apply the templates only to the elements matching your condition:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="VNum" select="999"/>

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

    <xsl:template match="PODet">
        <xsl:apply-templates select="VNum[text()=$VNum]"/>
    </xsl:template>

    <xsl:template match="VNum">
        <xsl:copy-of select=".."/>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 3

Related Questions