Counters in XSLT - 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>

Related

XSLT to transform given query with given parms

Here is the given XML-
<INPUT>
<pSql>select * from cntwrk where moddte>= :from_date and ins_dt < :to_date</parameterizedSql>
<arguments>
<dataType>DATETIME</dataType>
<values>2019-07-24T00:00:01</values>
<key>from_date</key>
</arguments>
<arguments>
<dataType>DATETIME</dataType>
<values>2019-09-23T00:00:01</values>
<key>to_date</key>
</arguments>
</INPUT>
I need to build a xslt to have the final query has
select * from cntwrk where moddte>= (to_date('2019-07-24 00:00:01','yyyy-MM-dd HH24:mi:ss')) and
ins_dt < (to_date('2019-09-23 00:00:01','yyyy-MM-dd HH24:mi:ss'))
output.
That is replace the :from_date with arguments/values after some concatenation.
Please find the XSLT that i tried, but could not get the desired output with using variables.
<?xml version="1.0"?>
<xsl:transform exclude-result-prefixes="xsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" indent="yes" />
<xsl:variable name="q_var" select="INPUT/parameterizedSql" />
<xsl:param name="find_var" select="concat(':',INPUT/arguments/key)" />
<xsl:param name="re_var" select="INPUT/arguments/values" />
<xsl:template match="INPUT">
<xsl:apply-templates select="arguments[dataType[text() = 'DATETIME']]" />
</xsl:template>
<xsl:template match="INPUT">
<xsl:for-each select="//arguments">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$q_var" />
<xsl:with-param name="replace" select="$find_var" />
<xsl:with-param name="with" select="$re_var" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="with" />
<xsl:choose>
<xsl:when test="contains($text,$replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$with" />
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="with" select="$with" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:transform>
The first thing to learn here is that xsl:for-each is not a loop. Each node in the selected node-set is processed individually. You cannot pass the result of one instance to another.
There are two possible ways to process the given string sequentially: one is a technique called sibling recursion, and the other is a through a named recursive template. The following example will demonstrate the 2nd method.
For simplicity, I will assume that each argument appears in the given string exactly once. If this assumption is not true, then you will need to call another recursive template to perform the actual replacement of the currently processed argument in the given string when calling the next iteration.
XML (corrected)
<INPUT>
<parameterizedSql>select * from cntwrk where moddte>= :from_date and ins_dt < :to_date</parameterizedSql>
<arguments>
<dataType>DATETIME</dataType>
<values>2019-07-24T00:00:01</values>
<key>from_date</key>
</arguments>
<arguments>
<dataType>DATETIME</dataType>
<values>2019-09-23T00:00:01</values>
<key>to_date</key>
</arguments>
</INPUT>
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="/INPUT">
<OUTPUT>
<xsl:call-template name="insert-arguments">
<xsl:with-param name="string" select="parameterizedSql"/>
<xsl:with-param name="arguments" select="arguments"/>
</xsl:call-template>
</OUTPUT>
</xsl:template>
<xsl:template name="insert-arguments">
<xsl:param name="string"/>
<xsl:param name="arguments"/>
<xsl:choose>
<xsl:when test="$arguments">
<!-- recursive call -->
<xsl:call-template name="insert-arguments">
<xsl:with-param name="string">
<!-- insert current argument -->
<xsl:variable name="argument" select="$arguments[1]" />
<xsl:variable name="search-string" select="concat(':', $argument/key)" />
<xsl:value-of select="substring-before($string, $search-string)"/>
<xsl:value-of select="$argument/values"/>
<xsl:value-of select="substring-after($string, $search-string)"/>
</xsl:with-param>
<xsl:with-param name="arguments" select="$arguments[position() > 1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<OUTPUT>select * from cntwrk where moddte>= 2019-07-24T00:00:01 and ins_dt < 2019-09-23T00:00:01</OUTPUT>
I don't see in your question the logic by which the inserted value needs to be wrapped in todate()so I skipped that part.

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.

How to remove particular characters from a string using XSLT?

I need to check if a particular string contains a a particular word for example to check if,
SultansOfSwing contains the word Swing.
Let me also mention that the value of the string in question is unknown. As in it can be any word so we do not know the length et cetera.
I understand I can do this by using the contains keyword.
But once I know that this word contains the Swing keyword I want to display the string without this "Swing" word.. thus effectively displaying only "SultansOf".
I have been trying to explore how I can achieve this but not getting any break through.
Could somebody please advise which keyword or function will provide this facility ? How can I remove a particular word from within a string.
Given this for input:
<root>
<song>SultansOfSwing</song>
<song>SwingOfSultans</song>
<song>SultansSwingOf</song>
</root>
The output of this:
<?xml version='1.0' ?>
<root>
<swing-less-long>SultansOf</swing-less-long>
<swing-less-long>OfSultans</swing-less-long>
<swing-less-long>SultansOf</swing-less-long>
</root>
Can be gotten from this. Note the use of substring-before and substring-after.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/">
<root>
<xsl:apply-templates select="root/song"/>
</root>
</xsl:template>
<xsl:template match="song">
<swing-less-long>
<xsl:if test="contains(., 'Swing')">
<xsl:call-template name="remove">
<xsl:with-param name="value" select="."/>
</xsl:call-template>
</xsl:if>
</swing-less-long>
</xsl:template>
<xsl:template name="remove">
<xsl:param name="value"/>
<xsl:value-of select="concat(substring-before($value, 'Swing'), substring-after($value, 'Swing'))"/>
</xsl:template>
</xsl:stylesheet>
I think this string replacement function is quite exhaustive:
EDIT - needed to change $string to $string2. Should work now
<xsl:template name="string-replace">
<xsl:param name="string1" select="''" />
<xsl:param name="string2" select="''" />
<xsl:param name="replacement" select="''" />
<xsl:param name="global" select="true()" />
<xsl:choose>
<xsl:when test="contains($string1, $string2)">
<xsl:value-of select="substring-before($string1, $string2)" />
<xsl:value-of select="$replacement" />
<xsl:variable name="rest" select="substring-after($string1, $string2)" />
<xsl:choose>
<xsl:when test="$global">
<xsl:call-template name="string-replace">
<xsl:with-param name="string1" select="$rest" />
<xsl:with-param name="string2" select="$string2" />
<xsl:with-param name="replacement" select="$replacement" />
<xsl:with-param name="global" select="$global" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$rest" />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string1" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
It's case-sensitive, mind you. In your case:
<xsl:call-template name="string-replace">
<xsl:with-param name="string1" select="'SultansOfSwing'" />
<xsl:with-param name="string2" select="'Swing'" />
<xsl:with-param name="replacement" select="''" />
</xsl:call-template>

call xslt template with parameter

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>