Given XML of:
<data>
<field>Value 1
Value 2
Value 3
</field>
</data>
I would like to be able to create some HTML to display the values and convert the
into <br/>
<html>
<head/>
<body>
<div>Field Values</div>
<div>Value 1<br/>Value 2<br/>Value 3<br/></div>
</body>
</html>
However I can't think of way to do this using XSL version 1.0?
I tried
<xsl:value-of select="field" disable-output-escaping="yes"/>
However the text all appears on 1 line.
Any ideas/suggestions?
Thanks
Dave
You can use a recursive template do do the replacement:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<data>
<xsl:call-template name="replaceCharsInString">
<xsl:with-param name="stringIn" select="data/field" />
</xsl:call-template>
</data>
</xsl:template>
<xsl:template name="replaceCharsInString">
<xsl:param name="stringIn"/>
<xsl:choose>
<xsl:when test="contains($stringIn,'
')">
<xsl:value-of select="substring-before($stringIn,'
')"/>
<br />
<xsl:call-template name="replaceCharsInString">
<xsl:with-param name="stringIn"
select="substring-after($stringIn,'
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$stringIn"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Here is how you can replace
with <br/>:
<xsl:template match="data">
<xsl:call-template name="add-br">
<xsl:with-param name="text" select="field" />
</xsl:call-template>
</xsl:template>
<xsl:template name="add-br">
<xsl:param name="text" select="."/>
<xsl:choose>
<xsl:when test="contains($text, '
')">
<xsl:value-of select="substring-before($text, '
')"/>
<br/>
<xsl:call-template name="add-br">
<xsl:with-param name="text" select="substring-after($text,'
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Related
I have a XML file following this scheme:
<translationData>
<product>
<attributeValue>
<value>1/4"</value>
<value1>1/4"</value1>
<currentValue>aaaa;bbbb</currentValue>
</attributeValue>
</product>
</translationData>
because of the semicolon in "currentValue" i need to escape the semicolon AND the double quotes in "value".
I am able to escape the semicolon by placing all text in qoutes as following:
XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8" />
<xsl:param name="delim" select="';'" />
<xsl:param name="quote" select="'"'" />
<xsl:param name="break" select="'
'" />
<xsl:template match="/">
<xsl:apply-templates select="translationData/product/attributeValue" />
</xsl:template>
<xsl:template match="attributeValue">
<xsl:apply-templates />
<xsl:if test="following::*">
<xsl:value-of select="$break" />
</xsl:if>
</xsl:template>
<xsl:template match="*">
<!-- remove normalize-space() if you want keep white-space at it is -->
<xsl:value-of select="concat($quote, translate(.,'"','\"'), $quote)" />
<xsl:if test="following-sibling::*">
<xsl:value-of select="$delim" />
</xsl:if>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
but somehow the Output is:
"1/4\";"1/4\";"aaaa;bbbb"
instead of
"1/4\"";"1/4\"";"aaaa;bbbb"
Where am I going wrong?
I am new to XML and XSLT and did not find any question handling this specific case.
XSLT code is from an answer by #Tomalak for another question. see here
The translate() function will only replace each single character with another single character.
To replace a single character " with a two-character string\" you need to use a named recursive template or - if your processor supports it - an extension function such as EXSLT str:replace().
Here's an example of using a recursive template:
...
<xsl:template match="*">
<xsl:text>"</xsl:text>
<xsl:call-template name="replace">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
<xsl:text>"</xsl:text>
<xsl:if test="position()!=last()">
<xsl:text>;</xsl:text>
</xsl:if>
</xsl:template>
...
<xsl:template name="replace">
<xsl:param name="text"/>
<xsl:param name="searchString">"</xsl:param>
<xsl:param name="replaceString">\"</xsl:param>
<xsl:choose>
<xsl:when test="contains($text,$searchString)">
<xsl:value-of select="substring-before($text,$searchString)"/>
<xsl:value-of select="$replaceString"/>
<!-- recursive call -->
<xsl:call-template name="replace">
<xsl:with-param name="text" select="substring-after($text,$searchString)"/>
<xsl:with-param name="searchString" select="$searchString"/>
<xsl:with-param name="replaceString" select="$replaceString"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
...
Given the following XML:
<application>
<documentation>Before text.
[This|http://google.com] is a link.
Click [here|http://google.com] for another link.
After text.
</documentation>
</application>
I want to replace new lines with <br/> tags and create links. The outcome should produce the following HTML:
Before text.<br/>
This is a link.<br/>
Click here for another link.<br/>
After text.
I have the XSLT below with the appropriate templates. My problem is that the <br/> elements added by the first function are stripped out by the second function. I've tried using an identity transform, but I can't wrap my head around it.
Any help would be appreciated.
My current XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0"/>
<xsl:template match="application">
<p>
<xsl:variable name="with_new_lines">
<xsl:call-template name="replace-newlines">
<xsl:with-param name="text" select="documentation"/>
<xsl:with-param name="replace" select="'
'"/>
<xsl:with-param name="by" select="'new_line'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="with_links">
<xsl:call-template name="create-links">
<xsl:with-param name="text">
<xsl:copy-of select="$with_new_lines"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:copy-of select="$with_links"/>
</p>
</xsl:template>
<xsl:template name="replace-newlines">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '
')">
<xsl:copy-of select="substring-before($text,'
')"/>
<br/>
<xsl:call-template name="replace-newlines">
<xsl:with-param name="text" select="substring-after($text,'
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Changing [here|http://a.com] to hereand
[http://a.com] to http://a.com-->
<xsl:template match="*" name="create-links">
<xsl:param name="text" select="."/>
<xsl:choose>
<xsl:when test="contains($text, 'http')">
<xsl:copy-of select="substring-before($text,'[')"/>
<xsl:variable name="the_link_and_after">
<xsl:copy-of select="substring-after($text,'[')"/>
</xsl:variable>
<xsl:variable name="the_link">
<xsl:copy-of select="substring-before($the_link_and_after,']')"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($the_link,'|')">
<xsl:variable name="the_url">
<xsl:copy-of select="substring-after($the_link,'|')"/>
</xsl:variable>
<a href="{$the_url}">
<xsl:copy-of select="substring-before($the_link,'|')"/>
</a>
</xsl:when>
<xsl:otherwise>
<a href="{$the_link}">
<xsl:copy-of select="$the_link"/>
</a>
</xsl:otherwise>
</xsl:choose>
<!--<xsl:copy-of select="substring-after($text,']')" />-->
<xsl:call-template name="create-links">
<xsl:with-param name="text" select="substring-after($text,']')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The problem with your approach is that each of your named templates creates a result-tree-fragment, containing a mixture of text nodes and elements (either <br> or <a>). When you send the result to be processed as a string by the other template, only the text nodes survive the treatment.
I would suggest you start by tokenizing the input into lines as elements. Then send each line in turn to be processed by the other template:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match="application">
<xsl:variable name="lines">
<xsl:call-template name="tokenize-lines">
<xsl:with-param name="text" select="documentation"/>
</xsl:call-template>
</xsl:variable>
<p>
<xsl:for-each select="exsl:node-set($lines)/line">
<xsl:call-template name="create-links">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
<br/>
</xsl:for-each>
</p>
</xsl:template>
<xsl:template name="tokenize-lines">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '
')">
<line><xsl:copy-of select="substring-before($text,'
')"/></line>
<xsl:call-template name="tokenize-lines">
<xsl:with-param name="text" select="substring-after($text,'
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<line><xsl:copy-of select="$text"/></line>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="create-links">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, 'http')">
<xsl:copy-of select="substring-before($text,'[')"/>
<xsl:variable name="the_link_and_after">
<xsl:copy-of select="substring-after($text,'[')"/>
</xsl:variable>
<xsl:variable name="the_link">
<xsl:copy-of select="substring-before($the_link_and_after,']')"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($the_link,'|')">
<xsl:variable name="the_url">
<xsl:copy-of select="substring-after($the_link,'|')"/>
</xsl:variable>
<a href="{$the_url}">
<xsl:copy-of select="substring-before($the_link,'|')"/>
</a>
</xsl:when>
<xsl:otherwise>
<a href="{$the_link}">
<xsl:copy-of select="$the_link"/>
</a>
</xsl:otherwise>
</xsl:choose>
<!--<xsl:copy-of select="substring-after($text,']')" />-->
<xsl:call-template name="create-links">
<xsl:with-param name="text" select="substring-after($text,']')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Alternatively, you could call the 2nd template from within the 1st one, for each line separately before returning it:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match="application">
<p>
<xsl:call-template name="create-lines">
<xsl:with-param name="text" select="documentation"/>
</xsl:call-template>
</p>
</xsl:template>
<xsl:template name="create-lines">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '
')">
<xsl:call-template name="create-links">
<xsl:with-param name="text" select="substring-before($text,'
')"/>
</xsl:call-template>
<br/>
<xsl:call-template name="create-lines">
<xsl:with-param name="text" select="substring-after($text,'
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="create-links">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="create-links">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, 'http')">
<xsl:copy-of select="substring-before($text,'[')"/>
<xsl:variable name="the_link_and_after">
<xsl:copy-of select="substring-after($text,'[')"/>
</xsl:variable>
<xsl:variable name="the_link">
<xsl:copy-of select="substring-before($the_link_and_after,']')"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($the_link,'|')">
<xsl:variable name="the_url">
<xsl:copy-of select="substring-after($the_link,'|')"/>
</xsl:variable>
<a href="{$the_url}">
<xsl:copy-of select="substring-before($the_link,'|')"/>
</a>
</xsl:when>
<xsl:otherwise>
<a href="{$the_link}">
<xsl:copy-of select="$the_link"/>
</a>
</xsl:otherwise>
</xsl:choose>
<!--<xsl:copy-of select="substring-after($text,']')" />-->
<xsl:call-template name="create-links">
<xsl:with-param name="text" select="substring-after($text,']')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I can't find the exact answer for this question so I hope someone will help me here.
I have a string and I want get the substring after the last '.'. I'm using xslt 1.0.
How is this done? This is my code.
<xsl:choose>
<xsl:otherwise>
<xsl:attribute name="class">method txt-align-left case-names</xsl:attribute>
<xsl:value-of select="./#name"/> // this prints a string eg: 'something1.something2.something3'
</xsl:otherwise>
</xsl:choose>
When i paste the suggested code I get an error message. "Parsing an XSLT stylesheet failed."
I can't think of a way to do this with a single expression in XSLT 1.0, but you can do it with a recursive template:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<n>
<xsl:call-template name="GetLastSegment">
<xsl:with-param name="value" select="'something1.something2.something3'" />
<xsl:with-param name="separator" select="'.'" />
</xsl:call-template>
</n>
</xsl:template>
<xsl:template name="GetLastSegment">
<xsl:param name="value" />
<xsl:param name="separator" select="'.'" />
<xsl:choose>
<xsl:when test="contains($value, $separator)">
<xsl:call-template name="GetLastSegment">
<xsl:with-param name="value" select="substring-after($value, $separator)" />
<xsl:with-param name="separator" select="$separator" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Result:
<n>something3</n>
I did the same behaviour with a xsl:function - usage is then a little bit simpler:
<xsl:function name="ns:substring-after-last" as="xs:string" xmlns:ns="yourNamespace">
<xsl:param name="value" as="xs:string?"/>
<xsl:param name="separator" as="xs:string"/>
<xsl:choose>
<xsl:when test="contains($value, $separator)">
<xsl:value-of select="ns:substring-after-last(substring-after($value, $separator), $separator)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value" />
</xsl:otherwise>
</xsl:choose>
</xsl:function>
And you can call it directly in a value-of:
<xsl:value-of select="ns:substring-after-last(.,'=')" xmlns:ns="yourNamespace"/>
Here is a solution using EXSLT str:tokenize:
<xsl:if test="substring($string, string-length($string)) != '.'"><xsl:value-of select="str:tokenize($string, '.')[last()]" /></xsl:if>
(the if is here because if your string ends with the separator, tokenize won't return an empty string)
I resolved it
<xsl:call-template name="GetLastSegment">
<xsl:with-param name="value" select="./#name" />
</xsl:call-template>
Did not need the
<xsl:with-param name="separator" value="'.'" />
in the template call
I have split one string key6='||1-LIW-3324|1-LIW-3325|1-LIW-3326|1-LIW-3327|1-LIW-4232' with separator '|' thru one template named StringSplit.
I have called this StringSplit template from another template. So each split value is stored in SeparatedLineItems.
Now I want to refer each split node(SeparatedLineItems) in the calling template and want to compare each separated/split node with another variable . How can i do it.
Here is the code.
<xsl:template match="/">
<xsl:variable name="check3">
<xsl:value-of select="1-LIW-3"/>
</xsl:variable>
<myProj>
<xsl:call-template name="StringSplit">
<xsl:with-param name="val" select="$key6"/>
</xsl:call-template>
<!--here I want to compare "SeperatedLineItems" with $check3 -->
<!--<xsl:variable name="con">
<xsl:value-of select="contains($key6,$check3)"/>
</xsl:variable>-->
</myProj>
</xsl:template>
<xsl:template name="StringSplit">
<xsl:param name="val" select="$key6"/>
<!-- do a check to see if the input string (still) has a "|" in it -->
<xsl:choose>
<xsl:when test="contains($val, '|')">
<!-- pull out the value of the string before the "|" delimiter -->
<SeperatedLineItems>
<xsl:value-of select="substring-before($val, '|')"/>
</SeperatedLineItems>
<!-- recursively call this template and pass in value AFTER the "|" delimiter -->
<xsl:call-template name="StringSplit">
<xsl:with-param name="val" select="substring-after($val, '|')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- if there is no more delimiter values, print out the whole string -->
<SeperatedLineItems>
<xsl:value-of select="$val"/>
</SeperatedLineItems>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This XSLT 1.0 style-sheet demonstrates how to access the elements returned by calling a template ...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="xsl msxsl">
<xsl:output method="text"/>
<xsl:variable name="key6" select="'||1-LIW-3324|1-LIW-3325|1-LIW-3326|1-LIW-3327|1-LIW-4232'" />
<xsl:template match="/">
Does my $key6 variable contain precisely '1-LIW-3'?
<xsl:variable name="keys">
<xsl:call-template name="StringSplit">
<xsl:with-param name="val" select="$key6"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="msxsl:node-set($keys)/*[. = '1-LIW-3']">
YES
</xsl:when>
<xsl:otherwise>
NO
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="StringSplit">
<xsl:param name="val" />
<xsl:choose>
<xsl:when test="contains($val,'|')">
<SeperatedLineItems>
<xsl:value-of select="substring-before($val,'|')" />
</SeperatedLineItems>
<xsl:variable name="remainder">
<xsl:call-template name="StringSplit">
<xsl:with-param name="val" select="substring-after($val,'|')" />
</xsl:call-template>
</xsl:variable>
<xsl:copy-of select="msxsl:node-set($remainder)/*" />
</xsl:when>
<xsl:when test="$val != ''">
<SeperatedLineItems>
<xsl:value-of select="$val" />
</SeperatedLineItems>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
To which the result is...
Does my $key6 variable contain '1-LIW-3'?
NO
And here is the XSLT 2.0 equivalent...
<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="xsl xs">
<xsl:output method="text"/>
<xsl:variable name="key6" select="'||1-LIW-3324|1-LIW-3325|1-LIW-3326|1-LIW-3327|1-LIW-4232'" />
<xsl:template match="/">
Does my $key6 variable contain precisely '1-LIW-3'?
<xsl:variable name="keys" select="tokenize($key6,'\|')" as="xs:string*" />
<xsl:choose>
<xsl:when test="some $key in $keys satisfies ($key = '1-LIW-3')">
YES
</xsl:when>
<xsl:otherwise>
NO
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The above makes the $keys variable a sequence of strings rather than elements containing strings. If you prefer elements, then you could use the following alternative. Although this alternative suffers from the disadvantage that it does not include the empty string items.
<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="xsl xs">
<xsl:output method="text"/>
<xsl:variable name="key6" select="'||1-LIW-3324|1-LIW-3325|1-LIW-3326|1-LIW-3327|1-LIW-4232'" />
<xsl:template match="/">
Does my $key6 variable contain precisely '1-LIW-3'?
<xsl:variable name="keys" as="element()*" >
<xsl:analyze-string select="concat($key6,'|')" regex="([^\|]*)\|">
<xsl:matching-substring>
<SeperatedLineItems>
<xsl:value-of select="regex-group(1)" />
</SeperatedLineItems>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:choose>
<xsl:when test="$keys[. = '1-LIW-3']">
YES
</xsl:when>
<xsl:otherwise>
NO
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
There is XML document:
<data>how;many;i;can;tell;you</data>
Need to get XML using XSLT version 1:
<manydata>
<onedata>how</onedata>
<onedata>many</onedata>
<onedata>i</onedata>
<onedata>can</onedata>
<onedata>tell</onedata>
<onedata>you</onedata>
</manydata>
How I can do it?
UPDATE:
Output format must be XML.
This recursive solution is probably one of the shortest possible:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="data">
<manydata><xsl:apply-templates/></manydata>
</xsl:template>
<xsl:template match="text()" name="tokenize">
<xsl:param name="pText" select="."/>
<xsl:if test="string-length($pText)">
<onedata>
<xsl:value-of select=
"substring-before(concat($pText,';'),';')"/>
</onedata>
<xsl:call-template name="tokenize">
<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;
<data>how;many;i;can;tell;you</data>
the wanted, correct result is produced:
<manydata>
<onedata>how</onedata>
<onedata>many</onedata>
<onedata>i</onedata>
<onedata>can</onedata>
<onedata>tell</onedata>
<onedata>you</onedata>
</manydata>
<xsl:template match="data">
<manydata>
<!--
empty <manydata/> will be generated,
if <data/> without child text()
-->
<xsl:apply-templates select="text()"/>
</manydata>
</xsl:template>
<xsl:template match="data/text()">
<!-- start point for recursion -->
<xsl:call-template name="tokenize-string">
<xsl:with-param name="separator" select="';'"/>
<xsl:with-param name="string" select="text()"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="tokenize-string">
<xsl:param name="separator"/>
<xsl:param name="string"/>
<xsl:variable name="string-before-separator"
select="substring-before( $string, $separator )"/>
<onedata>
<xsl:choose>
<!-- if $separator presents in $string take first piece -->
<xsl:when test="$string-before-separator">
<xsl:value-of select="$string-before-separator"/>
</xsl:when>
<!-- take whole $string, if no $separator in the $string -->
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</onedata>
<!-- recursive call, if separator was found -->
<xsl:if test="$string-before-separator">
<xsl:call-template name="tokenize-string">
<xsl:with-param name="separator" select="$separator"/>
<xsl:with-param name="string"
select="substring-after( $string, $separator )"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Try this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="data">
<xsl:element name="manydata">
<xsl:call-template name="splitsemicolons">
<xsl:with-param name="text" select="text()" />
</xsl:call-template>
</xsl:element>
</xsl:template>
<xsl:template name="splitsemicolons">
<xsl:param name="text" />
<xsl:choose>
<xsl:when test="contains($text,';')">
<xsl:element name="onedata">
<xsl:value-of select="substring-before($text,';')" />
</xsl:element>
<xsl:call-template name="splitsemicolons">
<xsl:with-param name="text" select="substring-after($text,';')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:element name="onedata">
<xsl:value-of select="$text" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This uses a named template that is called recursively, each time outputting what's before the first ;, and calling itself with everything after the first ;. If there isn't a ;, it just outputs whatever's left as-is.
You can use the XSLT extension library to get the tokenize function. Here is how the final code will look like:
<xsl:template match="/">
<manydata>
<xsl:for-each select="str:tokenize(data, ';')">
<xsl:value-of select="." />
</xsl:for-each>
</manydata>
</xsl:template>
</xsl:stylesheet>
Please note you will have to import the extension library into you XSLT using:
<xsl:import href="path/str.xsl" />
before you use the library functions.