Robie Nayak
Robie Nayak

Reputation: 827

How can we add a child tag if another childtag has specific string in XSLT?

My XML contains the following lines. I want to add a child tag <PV1.2>IN</PV1.2> if the <PV1.18> has the value "INR".

<PV1>
  <PV1.1>0001</PV1.1>
  <PV1.3>
    <PL.1>5N</PL.1>
    <PL.2>0552</PL.2>
    <PL.3>0B</PL.3>
  </PV1.3>
  <PV1.8>INR</PV1.8>
  <PV1.19>
    <CX.1>000002194171</CX.1>
  </PV1.19>
</PV1>

Output shoud be:

<PV1>
  <PV1.1>0001</PV1.1>
  <PV1.2>IN</PV1.2>
  <PV1.3>
    <PL.1>5N</PL.1>
    <PL.2>0552</PL.2>
    <PL.3>0B</PL.3>
  </PV1.3>
  <PV1.8>INR</PV1.8>
  <PV1.19>
    <CX.1>000002194171</CX.1>
  </PV1.19>
</PV1>

The piece of code I tried in XSLT is as below; but it doesn't work:

<xsl:template match="PV1">
  <xsl:choose>
    <xsl:when test="PV1.18 eq 'INR'">
      <PV1.2>IN</PV1.2>
    </xsl:when>
  </xsl:choose>
</xsl:template>

Upvotes: 0

Views: 66

Answers (1)

Tim C
Tim C

Reputation: 70618

Looking at the xslt template you have provided, not only will it not add the PV1.2 element, it should output nothing at all because it there is any code to copy across all the existing elements.

Anyway, this may be a typo, but your current template is looking for PV1.18, when there is none in your XML. I think perhaps PV1.8 should be PV1.18 in your XML sample. (I also think you should be using '=' and not 'eq' here). Ideally though, this should check should not be in an xsl:choose (especially when you don't have an xsl:otherwise), but you should do the check in a template match

<xsl:template match="PV1[PV1.18 = 'INR']">

Then within the template you would have to copy the existing PVI1 element, create the PV1.2 element, and also output the children.

Try this XSLT

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

   <xsl:template match="PV1[PV1.18 = 'INR']">
      <xsl:copy>
         <xsl:apply-templates select="PV1.1"/>
         <PV1.2>IN</PV1.2>
         <xsl:apply-templates select="*[not(self::PV1.1)]"/>
      </xsl:copy>
   </xsl:template>

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

The main thing to note here is the use of the Identity Transform, which will copy across all the other elements as-is, so you only need templates for things you need to transform. There are two xsl:apply-templates here, because it looks like you won't to insert the PV1.2 after PV1.1.

In the case of a PV1 element having no PV1.18 = 'INR', then the identity template does all the work, and the output will be the same as the input.

Upvotes: 1

Related Questions