2

I have a following scenario. I have a TEAM-MEMBERS node which has name in the format last name, first name

<TEAM-MEMBER><LONG-NAME>Last Name, First Name</LONG-NAME></TEAM-MEMBER>

I want to transform this to

<CONTACT><FIRSTNAME>First Name</FIRSTNAME><LASTNAME>Last Name</LASTNAME></CONTACT>

Basically i want to split the <LONG-NAME> node's value by ,

How can I achieve this using XSLT 1.0

This XSLT will be consumed by BizTalk Server hence i am looking for some XSLT 1.0 solutions only

Thanks

Karthik

KK99
  • 1,971
  • 7
  • 31
  • 64
  • 1
    possible duplicate of [Does XSLT have a Split() function?](http://stackoverflow.com/questions/136500/does-xslt-have-a-split-function) – James Sulak Mar 12 '11 at 06:52
  • 1
    If you have it working, please either post your code (preferred) or close the question as "no longer relevant". – Tomalak Mar 12 '11 at 07:32
  • Good question, +1. See my answer for two XSLT 1.0 solutions, each providing a general template to split a string into substrings (no matter how many) given a set of delimiters. :) – Dimitre Novatchev Mar 12 '11 at 18:01

3 Answers3

2

Here is a complete XSLT 1.0 solution that uses a general "split" template that splits a string into multiple substrings, provided a delimiter to designate the boundary between substrings:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="TEAM-MEMBER">
  <xsl:variable name="vrtfSplitWords">
   <xsl:call-template name="split">
    <xsl:with-param name="pText" select="."/>
   </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="vSplitWords"
  select="ext:node-set($vrtfSplitWords)/*"/>

  <CONTACT>
   <FIRSTNAME><xsl:value-of select="$vSplitWords[2]"/></FIRSTNAME>
   <LASTNAME><xsl:value-of select="$vSplitWords[1]"/></LASTNAME>
  </CONTACT>
 </xsl:template>

 <xsl:template name="split">
  <xsl:param name="pText" select="."/>
  <xsl:param name="pDelim" select="', '"/>
  <xsl:param name="pElemName" select="'word'"/>

  <xsl:if test="string-length($pText)">
   <xsl:element name="{$pElemName}">
    <xsl:value-of select=
     "substring-before(concat($pText,$pDelim),
                       $pDelim
                      )
     "/>
   </xsl:element>

   <xsl:call-template name="split">
    <xsl:with-param name="pText" select=
    "substring-after($pText,$pDelim)"/>
    <xsl:with-param name="pDelim" select="$pDelim"/>
    <xsl:with-param name="pElemName" select="$pElemName"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<TEAM-MEMBER><LONG-NAME>Last Name, First Name</LONG-NAME></TEAM-MEMBER>

the wanted, correct result is produced:

<CONTACT>
   <FIRSTNAME>First Name</FIRSTNAME>
   <LASTNAME>Last Name</LASTNAME>
</CONTACT>

II. Solution using FXSL

This transformation uses the str-split-to-words template from FXSL:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 exclude-result-prefixes="ext"
>
  <xsl:import href="strSplit-to-Words.xsl"/>
  <xsl:output indent="yes" omit-xml-declaration="yes"/>

   <xsl:strip-space elements="*"/>
   <xsl:output indent="yes" omit-xml-declaration="yes"/>

   <xsl:param name="pmaxLines" select="10"/>

    <xsl:template match="/">
      <xsl:variable name="vwordNodes">
        <xsl:call-template name="str-split-to-words">
          <xsl:with-param name="pStr" select="/"/>
          <xsl:with-param name="pDelimiters"
                          select="',()'"/>
        </xsl:call-template>
      </xsl:variable>

      <xsl:apply-templates select=
       "ext:node-set($vwordNodes)/*[normalize-space()]"/>

    </xsl:template>

    <xsl:template match="word[normalize-space()][1]">
      <FIRSTNAME>
       <xsl:value-of select="normalize-space()"/>
      </FIRSTNAME>
    </xsl:template>

    <xsl:template match="word[normalize-space()][2]">
      <MIDNAME>
       <xsl:value-of select="normalize-space()"/>
      </MIDNAME>
    </xsl:template>

    <xsl:template match="word[normalize-space()][last()]">
      <LASTNAME>
       <xsl:value-of select="normalize-space(.)"/>
      </LASTNAME>
    </xsl:template>
</xsl:stylesheet>

when applied to this XML document (made quite more complex):

<TEAM-MEMBER><LONG-NAME>First Name, (Jr.), Last Name</LONG-NAME></TEAM-MEMBER>

the wanted, correct result is produced:

<FIRSTNAME>First Name</FIRSTNAME>
<MIDNAME>Jr.</MIDNAME>
<LASTNAME>Last Name</LASTNAME>

Do Note:

The str-split-to-words template accepts multiple delimiters. Thus in this transformation the delimiters used are: ',', '(' and ')'

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
0

You need a recursive named template. Fortunately it's already been written: look for str:tokenize at http://www.exslt.org.

Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
Michael Kay
  • 156,231
  • 11
  • 92
  • 164
0

used substring-after() and substring-before() to get around the split

j0k
  • 22,600
  • 28
  • 79
  • 90
KK99
  • 1,971
  • 7
  • 31
  • 64