user1432155
user1432155

Reputation: 733

Splitting Values in XML using XSLT 1.0

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

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

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:

  1. Recursively called named template (split).

  2. The stop condition is the passed parameter being an empty node-set/string.

  3. Use of sentinel to avoid unnecessary conditional instructions.

Upvotes: 4

Borodin
Borodin

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

Related Questions