Kundan
Kundan

Reputation: 153

Template correction in XSLT

<To>
    <Id>SERVICE</Id>
    <Role>Commuter</Role>
</To>
<BPD>
    <OrgNo>234</OrgNo>      
</BPD>
<BON>123</BON>

I have this Input XML in which I want to check whether //To/Id contains SERVICE or not. If it contains SERVICE then a element should be added after <BPD> naming <BON>SERVICE</BON>. Also I want to check if my Input XML already contains <BON> element then its value should be replaced by SERVICE which is in <Id> element.

I have created a template for this ->

<xsl:template match="BPD">
 <xsl:choose>
   <xsl:when test="not(BON) and normalize-space(/To[Role='Commuter']/Id)='SERVICE'">
     <BON>
    <xsl:text>SERVICE</xsl:text>
     </BON>
   </xsl:when>          
   <xsl:when test="normalize-space(BON) and normalize-space(/To[Role='Commuter']/Id)='SERVICE'">
      <BON>
    <xsl:text>SERVICE</xsl:text>
      </BON>
    </xsl:when>
 </xsl:choose>
</xsl:template>

This template is checking whether exists or not. If it doesn't exist then it creates <BON> element and adds 'SERVICE' as value to it. And if exists then it creates one more element which is not required. I need to correct my second when situation.

Upvotes: 1

Views: 96

Answers (2)

Daniel Haley
Daniel Haley

Reputation: 52878

If you're just replacing the existing <BON> if it exists, you should only need this:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="BPD[../To[Role='Commuter']/Id='SERVICE']">
    <xsl:call-template name="ident"/>
    <BON>SERVICE</BON>
  </xsl:template>

  <xsl:template match="BON[../To[Role='Commuter']/Id='SERVICE']"/>  

</xsl:stylesheet>

With either this input:

<doc>
  <To>
    <Id>SERVICE</Id>
    <Role>Commuter</Role>
  </To>
  <BPD>
    <OrgNo>234</OrgNo>      
  </BPD>
  <BON>123</BON>  
</doc>

or this input (no <BON>)

<doc>
  <To>
    <Id>SERVICE</Id>
    <Role>Commuter</Role>
  </To>
  <BPD>
    <OrgNo>234</OrgNo>      
  </BPD>
</doc>

it will produce this output:

<doc>
   <To>
      <Id>SERVICE</Id>
      <Role>Commuter</Role>
   </To>
   <BPD>
      <OrgNo>234</OrgNo>
   </BPD>
   <BON>SERVICE</BON>
</doc>

Upvotes: 2

Tim C
Tim C

Reputation: 70638

I think what you are saying is that is that if you have a To element with a id of 'SERVICE' and a Role of 'Commuter' then you want to ensure there is a following BON element with a value of 'SERVICE' (replacing any existing one if it already exists).

This can be done without using an xsl:choose but two separate matching templates. Firstly you can match the case where you have a BON element and the preceding elements are for 'Commuter' and 'SERVICE'.

<xsl:template match="BON[preceding-sibling::To[Role='Commuter'][normalize-space(Id)='SERVICE']]">

Then you can have a template that matches the BPD element where there is no BON element at all.

Here is the full XSLT

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

   <xsl:template match="BON[preceding-sibling::To[Role='Commuter'][normalize-space(Id)='SERVICE']]" name="bon">
      <BON>SERVICE</BON>
   </xsl:template>   

   <xsl:template match="BPD[preceding-sibling::To[Role='Commuter'][normalize-space(Id)='SERVICE']][not(following-sibling::BON)]">
      <xsl:call-template name="identity" />
      <xsl:call-template name="bon" />
   </xsl:template>

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

Do note the use of named templates, to avoid duplicate coding of the BON element.

When applied to the following XML

<Root>
   <To>
      <Id>SERVICE</Id>
      <Role>Commuter</Role>
   </To>
   <BPD>
      <OrgNo>234</OrgNo>
   </BPD>
   <BON>123</BON>
</Root>

The following is output

<Root>
   <To>
      <Id>SERVICE</Id>
      <Role>Commuter</Role>
    </To>
    <BPD>
       <OrgNo>234</OrgNo>
    </BPD>
    <BON>SERVICE</BON>
</Root>

If you changed the input XML to the following, then it would also yield the same output in this case

<Root>
   <To>
      <Id>SERVICE</Id>
      <Role>Commuter</Role>
   </To>
   <BPD>
      <OrgNo>234</OrgNo>
   </BPD>
</Root>

Upvotes: 0

Related Questions