split function in xslt 1.0
Asked Answered
S

6

14

how to split a node value in XSLT 1.0?

<mark>1,2</mark>

i need to perform some operations in the for loop with each value of the output of split.

<xsl:for-each select=""> </xsl:for-each>

How to do this?

Seale answered 15/9, 2011 at 1:55 Comment(4)
Are there always two items in the value, or is it a variable number?Wellworn
it may vary.Its the value of the node mark.Seale
Good question, +1. Depending on which version of XSLT (1.0 or 2.0) is used, this can be done, with recursive processing or just using the standard XPath 2.0 function tokenize().Keown
its 1.0. so tokenize cannot be used.Seale
K
17

I. XSLT 1.0 solution:

Here is one way to do this in XSLT 1.0 using only the xxx:node-set() extension function:

<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="mark">
  <xsl:variable name="vrtfSplit">
   <xsl:apply-templates/>
  </xsl:variable>

  <xsl:for-each select="ext:node-set($vrtfSplit)/*">
   <processedItem>
    <xsl:value-of select="10 * ."/>
   </processedItem>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="text()" name="split">
  <xsl:param name="pText" select="."/>
   <xsl:if test="string-length($pText) >0">
    <item>
     <xsl:value-of select=
      "substring-before(concat($pText, ','), ',')"/>
    </item>

    <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 to the following XML document:

<mark>1,2,3,4,5</mark>

The wanted, correct output (each item multiplied by 10) is produced:

<processedItem>10</processedItem>
<processedItem>20</processedItem>
<processedItem>30</processedItem>
<processedItem>40</processedItem>
<processedItem>50</processedItem>

II. XSLT 2.0 solution:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="mark">
  <xsl:for-each select="tokenize(., ',')">
   <processedItem>
    <xsl:sequence select="10*xs:integer(.)"/>
   </processedItem>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>
Keown answered 15/9, 2011 at 3:39 Comment(0)
I
8

The explaination by Dimitre Novatchev is awesome, but we can also do it in much more simpler way without using node-set() function have a look:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">


    <xsl:output omit-xml-declaration="yes" indent="yes"/>



    <xsl:variable name="delimiter">
        <xsl:text>,</xsl:text>
    </xsl:variable>



    <xsl:template match="mark">
        <xsl:variable name="dataList">
            <xsl:value-of select="."/>
        </xsl:variable>
        <xsl:call-template name="processingTemplate">
            <xsl:with-param name="datalist" select="$dataList"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="processingTemplate">
        <xsl:param name="datalist"/>


        <xsl:choose>
        <xsl:when test="contains($datalist,$delimiter)  ">
                <xsl:element name="processedItem">
                    <xsl:value-of select="substring-before($datalist,$delimiter) * 10"/>
                </xsl:element>
                <xsl:call-template name="processingTemplate">
                    <xsl:with-param name="datalist" select="substring-after($datalist,$delimiter)"/>
                </xsl:call-template>
        </xsl:when>
            <xsl:when test="string-length($datalist)=1">
                <xsl:element name="processedItem">
                    <xsl:value-of select="$datalist * 10"/>

                    </xsl:element>
            </xsl:when>
        </xsl:choose>    

    </xsl:template>
</xsl:stylesheet>
Indiscreet answered 16/4, 2012 at 6:50 Comment(0)
I
3

In 1.0 you need to write a recursive template - except you don't, because it's already been written. Download the str:tokenize template from http://www.exslt.org.

Ingenuity answered 15/9, 2011 at 8:47 Comment(0)
C
2

If you can use exslt there's a tokenize() function that will do this nicely.

node-set str:tokenize(string, string?)

See http://www.exslt.org/str/functions/tokenize/

Contrast answered 15/9, 2011 at 3:24 Comment(0)
F
0

This code will split a delimited string in XSLT 1.0 (It will work for 2.0, but don't use the node-set.) It will also optionally suppress empty elements in the string or optionally upper case the elements.

<!-- Example delimited string. -->
<xsl:variable name="delimitedString" select="'a, b, c, ,   , d, e, f, g'"/>

<!-- Create a node set where each node contains one of the elements from the
     delimited string. -->
<xsl:variable name="splitNodes">
  <xsl:call-template name="getNodeListFromDelimitedList">
    <xsl:with-param name="inStrList" select="$delimitedString"/>
    <xsl:with-param name="delimiter" select="','"/>
    <xsl:with-param name="suppressEmptyElements" select="false()"/>
    <xsl:with-param name="upperCase" select="false()"/>
    <xsl:with-param name="allTrim" select="false()"/>
  </xsl:call-template>    
</xsl:variable>

<!-- Use this for XSLT 1.0 only. -->
<xsl:variable name="splitNodesList" select="msxml:node-set($splitNodes)"/>

<!-- Use the split node list to do something.  For example, create a string like 
     the delimited string, but without the delimiters. -->
<xsl:variable name="nonDelimitedString">
  <xsl:for-each select="$splitNodesList/element">
    <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:variable>


<!-- Do something with the nonDelimitedString. -->

<!-- 
*****************************************************************************************

This template converts a delimited string list to a node list as follows:

Each value in the delimited input string is extracted from the string.  Then, a node is 
created to contain the value.   The name of the node is 'element', and it is added to the 
list.  To use this template, create an variable and call this template from within the variable.
If you are using XSLT version 1.0, convert the node list to a node set using the node-set 
function.  You can access the element as follows:  $SomeVariableNodeSet/element

*****************************************************************************************
-->
<xsl:template name="getNodeListFromDelimitedList">
  <!-- Delimited string with one or more delimiters.  -->
  <xsl:param name="inStrList"/>
  <!-- The delimiter. -->
  <xsl:param name="delimiter" select="'|'"/>
  <!-- Set to true to suppress empty elements from being added to node list. Otherwise, set to 'false'.-->
  <xsl:param name="suppressEmptyElements" select="true()"/>
  <!-- Set to true to upper case the strings added to the node list.  -->
  <xsl:param name="upperCase" select="false()"/>
  <!-- Set to true to left trim and right trim the strings added to the nodes list.  -->
  <xsl:param name="allTrim" select="false()"/>

  <xsl:variable name="element">
    <xsl:choose>
      <xsl:when test="contains($inStrList,$delimiter)">
        <xsl:value-of select="substring-before($inStrList,$delimiter)"/> 
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$inStrList"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <!-- Write out the element based on parameters. -->
  <xsl:if test="not($suppressEmptyElements) or normalize-space($element) != ''">
    <!-- Put the element in the list.  -->
    <xsl:element name="element">
      <xsl:choose>
        <xsl:when test="$allTrim">
          <xsl:call-template name="all-trim">
            <xsl:with-param name="inStr" select="$element"/>
            <xsl:with-param name="upperCase" select="$upperCase"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:when test="$upperCase">
          <xsl:value-of select="translate($element, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$element"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:if>

  <xsl:if test="contains($inStrList,$delimiter)">
    <!-- Call template recursively to process the next element. -->
    <xsl:call-template name="getNodeListFromDelimitedList">
      <xsl:with-param name="inStrList" select="substring-after($inStrList,$delimiter)"/>
      <xsl:with-param name="delimiter" select="$delimiter"/>
      <xsl:with-param name="suppressEmptyElements" select="$suppressEmptyElements"/>
      <xsl:with-param name="upperCase" select="$upperCase"/>
      <xsl:with-param name="allTrim" select="$allTrim"/>
    </xsl:call-template>
  </xsl:if>

</xsl:template>


<!-- 
*****************************************************************************************
This template trims the blanks from the left and right sides of a string. 
*****************************************************************************************
-->
<xsl:template name="all-trim">
  <!-- The string that you want to all trim. -->
  <xsl:param name="inStr"/>
  <xsl:param name="upperCase" select="false()"/>

  <xsl:variable name="leftTrimmed">
    <xsl:call-template name="left-trim">
      <xsl:with-param name="inStr" select="$inStr"/>
    </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="rightTrimmed">
    <xsl:call-template name="right-trim">
      <xsl:with-param name="inStr" select="$leftTrimmed"/>
    </xsl:call-template>
  </xsl:variable>

  <xsl:choose>
    <xsl:when test="$upperCase">
      <xsl:value-of select="translate($rightTrimmed, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$rightTrimmed"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- 
*****************************************************************************************
This template trims the blanks from the left side of a string. 
*****************************************************************************************
-->
<xsl:template name="left-trim">
  <!-- The string you want to left trim.  -->
  <xsl:param name ="inStr"/>

  <xsl:choose>
    <xsl:when test="$inStr!=''">
      <xsl:variable name="temp" select="substring($inStr, 1, 1)"/>
      <xsl:choose>
        <xsl:when test="$temp=' '">
          <xsl:choose>
            <xsl:when test="string-length($inStr) &gt; 1">
              <xsl:call-template name="left-trim">
                <xsl:with-param name="inStr" select="substring($inStr, 2, string-length($inStr)-1)"/>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="''"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$inStr"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="''"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!--
*****************************************************************************************
This template trims the blanks from the right side of a string. 
*****************************************************************************************
-->
<xsl:template name="right-trim">
  <!-- The string you want to right trim.  -->
  <xsl:param name ="inStr"/>

  <xsl:choose>
    <xsl:when test="$inStr!=''">
      <xsl:variable name="temp" select="substring($inStr, string-length($inStr), 1)"/>
      <xsl:choose>
        <xsl:when test="$temp=' '">
          <xsl:choose>
            <xsl:when test="string-length($inStr) &gt; 1">
              <xsl:call-template name="right-trim">
                <xsl:with-param name="inStr" select="substring($inStr, 1, string-length($inStr)-1)"/>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="''"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$inStr"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="''"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
Flatfoot answered 23/12, 2016 at 5:36 Comment(0)
T
0

Based on @Abhinav solution I just simplified recursive solution to work with general strings. My input string which I need to split is "GEN_EME2_G9_3311|A55;GEN_EME2_G9_3312|A55;foooo_3312|A42"

    <xsl:variable name="delimiter">
       <xsl:text>;</xsl:text>
    </xsl:variable>

    <xsl:template name="fooTemplate">
   ...
        <xsl:choose>        
            <xsl:when test="$conditionlink != ''">      
                <xsl:call-template name="processconditionlinktemplate">
                    <xsl:with-param name="datalist" select="$conditionlink"/>
                </xsl:call-template>            
            </xsl:when>
        </xsl:choose>
    ...
    </xsl:template>

    <xsl:template name="processconditionlinktemplate">
        <xsl:param name="datalist"/>
        <xsl:choose>
            <xsl:when test="contains($datalist,$delimiter)">
                <xsl:element name="processedItem">
                    <xsl:value-of select="substring-before($datalist,$delimiter)"/>
                </xsl:element>
                <xsl:call-template name="processconditionlinktemplate">
                    <xsl:with-param name="datalist" select="substring-after($datalist,$delimiter)"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>     
                <xsl:element name="processedItem">
                    <xsl:value-of select="$datalist"/>  
                </xsl:element>
            </xsl:otherwise>
        </xsl:choose>    
    </xsl:template>
Transgress answered 29/9, 2021 at 10:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.