Reputation: 733
I'm really a newbie to this XSLT world. I am facing a problem of splitting the values present in a single XML node.
For example my input XML contains the following data:
<Employee>
<FirstName>AAA</FirstName>
<LastName>BBB</LastName>
<MobileNo>9999999999-6666666666-7777777777</MobileNo>
</Employee>
In the above example an employee can have multiple mobile numbers, so all his mobile numbers are merged into a single XML node <MobileNo>
. A hyphen (-) is used to separate the mobile numbers, meaning 9999999999
is the first mobile number, 6666666666
is the second mobile number, and 7777777777
is the third mobile number. An Employee can have any number of mobile numbers.
Myy output XML should have the following structure.
<Employee>
<FirstName>AAA</FirstName>
<LastName>BBB</LastName>
<MobileNo>9999999999</MobileNo>
<MobileNo>6666666666</MobileNo>
<MobileNo>7777777777</MobileNo>
</Employee>
so how do I achieve this using XSLT 1.0?
Your help will be appreciated.
Upvotes: 3
Views: 2913
Reputation: 243459
Here is a complete, shorter and simpler (no xsl:choose
, no xsl:when
, no xsl:otherwise
) XSLT 1.0 transformation that "splits" any number of dash-separated strings:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="MobileNo" name="split">
<xsl:param name="pText" select="."/>
<xsl:if test="$pText">
<MobileNo>
<xsl:value-of select="substring-before(concat($pText, '-'), '-')"/>
</MobileNo>
<xsl:call-template name="split">
<xsl:with-param name="pText" select="substring-after($pText, '-')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<Employee>
<FirstName>AAA</FirstName>
<LastName>BBB</LastName>
<MobileNo>9999999999-6666666666-7777777777</MobileNo>
</Employee>
the wanted, correct result is produced:
<Employee>
<FirstName>AAA</FirstName>
<LastName>BBB</LastName>
<MobileNo>9999999999</MobileNo>
<MobileNo>6666666666</MobileNo>
<MobileNo>7777777777</MobileNo>
</Employee>
Explanation:
Recursively called named template (split
).
The stop condition is the passed parameter being an empty node-set/string.
Use of sentinel to avoid unnecessary conditional instructions.
Upvotes: 4
Reputation: 126722
You must write this as a recursive named template. The code below shows the idea.
The named template split-mobile
here is passed a string with possible hyphens where the string must be split.
A call to substring-before
fetches the first number. This will return an empty string (which evaluates to false) if the string contains no hyphen.
An <xsl:choose>
element outputs the first number inside a <MobileNo>
element and calls substring-before
with the remainder of the string if it was hyphenated. Otherwise the entire string is output.
<xsl:template match="MobileNo">
<xsl:call-template name="split-mobile" >
<xsl:with-param name="numbers" select="text()" />
</xsl:call-template>
</xsl:template>
<xsl:template name="split-mobile">
<xsl:param name="numbers" />
<xsl:variable name="number" select="substring-before($numbers, '-')" />
<xsl:choose>
<xsl:when test="$number">
<MobileNo>
<xsl:value-of select="$number" />
</MobileNo>
<xsl:call-template name="split-mobile">
<xsl:with-param name="numbers" select="substring-after($numbers, '-')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<MobileNo>
<xsl:value-of select="$numbers" />
</MobileNo>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Upvotes: 0