how to fetch last line data from this xml by using xslt - xslt

trying to get last from the tag if data of last line is equal to personal means then need to populate as 1100 else what ever data presented that it should to be populated
here is my below xml:
<tag>
<name>20K</name>
<value>540211000000100155001
0100155XXXXXX
0100156XXXXX
0100157XXXXXXX
0100159XXXXXXXX
personal</value>
</tag>
how to use a logic in xslt can any one guide me

I. Here is a short and simple way to do this in XSLT 2.0:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/*/value">
"<xsl:sequence select="tokenize(., '(
)?
')[last()]"/>"
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
When this transformation is applied to the provided XML document:
<tag>
<name>20K</name>
<value>540211000000100155001
0100155XXXXXX
0100156XXXXX
0100157XXXXXXX
0100159XXXXXXXX
personal</value>
</tag>
the wanted, correct result is produced:
" personal"
II. XSLT 1.0 solution
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="value" name="skipLines">
<xsl:param name="pText" select="."/>
<xsl:choose>
<xsl:when test="not(contains($pText, '
'))">
"<xsl:value-of select="$pText"/>"
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="skipLines">
<xsl:with-param name="pText" select=
"substring-after($pText, '
')"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when this transformation is applied to the same XML document (above), again the same correct result is produced:
" personal"

<xsl:for-each select="//tag">
<xsl:if test="contains(value/text(),"personal")">
do stuff ...
</xsl:if>
</xsl:for-each>
just for inspiration :)

Related

Split the values of a Tag using xslt

Source:
<Data>
<value>M1,M2,M3,M4,M5,M6</value>
</Data>
Need to Display them as
Output:
<ABCD>
<value1>M1</value1>
<value2>M2</value2>
<value3>M3</value3>
<value4>M4</value4>
<value5>M5</value5>
<value6>M6</value6>
</ABCD>
XSLT:
I actually want to split the value based on "," and place them in different variables.
Using str-split(), Can I load it in different variables.
This XSLT 1.0 transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<ABCD>
<xsl:apply-templates/>
</ABCD>
</xsl:template>
<xsl:template match="value/text()" name="split">
<xsl:param name="pText" select="."/>
<xsl:param name="pOrd" select="1"/>
<xsl:if test="$pText">
<xsl:element name="value{$pOrd}">
<xsl:value-of select=
"substring-before(concat($pText, ','), ',')"/>
</xsl:element>
<xsl:call-template name="split">
<xsl:with-param name="pText" select="substring-after($pText, ',')"/>
<xsl:with-param name="pOrd" select="$pOrd+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<Data>
<value>M1,M2,M3,M4,M5,M6</value>
</Data>
produces the wanted, correct result:
<ABCD>
<value1>M1</value1>
<value2>M2</value2>
<value3>M3</value3>
<value4>M4</value4>
<value5>M5</value5>
<value6>M6</value6>
</ABCD>
Explanation:
Recursive named template, with stop-condition when the passed text-parameter becomes the empty string.
Proper use of xsl:element and AVT.
Proper use of the standard XPath functions substring-before() and substring-after
Proper use of a sentinel to simplify the code and make it more efficient.
If you have access to EXSLT you can use str:split().
<xsl:apply-templates select='str:split(/Data/value, ",")' />
Runnable example here

how to get required name from a string in xslt?

e.g i have following strings:
xoc.coe.hw.ZSBALAJI
hw.cor.exp.nt.ZSSHIVA
i have to get only last string (i.e. ZSBALAJI from first and ZSSHIVA from second). How can I do it in xslt.
Thanks in advance.
Here is an XSLT-1.0 solution to your problem:
<?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="//string">
<xsl:call-template name="skipper">
<xsl:with-param name="source" select="."/>
<xsl:with-param name="delimiter" select="'.'"/>
</xsl:call-template>
</xsl:template>
<!-- returns the substring after the last delimiter -->
<xsl:template name="skipper">
<xsl:param name="source"/>
<xsl:param name="delimiter"/>
<xsl:choose>
<xsl:when test="contains($source,$delimiter)">
<xsl:call-template name="skipper">
<xsl:with-param name="source" select="substring-after($source,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$source"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When applied to this document:
<?xml version="1.0" encoding="UTF-8"?>
<strings>
<string>xoc.coe.hw.ZSBALAJI</string>
<string>hw.cor.exp.nt.ZSSHIVA</string>
</strings>
It produces the following result:
ZSBALAJI
ZSSHIVA
Let's assume that you have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<a>xoc.coe.hw.ZSBALAJI</a>
<a>hw.cor.exp.nt.ZSSHIVA</a>
</root>
Then the following XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:template match="//a">
<xsl:variable name="parts" select="tokenize(node(), '\.')"/>
<xsl:variable name="count" select="count($parts)"/>
<xsl:for-each select="$parts">
<xsl:if test="position() = $count">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
will ouput
ZSBALAJI
ZSSHIVA
Essentially, you can use XPath tokenize function and then take the last token.
You can try and use EXSLT tokenize(string, string?) function to split by '.' on the relevant node, see this for additional info.

How can I achieve SPLIT function in XSLT 1.0

I have a following scenario. I have a TEAM-MEMBERS node which has name in the format last name, first name
<TEAM-MEMBER><LONG-NAME>Last Name, First Name</LONG-NAME></TEAM-MEMBER>
I want to transform this to
<CONTACT><FIRSTNAME>First Name</FIRSTNAME><LASTNAME>Last Name</LASTNAME></CONTACT>
Basically i want to split the <LONG-NAME> node's value by ,
How can I achieve this using XSLT 1.0
This XSLT will be consumed by BizTalk Server hence i am looking for some XSLT 1.0 solutions only
Thanks
Karthik
Here is a complete XSLT 1.0 solution that uses a general "split" template that splits a string into multiple substrings, provided a delimiter to designate the boundary between substrings:
<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="TEAM-MEMBER">
<xsl:variable name="vrtfSplitWords">
<xsl:call-template name="split">
<xsl:with-param name="pText" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="vSplitWords"
select="ext:node-set($vrtfSplitWords)/*"/>
<CONTACT>
<FIRSTNAME><xsl:value-of select="$vSplitWords[2]"/></FIRSTNAME>
<LASTNAME><xsl:value-of select="$vSplitWords[1]"/></LASTNAME>
</CONTACT>
</xsl:template>
<xsl:template name="split">
<xsl:param name="pText" select="."/>
<xsl:param name="pDelim" select="', '"/>
<xsl:param name="pElemName" select="'word'"/>
<xsl:if test="string-length($pText)">
<xsl:element name="{$pElemName}">
<xsl:value-of select=
"substring-before(concat($pText,$pDelim),
$pDelim
)
"/>
</xsl:element>
<xsl:call-template name="split">
<xsl:with-param name="pText" select=
"substring-after($pText,$pDelim)"/>
<xsl:with-param name="pDelim" select="$pDelim"/>
<xsl:with-param name="pElemName" select="$pElemName"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<TEAM-MEMBER><LONG-NAME>Last Name, First Name</LONG-NAME></TEAM-MEMBER>
the wanted, correct result is produced:
<CONTACT>
<FIRSTNAME>First Name</FIRSTNAME>
<LASTNAME>Last Name</LASTNAME>
</CONTACT>
II. Solution using FXSL
This transformation uses the str-split-to-words template from FXSL:
<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:import href="strSplit-to-Words.xsl"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:param name="pmaxLines" select="10"/>
<xsl:template match="/">
<xsl:variable name="vwordNodes">
<xsl:call-template name="str-split-to-words">
<xsl:with-param name="pStr" select="/"/>
<xsl:with-param name="pDelimiters"
select="',()'"/>
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select=
"ext:node-set($vwordNodes)/*[normalize-space()]"/>
</xsl:template>
<xsl:template match="word[normalize-space()][1]">
<FIRSTNAME>
<xsl:value-of select="normalize-space()"/>
</FIRSTNAME>
</xsl:template>
<xsl:template match="word[normalize-space()][2]">
<MIDNAME>
<xsl:value-of select="normalize-space()"/>
</MIDNAME>
</xsl:template>
<xsl:template match="word[normalize-space()][last()]">
<LASTNAME>
<xsl:value-of select="normalize-space(.)"/>
</LASTNAME>
</xsl:template>
</xsl:stylesheet>
when applied to this XML document (made quite more complex):
<TEAM-MEMBER><LONG-NAME>First Name, (Jr.), Last Name</LONG-NAME></TEAM-MEMBER>
the wanted, correct result is produced:
<FIRSTNAME>First Name</FIRSTNAME>
<MIDNAME>Jr.</MIDNAME>
<LASTNAME>Last Name</LASTNAME>
Do Note:
The str-split-to-words template accepts multiple delimiters. Thus in this transformation the delimiters used are: ',', '(' and ')'
You need a recursive named template. Fortunately it's already been written: look for str:tokenize at http://www.exslt.org.
used substring-after() and substring-before() to get around the split

XSLT find word near another word

How can i find, with XSLT, the word before and after another know word in a text node?
I. In XSLT 2.x / XPath 2.x one can use the functions tokenize() and index-of() to produce the desired results with one-liner XPath expressions:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="pWord" select="'three'"/>
<xsl:template match="text()">
<xsl:sequence select=
"tokenize(., ',\s*')
[index-of(tokenize(current(), ',\s*'), $pWord) -1]"/>
<xsl:sequence select=
"tokenize(., ',\s*')
[index-of(tokenize(current(), ',\s*'), $pWord) +1]"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>One, two, three, four</t>
the wanted, correct result is produced:
two four
II. XSLT 1.0 solution
It is possible to solve the same task in XSLT 1.0 using the strSplit-to-Words template of FXSL.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
>
<xsl:import href="strSplit-to-Words.xsl"/>
<xsl:output method="text"/>
<xsl:param name="pWord" select="'three'"/>
<xsl:template match="/">
<xsl:variable name="vrtfwordNodes">
<xsl:call-template name="str-split-to-words">
<xsl:with-param name="pStr" select="/"/>
<xsl:with-param name="pDelimiters"
select="',
'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="vwordNodes"
select="ext:node-set($vrtfwordNodes)/*"/>
<xsl:variable name="vserchWordPos" select=
"count($vwordNodes
[. = $pWord]/preceding-sibling::*
) +1"/>
<xsl:value-of select=
"concat($vwordNodes[$vserchWordPos -1],
' ',
$vwordNodes[$vserchWordPos +1]
)
"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the same XML document:
<t>One, two, three, four</t>
the wanted, correct result is produced:
two four

XSLT: How to reverse output without sorting by content

I have a list of items:
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
and I want as output
z
c
x
a
I have no order information in the file and I just want to reverse the lines. The last line in the source file should be first line in the output. How can I solve this problem with XSLT without sorting by the content of the items, which would give the wrong result?
I will present two XSLT solutions:
I. XSLT 1.0 with recursion Note that this solution works for any node-set, not only in the case when the nodes are siblings:
This transformation:
<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="/*">
<xsl:call-template name="reverse">
<xsl:with-param name="pList" select="*"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="reverse">
<xsl:param name="pList"/>
<xsl:if test="$pList">
<xsl:value-of
select="concat($pList[last()], '
')"/>
<xsl:call-template name="reverse">
<xsl:with-param name="pList"
select="$pList[not(position() = last())]"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<t>
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
</t>
produces the wanted result:
z
c
x
a
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">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:value-of select="reverse(*)/string(.)"
separator="
"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the same XML document, the same correct result is produced.
XML CODE:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<device>
<element>a</element>
<element>x</element>
<element>c</element>
<element>z</element>
</device>
XSLT CODE:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//device">
<xsl:for-each select="element">
<xsl:sort select="position()" data-type="number" order="descending"/>
<xsl:text> </xsl:text>
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
note: if you're using data-type="number", and any of the values aren't numbers, those non-numeric values will sort before the numeric values. That means if you're using order="ascending", the non-numeric values appear first; if you use order="descending", the non-numeric values appear last.
Notice that the non-numeric values were not sorted; they simply appear in the output document in the order in which they were encountered.
also, you may find usefull to read this:
http://docstore.mik.ua/orelly/xml/xslt/ch06_01.htm
Not sure what the full XML looks like, so I wrapped in a <doc> element to make it well formed:
<doc>
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
</doc>
Running that example XML against this stylesheet:
<?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" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:call-template name="reverse">
<xsl:with-param name="item" select="doc/item[position()=last()]" />
</xsl:call-template>
</xsl:template>
<xsl:template name="reverse">
<xsl:param name="item" />
<xsl:value-of select="$item" />
<!--Adds a line feed-->
<xsl:text>
</xsl:text>
<!--Move on to the next item, if we aren't at the first-->
<xsl:if test="$item/preceding-sibling::item">
<xsl:call-template name="reverse">
<xsl:with-param name="item" select="$item/preceding-sibling::item[1]" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Produces the requested output:
z
c
x
a
You may need to adjust the xpath to match your actual XML.
Consider this XML input:
<?xml version="1.0" encoding="utf-8" ?>
<items>
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
</items>
The XSLT:
<?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="/items[1]">
<xsl:variable name="items-list" select="." />
<xsl:variable name="items-count" select="count($items-list/*)" />
<xsl:for-each select="item">
<xsl:variable name="index" select="$items-count+1 - position()"/>
<xsl:value-of select="$items-list/item[$index]"/>
<xsl:value-of select="'
'"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
And the result:
z
c
x
a