XSLT 1.0 to remove leading and trailing spaces - xslt

I have to remove leading and trailing spaces using XSL 1.0
cannot use normalize-space for this .
and tried the below code
<xsl:template match="text()">
<xsl:value-of select="replace(.,'^\s+|\s+$','')"/>
</xsl:template>
before commands to start the actual mapping
but does not help
how to achieve this ?

Well, in XSLT 1.0, you can use recursive template (NOT preferable) method to remove leading and trailing spaces (In case you don't want to use normalize-space())
Let's assume your input as following:
<?xml version="1.0" encoding="UTF-8"?>
<body>
<h1> A text having so many leading and trailing spaces! </h1>
</body>
Note: The below solution uses xmlns:str="xalan://org.apache.commons.lang.StringUtils" to use it's two functions ends-with and substringBeforeLast
An XSLT 1.0 solution to achieve the task:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="xalan://org.apache.commons.lang.StringUtils"
exclude-result-prefixes="str">
<xsl:output method="xml" indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="h1">
<h1>
<xsl:variable name="leadingSpaceRemoved">
<xsl:call-template name="removeLeadingSpace">
<xsl:with-param name="text" select="." />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="trailingSpaceRemoved">
<xsl:call-template name="removeTrailingSpace">
<xsl:with-param name="text" select="$leadingSpaceRemoved" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$trailingSpaceRemoved" />
</h1>
</xsl:template>
<xsl:template name="removeLeadingSpace">
<xsl:param name="text" />
<xsl:variable name="h1" select="$text" />
<xsl:choose>
<xsl:when test="starts-with($h1,' ')">
<xsl:call-template name="removeLeadingSpace">
<xsl:with-param name="text" select="substring-after($h1,' ')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$h1" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="removeTrailingSpace">
<xsl:param name="text" />
<xsl:variable name="h1" select="$text" />
<xsl:choose>
<xsl:when test="str:ends-with($h1,' ')">
<xsl:call-template name="removeTrailingSpace">
<xsl:with-param name="text" select="str:substringBeforeLast($h1,' ')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$h1" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Also, if you can call a java library/class in your environment, it will be more easier to achieve the same as below:
Your XSLT would be:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:stringparser="xalan://com.example.commons.xsl.StringUtil"
exclude-result-prefixes="stringparser">
<xsl:output method="xml" indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="h1">
<h1>
<xsl:value-of select="stringparser:trim(.)" />
</h1>
</xsl:template>
</xsl:stylesheet>
And the StringUtil.java would be:
import org.apache.commons.lang.StringUtils;
public class StringUtil {
/**
*
* #param input
* #return remove leading and trailing spaces.
*/
public static String trim(final String input) {
if (StringUtils.isNotBlank(input)) {
return input.trim();
}
return input;
}
}

One of possible solutions is to use normalize-space()
function (works even in XSLT 1.0).
It does even more, i.e. it replaces multiple white chars inside
with a single space.
To apply it to all text nodes, add such a template:
<xsl:template match="text()">
<xsl:value-of select="normalize-space()"/>
</xsl:template>
But if you have also the identity template, the above template
must be in your script after the identity template.

Related

XSLT to handle quotes and Pipe Delimited symbol

Experts, i need to write XSLT 1.0 code to remove the quotes for multiple conditions.
CASE1: Remove the double quotes
CASE2: Remove the double quotes + delete the PIPE symbol inside that double quotes (IF exist)
CASE3: Remove Single quote " from the input field.
Input:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ns0:Accounting xmlns:ns0="http://sample.com">
<Record>
<DRCR>"DR"</DRCR>
<GLREFERENCE>"TEST|CASE"</GLREFERENCE>
<GLVALUEDATE>EXAM"PLE</GLVALUEDATE>
<GLACCOUNTNUMBER>"1160</GLACCOUNTNUMBER>
<GLEXAMPLE>123</GLEXAMPLE>
<GLEXAMPLE1>EXTRACT|2021-06-16|2853|1308026.7500|1176</GLEXAMPLE1>
</Record>
</ns0:Accounting>
** Desired Output:**
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ns0:Accounting xmlns:ns0="http://sample.com">
<Record>
<DRCR>DR</DRCR>
<GLREFERENCE>TEST CASE</GLREFERENCE>
<GLVALUEDATE>EXAMPLE</GLVALUEDATE>
<GLACCOUNTNUMBER>1160</GLACCOUNTNUMBER>
<GLEXAMPLE>123</GLEXAMPLE>
<GLEXAMPLE1>EXTRACT|2021-06-16|2853|1308026.7500|1176</GLEXAMPLE1>
</Record>
</ns0:Accounting>
** XSLT I tried:**
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:call-template name="process">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="process">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '"')">
<xsl:value-of select="substring-before($text, '"')"/>
<xsl:value-of select="translate(substring-before(substring-after($text, '"'), '"'), '|', '')"/>
<xsl:call-template name="process">
<xsl:with-param name="text" select="substring-after(substring-after($text, '"'), '"')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This XSLT not handling case 3, which has single quote in the input field. Please assist here..
Maybe something like this could work for you:
XSLT 1.0 (+ EXSLT node-set function)
<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="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:choose>
<xsl:when test="contains(., '"')">
<xsl:variable name="tokens">
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="exsl:node-set($tokens)/token">
<xsl:choose>
<xsl:when test="(position()=1 or position()=last()) and last() > 1">
<xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="translate(., '|', '')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="'"'"/>
<xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
<xsl:if test="$token">
<token>
<xsl:value-of select="$token"/>
</token>
</xsl:if>
<xsl:if test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Note that this does not check the parity of the quotation marks. Any vertical bar character that is both preceded and followed by a quotation mark will be removed. For example, an input of:
<EXAMPLE>abc|123"def|456"ghi|789"jkl|012</EXAMPLE>
will be transformed to:
<EXAMPLE>abc|123def456ghi789jkl|012</EXAMPLE>

String Split to new Elements using XSL 1.0

Can any guide me to split the given xml element values into multiple child elements based on a token. Here is my sample input xml and desired output. I have a limitation to use xsl 1.0. Thank you.
Input XML:
<?xml version='1.0' encoding='UTF-8'?>
<SQLResults>
<SQLResult>
<ACTION1>Action1</ACTION1>
<ACTION2>Action2</ACTION2>
<Encrypt>Program=GPG;Code=23FCS;</Encrypt>
<SENDER>Program=WebPost;Protocol=WS;Path=/home/Inbound</SENDER>
</SQLResult>
</SQLResults>
Output XML:
<?xml version='1.0' encoding='UTF-8'?>
<SQLResults>
<SQLResult>
<ACTION1>Action1</ACTION1>
<ACTION2>Action2</ACTION2>
<Encrypt>
<Program>GPG</Program>
<Code>23FCS</Code>
</Encrypt>
<SENDER>
<Program>Action4</Program>
<Protocol>WS</Protocol>
<Path>/home/Inbound</Path>
</SENDER>
</SQLResult>
</SQLResults>
In XSLT 2 it would be easy, just with the following template:
<xsl:template match="Encrypt|SENDER">
<xsl:copy>
<xsl:analyze-string select="." regex="(\w+)=([\w/]+);?">
<xsl:matching-substring>
<element name="{regex-group(1)}">
<xsl:value-of select="regex-group(2)"/>
</element>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
Because you want to do it in XSLT 1, you have to express it another way.
Instead of analyze-string you have to:
Tokenize the content into non-empty tokens contained between ; chars.
You have to add tokenize template.
Each such token divide into 2 substrings, before and after = char.
Create an element with the name equal to the first substring.
Write the content of this element - the second substring.
XSLT 1 has also such limitation that the result of the tokenize template
is a result tree fragment (RTF) not the node set and thus it cannot be
used in XPath expressions.
To circumvent this limitation, you must use exsl:node-set function.
So the whole script looks like below:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="Encrypt|SENDER">
<xsl:copy>
<xsl:variable name="tokens">
<xsl:call-template name="tokenize">
<xsl:with-param name="txt" select="."/>
<xsl:with-param name="delim" select="';'"/>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="exsl:node-set($tokens)/token">
<xsl:variable name="t1" select="substring-before(., '=')"/>
<xsl:variable name="t2" select="substring-after(., '=')"/>
<xsl:element name="{$t1}">
<xsl:value-of select="$t2" />
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="txt" />
<xsl:param name="delim" select="' '" />
<xsl:choose>
<xsl:when test="$delim and contains($txt, $delim)">
<token>
<xsl:value-of select="substring-before($txt, $delim)" />
</token>
<xsl:call-template name="tokenize">
<xsl:with-param name="txt" select="substring-after($txt, $delim)" />
<xsl:with-param name="delim" select="$delim" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$txt">
<token><xsl:value-of select="$txt" /></token>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
</xsl:transform>

XSL to capture URL Params

Not able to extract the params using XSLT,
for eg.: http://www.example.com/AB/100/123456/09/8
using XSLT need to extract like var1=AB, Var2=100, Var3=123456, var4=09, var5=8, All the params are mandatory. and var3 can accept 1-999999, could somebody share some ideas
tried Substring but it didn't help much
Though the input is not clear, just as example: given an input XML
<root>
<url>http://www.example.com/AB/100/123456/09/8</url>
</root>
following XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="url">
<xsl:call-template name="parse">
<xsl:with-param name="url" select="substring-after(.,'//')" />
<xsl:with-param name="position" select="1" />
</xsl:call-template>
</xsl:template>
<xsl:template name="parse">
<xsl:param name="url" />
<xsl:param name="position" />
<xsl:choose>
<xsl:when test="contains(substring-after($url, '/'),'/')">
<xsl:value-of select="concat('Var', $position, ': ')" />
<xsl:value-of select="substring-before(substring-after($url, '/'),'/')" />
<xsl:text>, </xsl:text>
<xsl:call-template name="parse">
<xsl:with-param name="url" select="substring-after($url, '/')" />
<xsl:with-param name="position" select="$position + 1" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('Var', $position, ': ')" />
<xsl:value-of select="substring-after($url,'/')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:transform>
produces the ouput
Var1: AB, Var2: 100, Var3: 123456, Var4: 09, Var5: 8
using the template parse which recursively calls itself when the url contains a /.
For every call the parameter url is reduced using substring-after() and the parameter position is incremented.

Selecting a last word from a string in xslt

I just want to take the last element from a string which is like this "aaa-bbb-ccc-ddd" in xslt.
Out put should be "ddd" irrecspective of '-'s.
XSLT/Xpath 2.0 - using the tokenize() function to split the string on the "-" and then use a predicate filter to select the last item in the sequence:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="tokenize('aaa-bbb-ccc-ddd','-')[last()]"/>
</xsl:template>
</xsl:stylesheet>
XSLT/XPath 1.0 - using a recursive template to look for the last occurrence of "-" and selecting the substring following it:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:call-template name="substring-after-last">
<xsl:with-param name="input" select="'aaa-bbb-ccc-ddd'" />
<xsl:with-param name="marker" select="'-'" />
</xsl:call-template>
</xsl:template>
<xsl:template name="substring-after-last">
<xsl:param name="input" />
<xsl:param name="marker" />
<xsl:choose>
<xsl:when test="contains($input,$marker)">
<xsl:call-template name="substring-after-last">
<xsl:with-param name="input"
select="substring-after($input,$marker)" />
<xsl:with-param name="marker" select="$marker" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$input" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

Use xslt replace function to replace a word with an element

I want to usw the XSLT replace function to replace words in a text with
<strong>word</strong>.
I wrote the following template:
<xsl:template name="make-bold">
<xsl:param name="text"/>
<xsl:param name="word"/>
<xsl:variable name="replacement">
<strong><xsl:value-of select="$word"/></strong>
</xsl:variable>
<xsl:value-of select="replace($text, $word, $replacement )" />
</xsl:template>
Unfortunately, and are not rendered, althoug the rest works.
Could anyone help me?
Best, Suidu
Well the replace function http://www.w3.org/TR/xpath-functions/#func-replace takes a string and returns a string. You seem to want to create an element node, not a simple string. In that case using analyze-string http://www.w3.org/TR/xslt20/#analyze-string instead of replace could help.
Here is a sample XSLT 2.0 stylesheet:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="html" indent="no"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#*, node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="text()" mode="wrap">
<xsl:with-param name="words" as="xs:string+" select="('foo', 'bar')"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" mode="wrap">
<xsl:param name="words" as="xs:string+"/>
<xsl:param name="wrapper-name" as="xs:string" select="'strong'"/>
<xsl:analyze-string select="." regex="{string-join($words, '|')}">
<xsl:matching-substring>
<xsl:element name="{$wrapper-name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
When you run that with an XSLT 2.0 processor like Saxon 9 against the following input sample
<html>
<body>
<p>This is an example with foo and bar words.</p>
</body>
</html>
the output is as follows:
<html>
<body>
<p>This is an example with <strong>foo</strong> and <strong>bar</strong> words.</p>
</body>
</html>
hmm is is because here it its the string value that is replaced, you might try to use the node set?
i cannot test as i dont use xslt 2.0 but you might try a recursive template ie
<xsl:template match="yourtextelement">
<xsl:call-template name="MaketextStrong">
</xsl:template>
<xsl:template name="MaketextStrong">
<xsl:param name="text" select="."/>
<xsl:choose>
<xsl:when test="contains($text, 'texttomakestrong')">
<xsl:value-of select="substring-before($text, 'texttomakestrong')"/>
<strong>texttomakestrong</strong>
<xsl:call-template name="break">
<xsl:with-param name="text" select="substring-after($text,
'texttomakestrong')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>