how to process number ranges in xslt2.0 - xslt

My XML.
<a>
<range nr="1" no-range="1 2 3 4" oc="4"/>
<range nr="2" no-range="41 42 43 44" oc="4"/>
<range nr="3" no-range="43 44 45 46" oc="4"/>
<range nr="4" no-range="50 51 52 53" oc="4"/>
<range nr="5" no-range="53 54" oc="2"/>
<range nr="6" no-range="60 61" oc="2"/>
</a>
I was trying this but not sure how to compare two arrays and print the difference:
<?xml version="1.0" encoding="UTF-8"?>
<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:template match="a">
<xsl:variable name="bRannge">
<xsl:for-each select="range">
<xsl:variable name="aRange" select="tokenize(concat(#no-range, ' '), ' ')"/>
<xsl:value-of select="$aRange"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="cRange" select="tokenize(normalize-space($bRannge), ' ')"/>
<xsl:variable name="aSeq">
<xsl:for-each select="1 to xs:integer(number($cRange[last()]))">
<xsl:value-of select="position()"/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="bSeq" select="tokenize(normalize-space($aSeq), ' ')"/>
[<xsl:value-of select="$cRange"/>]
[<xsl:value-of select="$bSeq"/>]
<!-- How to compare two arrays -->
</xsl:template>
How can I get following report using xslt 2.0:
Number ranges not in use 5-40, 47-49, 55-59
'nr 3' is overlapping with 'nr 2' overlapping number = 43, 44
'nr 5' is overlapping with 'nr 4' overlapping number = 53

You can create each sequence you have with a single expression and then compare them as follows:
<xsl:template match="a">
<xsl:variable name="seq1" as="xs:integer*"
select="for $s in range/#no-range/tokenize(., '\s+')
return xs:integer($s)"/>
<xsl:variable name="seq2" as="xs:integer*"
select="1 to $seq1[last()]"/>
[<xsl:value-of select="$seq1"/>]
[<xsl:value-of select="$seq2"/>]
[<xsl:value-of select="$seq2[not(. = $seq1)]"/>]
</xsl:template>
That outputs the sequence of integers not in your no-range attribute values:
[5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 47 48 49 55 56 57 58 59]
As for finding consecutive ranges, one way would be to use grouping as follows:
<xsl:template match="a">
<xsl:variable name="seq1" as="xs:integer*"
select="for $s in range/#no-range/tokenize(., '\s+')
return xs:integer($s)"/>
<xsl:variable name="seq2" as="xs:integer*"
select="1 to $seq1[last()]"/>
[<xsl:value-of select="$seq1"/>]
[<xsl:value-of select="$seq2"/>]
<xsl:variable name="seq3" as="xs:integer*"
select="$seq2[not(. = $seq1)]"/>
[<xsl:value-of select="$seq3"/>]
<xsl:for-each-group select="$seq3" group-adjacent=". - position()">
[<xsl:value-of select="current-group()[1], current-group()[last()]"
separator=" - "/>]
</xsl:for-each-group>
which then gives
[5 - 40]
[47 - 49]
[55 - 59]

Related

XSLT sort Arabic letters

I have XML like:
<Answers>
<QuestionAnswer Id="1" Answer="أقل من 16 عام"/>
<QuestionAnswer Id="2" Answer="17 – 24 عامً"/>
<QuestionAnswer Id="3" Answer="25- 34 عامً"/>
<QuestionAnswer Id="4" Answer="35- 44 عامً"/>
<QuestionAnswer Id="5" Answer="أكثر من 45 عامً"/>
</Answers>
XSL:
<xsl:for-each select=".//QuestionAnswer">
<xsl:variable name="AnswerId" select="#Id"/>
<xsl:variable name="AnswerText" select="#Answer"/>
<xsl:value-of select="concat(' ',$AnswerId, ' "', $AnswerText, '"')" />
</xsl:for-each>
and return should be the order from XML, but is in an odd order because of Arabic characters.
How can I fix this?
1 "أقل من 16 عام"
2 "17 – 24 عامً"
3 "25- 34 عامً"
4 "35- 44 عامً"
5 "أكثر من 45 عامً"
If you want to sort on the value of #Answer then you should be able to use
<xsl:for-each select=".//QuestionAnswer">
<xsl:sort select="#Answer" lang="ar"/>
You can further qualify the language code, e.g. lang="ar-EG" gives sorting according to the rules for Arabic as used in Egypt. I don't know anything about Arabic so I don't know if this is necessary.
Of course, it might be that your XSLT processor does not support all possible language codes.
Try adding the RTL unicode to your sentence:
<xsl:variable name="rightToLeftUnicode" select="'‎'"></xsl:variable>
<xsl:value-of select="concat(' ',$AnswerId, ' "', $AnswerText, '"', $rightToLeftUnicode)" />

xsl - format-number from one to two digits 1 => 01

is there in XSLT some function or somethg to alow format digits
like eg 1 will become 01
so if I have
<a>10</a>
<b>5</b>
they will apear as
A10
and
B05
Function Formating numbers:
<xsl:template match="root/*">
<xsl:value-of select="format-number(.,'00')"/>
</xsl:template>
XSLT 1.0 uppercase of nodenames:
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:value-of select="translate(name(), $smallcase, $uppercase)" />
Combined:
<xsl:value-of select="concat(translate(name(), $smallcase, $uppercase), format-number(.,'00'))" />
format-number(5, '00')
returns "05".
Similarly,
format-number(10, '00')
returns "10".

XSLT XML transformation using Oracle 11g

I am shredding XML stored in CLOB column of a table using Oracle 11g SQL by passing ML through a XSLT using oracle function xmltransform.
After transformaing I get shredded data in column format
wherever parent nodes are repeating, child elements are not be repeated within a parent node
SQL query for transforming
---------------------------
with xml_xsl as (select '<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="/">
<ROWSET>
<xsl:apply-templates select="*">
<xsl:with-param name="lvl" select="0"/>
</xsl:apply-templates>
</ROWSET>
</xsl:template>
<xsl:template match="*">
<xsl:param name="id"/>
<xsl:param name="pid"/>
<xsl:param name="pxp"/>
<xsl:param name="lvl"/>
<xsl:param name="position"/>
<xsl:variable name="id" select="substring(generate-id(.),2)"/>
<xsl:variable name="name" select="local-name(.)"/>
<xsl:variable name="xp" select="concat($pxp,''/'',$name)"/>
<xsl:variable name="pos" select="count(preceding::*[name(.)=$name])"/>
<ROW id="{$id}" pid="{$pid}" name="{$name}" xpath="{$xp}" level="{$lvl+1}" position="{$pos}" kind="element">
<xsl:value-of select="text()"/>
</ROW>
<xsl:apply-templates select="*">
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="pid" select="$id"/>
<xsl:with-param name="pxp" select="$xp"/>
<xsl:with-param name="lvl" select="$lvl+1"/>
<xsl:with-param name="position" select="$pos"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>' as xsl,
'<x1:A xmlns:x1="http://www.w3.org/transform">
<x2:B xmlns:x2="http://www.w3.org/transform">
<C>99999</C>
<C>2222</C>
</x2:B>
<E>8888</E>
<D>
<G1>Deep</G1>
</D>
<D>
<G>Deep3</G>
</D>
</x1:A>' as xml from dual)
select x.*
from xml_xsl a
, xmltable('/ROWSET/ROW'
passing xmltransform(xmlparse(document a.xml), xmlparse(document a.xsl wellformed))
columns id number path '#id'
, p_id number path '#pid'
, node_name varchar2(30) path '#name'
, node_value varchar2(4000) path '.'
, xpath varchar2(4000) path '#xpath'
, pos number path '#position'
) x;
Input XML:
----------
<A>
<B>
<C>99999</C>
</B>
<E>8888</E>
<D>
<G1>Deep</G1>
</D>
<D>
<G>XYZ</G>
</D>
</A>
Output
-------
id Parentid node depth position value xpath
-- -------- ----- ----- -------- ----- ------
1 NULL A 0 0 NULL /A
2 1 B 1 0 NULL /A/B
3 2 C 2 0 99999 /A/B/C
4 1 E 1 0 8888 /A/E
5 1 D 1 0 NULL /A/D
6 5 G1 2 0 Deep /A/D/G1
7 1 D 1 1 NULL /A/D
**8 7 G 2 0 XYZ /A/D/G** Postion for node G showing 0 which should req. 1
As node G is not present in parent D previously but present in 2nd parent D the position for that should be 1 rather than 0.
I tried every thing but not getting solution.

how to convert xsl dateformat?

How to convert
01/29/2012 00:00
to
Monday, Jan 29, 2012
in xslt?
I. An XSLT 1.0 solution (not producing the day of the week), which is much simpler and shorter than other answers :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output method="text"/>
<my:months>
<m>Jan</m><m>Feb</m><m>Mar</m><m>Apr</m><m>May</m><m>Jun</m>
<m>Jul</m><m>Aug</m><m>Sep</m><m>Oct</m><m>Nov</m><m>Dec</m>
</my:months>
<xsl:variable name="vMonthNames" select=
"document('')/*/my:months/*"/>
<xsl:template match="text()">
<xsl:variable name="vnumMonth" select="substring-before(., '/')"/>
<xsl:variable name="vDay" select=
"substring-before(substring-after(., '/'), '/')"/>
<xsl:variable name="vYear" select=
"substring-before(substring-after(substring-after(., '/'), '/'), ' ')"/>
<xsl:value-of select=
"concat($vMonthNames[0+$vnumMonth], ' ',
$vDay, ', ',
$vYear
)"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>01/29/2012 00:00</t>
the wanted result is produced:
Jan 29, 2012
II.In XSLT 2.0 one can use very powerful date-time functions, such as format-dateTime().
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="text()">
<xsl:variable name="vComps" select=
"tokenize(., '/')"/>
<xsl:variable name="vstdDate" select=
"concat(substring-before($vComps[3], ' '), '-',
$vComps[1], '-',
$vComps[2]
)"/>
<xsl:sequence select=
"format-date(xs:date($vstdDate), '[FNn], [MNn] [D], [Y]')"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the same XML document (above), the wanted, correct result is produced:
Sunday, January 29, 2012
Source : http://geekswithblogs.net/workdog/archive/2007/02/08/105858.aspx#110623
" I've modified to convert "1/20/2007 10:22:28 PM" to "January 20, 2007" ... to save anyone who finds it useful a few minutes.
<xsl:template name="FormatDate">
<!-- expected date format 1/20/2007 10:22:28 PM [OR] 01/20/2007 10:22:28 PM -->
<xsl:param name="DateTime" />
<!-- new date format January 20, 2007 -->
<xsl:variable name="mo">
<xsl:value-of select="substring-before($DateTime,'/')" />
</xsl:variable>
<xsl:variable name="day-temp">
<xsl:value-of select="substring-after($DateTime,'/')" />
</xsl:variable>
<xsl:variable name="day">
<xsl:value-of select="substring-before($day-temp,'/')" />
</xsl:variable>
<xsl:variable name="year-temp">
<xsl:value-of select="substring-after($day-temp,'/')" />
</xsl:variable>
<xsl:variable name="year">
<xsl:value-of select="substring($year-temp,1,4)" />
</xsl:variable>
<xsl:choose>
<xsl:when test="$mo = '1' or $mo = '01'">January</xsl:when>
<xsl:when test="$mo = '2' or $mo = '02'">February</xsl:when>
<xsl:when test="$mo = '3' or $mo = '03'">March</xsl:when>
<xsl:when test="$mo = '4' or $mo = '04'">April</xsl:when>
<xsl:when test="$mo = '5' or $mo = '05'">May</xsl:when>
<xsl:when test="$mo = '6' or $mo = '06'">June</xsl:when>
<xsl:when test="$mo = '7' or $mo = '07'">July</xsl:when>
<xsl:when test="$mo = '8' or $mo = '08'">August</xsl:when>
<xsl:when test="$mo = '9' or $mo = '09'">September</xsl:when>
<xsl:when test="$mo = '10'">October</xsl:when>
<xsl:when test="$mo = '11'">November</xsl:when>
<xsl:when test="$mo = '12'">December</xsl:when>
</xsl:choose>
<xsl:value-of select="' '"/>
<xsl:if test="(string-length($day) < 2)">
<xsl:value-of select="0"/>
</xsl:if>
<xsl:value-of select="$day"/>
<xsl:value-of select="', '"/>
<xsl:value-of select="$year"/>
</xsl:template>
"
Apologies for this horribly complicated solution, but it'll give you exactly what you want in XSLT 1.0:
<xsl:variable name="months" select="'JanFebMarAprMayJunJulAugSepOctDec'" />
<xsl:variable name="weekdays" select="'Monday Tuesday WednesdayThursday Friday Saturday Sunday '" />
<xsl:template match="date">
<xsl:variable name="days">
<xsl:value-of select="
((substring(.,7,4) - 1970) * 365)+floor((substring(.,7,4) - 1970) div 4)+
substring('000,031,059,090,120,151,181,212,243,273,304,334,365',substring(.,1,2)*4-3,3)+
(substring(.,4,2)-1)+
(1-floor(((substring(.,7,4) mod 4) + 2) div 3))*floor((substring(.,1,2)+17) div 20)
" />
</xsl:variable>
<xsl:value-of select="concat(
normalize-space(substring($weekdays,(($days+3) mod 7) * 9 + 1, 9)),
', ',
substring($months,substring(.,1,2) * 3 - 2, 3),
' ',
substring(.,4,2) + 0,
', ',
substring(.,7,4)
)" />
</xsl:template>
The construction of the variable 'days' uses a fairly complicated formula that determines the number of days since 1/1/1970. It's a simple matter from there to add 3 (because 1/1/1970 was a Thursday) and take the mod 7 of this figure to get the day of the week from the weekdays variable with substr.
If you're going to be working with dates a lot though, get XSLT2!

generating clrf in irrespective manner

having a string length about of 120
here below my message string:
CID_Ultimate_Ben_Details=pabbisettishanmukhpraveenkumarpabbisettishanmukhpraveenkumarpabbisettishanmukhpraveenkumarpabbisettishanmukhpraveenkumar
Ex: the message length of 140
output required as :
1 to 35 chars in first line
36 t0 70 chars in second line
71 to 105 chars in third line
106 to 140 in fourth line
here my xslt logic:
<xsl:if test ="./CID_Ultimate_Ben_Details != '' " >
<xsl:if test ="string-length(./CID_Ultimate_Ben_Details) != '11' and string-length(./CID_Ultimate_Ben_Details) != '8' ">
<xsl:if test="string-length(./CID_Ultimate_Ben_Details) > 1">
<xsl:value-of select="concat(':58D:',substring(./CID_Ultimate_Ben_Details,1,35))" />
</xsl:if>
<xsl:if test="string-length(./CID_Ultimate_Ben_Details) > 35">
<xsl:value-of select="concat('
',substring(./CID_Ultimate_Ben_Details,36,70))" />
</xsl:if>
<xsl:if test="string-length(./CID_Ultimate_Ben_Details) > 70">
<xsl:value-of select="concat('
',substring(./CID_Ultimate_Ben_Details,71,105))" />
</xsl:if>
<xsl:if test="string-length(./CID_Ultimate_Ben_Details) > 105">
<xsl:value-of select="concat('
',substring(./CID_Ultimate_Ben_Details,106,140))" />
</xsl:if>
</xsl:if>
<xsl:text>
</xsl:text >
</xsl:if>
output required as :
:58D:pabbisettishanmukhpraveenkumarpabbi
settishanmukhpraveenkumarpabbisetti
shanmukhpraveenkumarpabbisettishanm
ukhpraveenkumar
but now for the above logic output is coming as such:
:58D:pabbisettishanmukhpraveenkumarpabbi
settishanmukhpraveenkumarpabbisettishanmukhpraveenkumarpabbisettishanm
shanmukhpraveenkumarpabbisettishanmukhpraveenkumar
ukhpraveenkumar
why it was generating clrf in a irrespective manner.can any one suggest me please to achive my required output
Here is a correct and general (working for any text-length and number of output lines) XSLT 1.0 solution (the XSLT 2.0 solution is really elementary):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pmsgLength" select="140"/>
<xsl:param name="pnumLines" select="4"/>
<xsl:variable name="vmaxLineLength" select=
"ceiling($pmsgLength div $pnumLines)"/>
<xsl:template match="/*/text()" name="split">
<xsl:param name="pText" select="."/>
<xsl:param name="pnextLines" select="$pnumLines"/>
<xsl:param name="pHead" select="':58D:'"/>
<xsl:if test="$pnextLines">
<xsl:value-of select=
"concat('
',$pHead, substring($pText, 1, $vmaxLineLength))"/>
<xsl:call-template name="split">
<xsl:with-param name="pText" select="substring($pText, $vmaxLineLength+1)"/>
<xsl:with-param name="pnextLines" select="$pnextLines -1"/>
<xsl:with-param name="pHead" select="''"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>pabbisettishanmukhpraveenkumarpabbisettishanmukhpraveenkumarpabbisettishanmukhpraveenkumarpabbisettishanmukhpraveenkumar</t>
the wanted, correct output is produced:
:58D:pabbisettishanmukhpraveenkumarpabbi
settishanmukhpraveenkumarpabbisetti
shanmukhpraveenkumarpabbisettishanm
ukhpraveenkumar
The third argument of substring() is the length required, not the end position as in Java.