call xslt template with parameter - xslt

I have this xslt:
<xsl:template name="dumpDebugData">
<xsl:param name="elementToDump" />
<xsl:for-each select="$elementToDump/#*">
<xsl:text>
</xsl:text> <!-- newline char -->
<xsl:value-of select="name()" /> : <xsl:value-of select="." />
</xsl:for-each>
</xsl:template>
i want to display every element (as in name/value), how do i call this template?

Since the template expects a node set, you must do:
<xsl:call-template name="dumpDebugData">
<xsl:with-param name="elementToDump" select="some/xpath" />
</xsl:call-template>

Try something like this:
<xsl:call-template name="dumpDebugData">
<xsl:with-param name="elementToDump">foo</xsl:with-param>
</xsl:call-template>

The original answer does not use the parameter. It only works if the paramater = the current element. This takes the parameter into account.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="element()">
<xsl:call-template name="dumpDebugData">
<xsl:with-param name="elementToDump" select="." />
</xsl:call-template>
<xsl:apply-templates />
</xsl:template>
<xsl:template name="dumpDebugData">
<xsl:param name="elementToDump" />
Node:
<xsl:value-of select="name($elementToDump)" />
:
<xsl:value-of select="text($elementToDump)" />
<xsl:for-each select="$elementToDump/#*">
Attribute:
<xsl:value-of select="name()" />
:
<xsl:value-of select="." />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

There are a number of issues in your original XSLT, so I worked through it and got you the following code which does what you want I believe:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="element()">
<xsl:call-template name="dumpDebugData">
<xsl:with-param name="elementToDump" select="." />
</xsl:call-template>
<xsl:apply-templates />
</xsl:template>
<xsl:template name="dumpDebugData">
<xsl:param name="elementToDump" />
Node:
<xsl:value-of select="name()" />
:
<xsl:value-of select="text()" />
<xsl:for-each select="attribute::*">
Attribute:
<xsl:value-of select="name()" />
:
<xsl:value-of select="." />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Related

XSLT 1.0 to remove leading and trailing spaces

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.

XSLT Transform to XML

I have some xml in the following format:
<top>
<topValue Value="1#1#5" />
<topValue Value="2#2#10" />
<topValue Value="1#1#3" />
<topValue Value="2#2#30" />
</top>
and output should look like that:
<boo>
<booEnrty>
<v>5</v>
<v>10</v>
</booEnrty>
<booEnrty>
<v>3</v>
<v>30</v>
</booEnrty>
</boo>
my XSLT to transform
<boo>
<xsl:for-each select="top/topValue">
<xsl:if test="position() mod 2 = 0">
<booEnrty>
<v><xsl:value-of select="substring-after(substring-after(#Value,'#'),'#')"/></v>
</booEnrty>
</xsl:if>
</xsl:for-each>
</boo>
What should the XSLT document look like to do this transform?
Any ideas?
Thanks
Maybe someone got a better approach to this, but the XSLT below works for your case.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="top">
<boo>
<xsl:apply-templates select="topValue[position() mod 2 = 1]"/>
</boo>
</xsl:template>
<xsl:template match="topValue[position() mod 2 = 1]">
<booEntry>
<v>
<xsl:call-template name="substring-after-last">
<xsl:with-param name="string" select="#Value" />
<xsl:with-param name="delimiter" select="'#'" />
</xsl:call-template>
</v>
<xsl:apply-templates select="following-sibling::*[1]"/>
</booEntry>
</xsl:template>
<xsl:template match="topValue">
<v>
<xsl:call-template name="substring-after-last">
<xsl:with-param name="string" select="#Value" />
<xsl:with-param name="delimiter" select="'#'" />
</xsl:call-template>
</v>
</xsl:template>
<xsl:template name="substring-after-last">
<xsl:param name="string" />
<xsl:param name="delimiter" />
<xsl:choose>
<xsl:when test="contains($string, $delimiter)">
<xsl:call-template name="substring-after-last">
<xsl:with-param name="string"
select="substring-after($string, $delimiter)" />
<xsl:with-param name="delimiter" select="$delimiter" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$string"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
How about something short and simple?
XSLT 1.0
<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:template match="/top">
<boo>
<xsl:for-each select="topValue[position() mod 2 = 1]">
<booEnrty>
<xsl:for-each select=". | following-sibling::topValue[1]">
<v>
<xsl:value-of select="substring-after(substring-after(#Value,'#'),'#')"/>
</v>
</xsl:for-each>
</booEnrty>
</xsl:for-each>
</boo>
</xsl:template>
</xsl:stylesheet>

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.

print xpath and value of element and attribute using XSLT

I would like to print path of element and attributes if any along with values using XSLT. e.g
XML :
<root>
<node attr='abc' module='try'>
<subnode>Roshan</subnode>
<subnode>Chetan</subnode>
<subnode>Jennifer</subnode>
</node>
</root>
Output :
/root##
/root/node##
/root/node/#attr##abc
/root/node/#module##try
/root/node/subnode[1]##Roshan
/root/node/subnode[2]##Chetan
/root/node/subnode[3]##Jennifer
I am trying with below snippet, but could only print path of element and it's value
<xsl:template match="*">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="concat('/',local-name())" />
<xsl:if
test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
<xsl:value-of
select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')" />
</xsl:if>
<!-- <xsl:call-template name="attrData"></xsl:call-template> -->
</xsl:for-each>
<xsl:text>##</xsl:text>
<xsl:apply-templates select="node()" />
</xsl:template>
I am new to XSLT. Please help!!!!
I made the following XSLT and added also the [position] to the output. You can remove that if you need.
This gives this output:
/root[1]
/root[1]/node[1]
/root[1]/node[1]/#attr[1]##abc
/root[1]/node[1]/#module[1]##try
/root[1]/node[1]/subnode[1]##Roshan
/root[1]/node[1]/subnode[2]##Chetan
/root[1]/node[1]/subnode[3]##Jennifer
With this XSLT. With the two output template you can choose how to print the Xpath.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="" version="2.0">
<xsl:output method="text" encoding="utf-8" />
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
<xsl:call-template name="generateXPath">
<xsl:with-param name="previous" select="''"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="generateXPath">
<xsl:param name="previous" as="xs:string"/>
<xsl:variable name="this" select="." as="node()"/>
<xsl:if test="not(empty(.))">
<xsl:variable name="thisXPath" select="concat($previous, '/', name(.),'[', count(preceding-sibling::*[name() = name($this)])+1,']')"></xsl:variable>
<xsl:apply-templates select="." mode="output">
<xsl:with-param name="previous" select="$previous"/>
</xsl:apply-templates>
<xsl:text>
</xsl:text>
<xsl:for-each select="*|#*">
<xsl:call-template name="generateXPath">
<xsl:with-param name="previous" select="$thisXPath"/>
</xsl:call-template>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="output">
<xsl:param name="previous" as="xs:string"/>
<xsl:variable name="this" select="." as="node()"/>
<xsl:variable name="thisXPath">
<xsl:value-of select="concat($previous, '/', name(.),'[', count(preceding-sibling::*[name() = name($this)])+1,']')"></xsl:value-of>
<xsl:if test="not(*)">
<xsl:value-of select="concat('##',text())"></xsl:value-of>
</xsl:if>
</xsl:variable>
<xsl:value-of select="$thisXPath" />
</xsl:template>
<xsl:template match="#*" mode="output">
<xsl:param name="previous" as="xs:string"/>
<xsl:variable name="this" select="." as="node()"/>
<xsl:variable name="thisXPath" select="concat($previous, '/#', name(.),'[', count(preceding-sibling::*[name() = name($this)])+1,']','##',.)"></xsl:variable>
<xsl:value-of select="$thisXPath" />
</xsl:template>
</xsl:stylesheet>

Counters in XSLT

how to implement counter type functionality in xslt
XSLT is based upon Functional programming hence you can not use counters you can try Recursions if it can be of your help
You can use recursion to simulate counter functionality, but you have not specified any input or output format, so providing some general code.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<!-- TODO: Auto-generated template -->
<xsl:call-template name="counter">
<xsl:with-param name="start" select="1" />
<xsl:with-param name="stop" select="10" />
<xsl:with-param name="increment" select="1" />
</xsl:call-template>
</xsl:template>
<xsl:template name="counter">
<xsl:param name="start" />
<xsl:param name="stop" />
<xsl:param name="increment" />
Value:<xsl:value-of select="$increment"/>
<xsl:if test="$increment < $stop">
<xsl:call-template name="counter">
<xsl:with-param name="start" select="$start" />
<xsl:with-param name="stop" select="$stop" />
<xsl:with-param name="increment" select="$increment+1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>