Group consecutive numbers in XSLT - xslt

How to handle the below type of scenario using XSLT?
Example 1:
Input: <cross-refs>[5, 6, 7, 8, 9]</cross-refs>
Excepted output: <cross-refs>[5-9]</cross-refs>
Example 2:
Input: <cross-refs>[4, 6, 7, 8, 9]</cross-refs>
Excepted output: <cross-refs>[4,6-9]</cross-refs>
Example 3:
Input: <cross-refs>[4, 5, 6, 7, 9, 11, 12,13]</cross-refs>
Excepted output: <cross-refs>[4-7,9,11-13]</cross-refs>
Example 4:
Input: <cross-refs>[4, 5, 6, 7, 9, 10, 11, 12, 13]</cross-refs>
Excepted output: <cross-refs>[4-7,9-13]</cross-refs>
Thanks in advance

Consider the following example:
XML
<input>
<cross-refs>[5, 6, 7, 8, 9]</cross-refs>
<cross-refs>[4, 6, 7, 8, 9]</cross-refs>
<cross-refs>[4, 5, 6, 7, 9, 11, 12, 13]</cross-refs>
<cross-refs>[4, 5, 6, 7, 9, 10, 11, 12, 13]</cross-refs>
</input>
XSLT 2.0
<xsl:stylesheet version="2.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:for-each select="cross-refs">
<xsl:copy>
<xsl:variable name="tokens" select="tokenize(translate(., '[]', ''), ', ')" />
<xsl:for-each-group select="$tokens" group-adjacent="number(.) - position()">
<xsl:value-of select="." />
<xsl:if test="count(current-group()) > 1">
<xsl:text>-</xsl:text>
<xsl:value-of select="current-group()[last()]" />
</xsl:if>
<xsl:if test="position()!=last()">,</xsl:if>
</xsl:for-each-group>
</xsl:copy>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<output>
<cross-refs>5-9</cross-refs>
<cross-refs>4,6-9</cross-refs>
<cross-refs>4-7,9,11-13</cross-refs>
<cross-refs>4-7,9-13</cross-refs>
</output>

Related

DateTime Parsing in XSLT Xp20

I am having the Date field as below
<Input>
<date>08/26/2020</date>
</Input>
i would need to parse it as like below
<date>2020-08-26</date>
I have tried using below xpath funtion in XSLT, which is not producing any result
xp20:format-dateTime(/Input/date,'[Y0001]-[M01]-[D01]')
Any help here??
Using replace you can reorder the components, if you want to create an XSLT/XPath xs:date, additionally use the constructor function:
<xsl:template match="date">
<xsl:copy>
<xsl:value-of select="xs:date(replace(., '([0-9]{2})/([0-9]{2})/([0-9]{4})', '$3-$1-$2'))"/>
</xsl:copy>
</xsl:template>
What you could do is, extract sub strings, and re-join them as needed.
<date><xsl:value-of select="concat(substring-after(substring-after(date/text(),'/'),'/'), '-', substring-before(date/text(),'/'), '-', substring-before(substring-after(date/text(),'/'),'/'))" /></date>
or better use a template for this:
<xsl:template name="format_date">
<xsl:param name="date" />
<xsl:value-of select="concat( substring($date, 7, 2),'.',substring($date, 5, 2), '.', substring($date, 1, 4), ', ', substring($date, 9, 2),':',substring($date, 11, 2),'h' )" />
</xsl:template>
and pass the date as param (with-param).
which'll give you the desired <date>2020-08-26</date>

Convert date in XSL

I was wondering how can you this kind of date into a normal one.
Sample xml:
I want my output to be like this: 01/03/1959 based from the sample xml. I'm using xslt version 1.0 and xpath 1.0
Well, there are no dates as such in XSLT 1.0, so just threat this as an exercise in string manipulation and write out:
<xsl:value-of select="substring(data, 5, 2)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring(data, 7, 2)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring(data, 1, 4)"/>
or, if you prefer:
<xsl:value-of select="concat(substring(data, 5, 2), '/', substring(data, 7, 2), '/', substring(data, 1, 4))"/>
how can you this kind of date into a normal one.
Actually, the "normal one" would look like this: 1959-01-03.
http://en.wikipedia.org/wiki/ISO_8601

Date conversion YYYYMMDD to YYYY-MM-DD

I have a date string in format YYYYMMDD for example 20140330
In xsl 1.0 I want to convert the date string to format YYYY-MM-DD for example 2014-03-30
I tried using several date functions but it did not work.
Can anyone help me to convert the date ?
You can use the substring function. Given the following input XML:
<root>20140330</root>
and the following stylesheet:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="root">
<xsl:value-of select="concat(substring(., 1, 4), '-', substring(., 5, 2), '-', substring(., 7, 2))"/>
</xsl:template>
</xsl:stylesheet>
it outputs:
2014-03-30

comparing 2 squences in xslt

I have 2 sequences one is from 1 to 10 and other is 1 to 3.
how to compare the second sequence with first sequence to test whether first 3 items are same ?
Use this short XPath expression:
deep-equal(subsequence($seq1, 1, count($seq2)), $seq2)
When evaluated it produces true() exactly if the second sequence is a starting subsequence of the first. The two sequences can contain a mixture of any XDM items, including nodes.
Here is a full demonstration:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="vSeq1" select=
"1, 2, 3, 4, 5, 6, 7, 8, 9, 10"/>
<xsl:variable name="vSeq2" select=
"1, 2, 3"/>
<xsl:variable name="vSeq3" select="/*/*"/>
<xsl:variable name="vSeq4" select="/*/*[position() gt 5]"/>
<xsl:variable name="vSeq5" select="/*/*"/>
<xsl:variable name="vSeq6" select="/*/*[position() le 5]"/>
<xsl:template match="/">
<xsl:sequence select=
"deep-equal(subsequence($vSeq1, 1, count($vSeq2)), $vSeq2)"/>
===========
<xsl:sequence select=
"deep-equal(subsequence($vSeq3, 1, count($vSeq4)), $vSeq4)"/>
===========
<xsl:sequence select=
"deep-equal(subsequence($vSeq5, 1, count($vSeq6)), $vSeq6)"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
the wanted, correct result is produced:
true
===========
false
===========
true
Assuming you have two variables seq1 and seq2 you can simply test <xsl:if test="$seq1[1] eq $seq2[1] and $seq1[2] eq $seq2[2] and $seq1[3] eq $seq2[3]">...</xsl:if>.

SSN format in XSLT?

I could use some help creating an XSL template that will take a string of numbers (i.e., 123456789) and format that string into a Social Security Number format (i.e., 123-45-6789). I found one example on the Internet, but it seemed overcomplicated.
I'm new to XSLT, so please keep that in mind when replying. Thank you!
XSLT 1.0's string functions are a bit limited, but fortunately this isn't too hard:
Assuming < ssn >123456789< /ssn>:
<xsl:template match="ssn">
<xsl:value-of select="substring(., 0, 4)"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="substring(., 4, 2)"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="substring(., 6, 4)"/>
</xsl:template>
In XSLT 2.0, concat() can take more than two arguments, so it's a single line:
<xsl:template match="ssn">
<xsl:value-of select="concat(substring(., 0, 4), '-', substring(., 4, 2), '-', substring(., 6, 4))" />
</xsl:template>