Alok Ranjan
Alok Ranjan

Reputation: 131

Adding an element in xml based on match using xsl

I have xml entries as follows:

<employee>
<component name="address">
<property name="city" value="Bangalore">
<property name="state" value="Karnataka">
<component/>
<component name="info">
<property name="name" value="Alok"></property>
<property name="age" value="25"></property>
</component>
</employee>

So for entry in info field, I want to add an element with position as engineer like below:

<property name="position" value ="engineer"></property>

I am trying to achieve this by doing

<xsl:template match="/employee/component[@name='info']">
  <xsl:if test="not(property[@name='position'])">
  <xsl:element name="property">
  <xsl:attribute name="position">position</xsl:attribute>
  <xsl:attribute name="value">engineer</xsl:attribute>
  </xsl:element>
  </xsl:if>
  </xsl:template>

But what it is doing is completely removing the info block and adding line

Need suggestions on correct way of implementing this.

Upvotes: 0

Views: 139

Answers (1)

Tim C
Tim C

Reputation: 70598

The problem is in your template, you are creating a new element, but you are tell XSLT to also copy the existing component node and its child nodes. You are effectively saying when you find a matching component node, create a new node instead.

What you need to do, is add code to copy the existing node, like so

<xsl:template match="/employee/component[@name='info']">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:if test="not(property[@name='position'])">
            <xsl:element name="property">
                <xsl:attribute name="position">position</xsl:attribute>
                <xsl:attribute name="value">engineer</xsl:attribute>
            </xsl:element>
        </xsl:if>
    </xsl:copy>
</xsl:template>

This can be simplified though by moving the condition in the xsl:if to the template match instead. Also, there is no need to use xsl:element and xsl:attribute here, just write out the new element directly.

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

    <xsl:template match="/employee/component[@name='info'][not(property[@name='position'])]">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <property position="position" name="engineer" />
        </xsl:copy>
    </xsl:template>

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

Note the use of the Identity Template in the transformation to copy all other existing nodes.

Upvotes: 2

Related Questions