Reputation: 153
<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
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
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