1
votes

I have following xml file

<rules>
  <rule>
    <name>aa</name>
  </rule>

    <rule>
    <name>cc</name>
  </rule>

  <rule>
     <name>bb</name>
  </rule>

 </rules>

I would like to remove existing 3 rules and instead add new rule

 <rule>
     <name>zz</name>
  </rule>

so the output should be

<rules>
    <rule>
        <name>zz</name>
    </rule>
</rules>

I have tried this xslt ,

<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:template match="rule[name[text()='aa']]"/>
    <xsl:template match="rule[name[text()='bb']]"/>

    <xsl:template match="rule[name[text()='cc']]"/>


    <xsl:template match="rule[position()=last()]">
        <xsl:copy-of select="."/>
        <rule>
            <name>zz</name>
        </rule>
    </xsl:template>


</xsl:stylesheet>

but it produce this - (cc is not removed)

<rules>
    <rule>
        <name>cc</name>
    </rule>
    <rule>
        <name>zz</name>
    </rule>

</rules>

What is the problem with xslt ?

2
Remove <xsl:copy-of select="."/> from your template - har07

2 Answers

1
votes

If you want to replace all rule elements under rules, it might be simpler just to have a template that matches rules instead, where you output the new rule, and don't select anything else.

<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:template match="rules">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>            
            <rule>
                <name>zz</name>
            </rule>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Alternatively, if you have other rule elements you want to keep, other the the aa, bb and cc ones, then you can add an xsl:apply-templates to the rules templates, and have your other matching templates to ignore them

<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:template match="rules">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>            
            <rule>
                <name>zz</name>
            </rule>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="rule[name='aa']"/>
    <xsl:template match="rule[name='bb']"/>
    <xsl:template match="rule[name='cc']"/>
</xsl:stylesheet>
0
votes

As XSL is functional, all operations you define happen on the original document. It is not like you remove the one rule then another etc, you just define a function that will be applied to the original document. Your last template will transform the matched node into the same node (copy operation) plus the new element.