HIPAA 5010 to csv via XSLT - Loop Path issue? - loops

I am attempting to learn some XLST for extracting data from EDi 837/835 files. The below will place the fields specified from Loop 2100 in to a cvs format, but not the fields from Loop 2110. The stylesheet below it will return the fields from Loop 2110 but not 2100. How could I combine the loops to return the fields from both 2100 and 2110 in 1 stylesheet? I have tried several options and have been unsuccessful returning all fields in a csv format. Any ideas? Any help is greatly appreciated. The 835 Test file id is at the bottom.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="text" indent="yes"/>
<xsl:template match="Interchange">
<xsl:apply-templates select="FunctionGroup/Transaction/Loop[#LoopId='2000']/Loop
[#LoopId='2100']"/>
</xsl:template>
<xsl:template match="Loop[#LoopId='2100'] ">
<xsl:variable name="trans" select="../../."/>
<xsl:variable name="payer" select="../../Loop[#LoopId='1000A']"/>
<xsl:variable name="payee" select="../../Loop[#LoopId='1000B']"/>
<xsl:variable name="payment" select="."/>
<xsl:variable name="cas" select="../../Loop[#LoopId='2110']"/>
<xsl:variable name="caxx" select="."/>
<xsl:value-of select="$trans/BPR/BPR16"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$caxx/N1/N102"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payee/N1/N102"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payee/N1/N104"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CLP/CLP01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CLP/CLP02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CLP/CLP03"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/NM1[NM101='QC']/NM103"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/NM1[NM101='QC']/NM104"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$cas/DTM[DTM01='472']/DTM02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='CO']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='CO']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='CR']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='CR']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='OA']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='OA']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='PI']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='PI']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='PR']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='PR']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/REF[REF01='6R']/REF02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$cas/CAS[CAS01='PR']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="text" indent="yes"/>
<xsl:template match="Interchange">
<xsl:apply-templates select="FunctionGroup/Transaction/Loop[#LoopId='2000']/Loop
[#LoopId='2100']/Loop[#LoopId='2110']"/>
</xsl:template>
<xsl:template match="Loop[#LoopId='2110'] ">
<xsl:variable name="trans" select="../../."/>
<xsl:variable name="payer" select="../../Loop[#LoopId='1000A']"/>
<xsl:variable name="payee" select="../../Loop[#LoopId='1000B']"/>
<xsl:variable name="payment" select="."/>
<xsl:variable name="cas" select="../../Loop[#LoopId='2110']"/>
<xsl:variable name="caxx" select="."/>
<xsl:value-of select="$trans/BPR/BPR16"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$caxx/N1/N102"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payee/N1/N102"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payee/N1/N104"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CLP/CLP01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CLP/CLP02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CLP/CLP03"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/NM1[NM101='QC']/NM103"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/NM1[NM101='QC']/NM104"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$cas/DTM[DTM01='472']/DTM02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='CO']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='CO']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='CR']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='CR']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='OA']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='OA']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='PI']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='PI']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='PR']/CAS01"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/CAS[CAS01='PR']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$payment/REF[REF01='6R']/REF02"/>
<xsl:value-of select=",'"/>
<xsl:value-of select="$cas/CAS[CAS01='PR']/CAS02"/>
<xsl:value-of select="','"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
---------835 file
ISA*00* *00* *ZZ*ASHTB *ZZ*01017
*040315*1005*U*00401*004075123*0*P*:~
GS*HP*ASHTB*01017*20040315*1005*1*X*004010X091A1~
ST*835*07504123~
BPR*H*5.75*C*NON************20040315~
TRN*1*A04B001017.07504*1346000128~
DTM*405*20040308~
N1*PR*ASHTABULA COUNTY ADAMH BD~
N3*4817 STATE ROAD SUITE 203~
N4*ASHTABULA*OH*44004~
N1*PE*LAKE AREA RECOVERY CENTER *FI*346608640~
N3*2801 C. COURT~
N4*ASHTABULA*OH*44004~
REF*PQ*1017~
LX*1~
CLP*444444*1*56.70*56.52*0*MC*0000000655555555*53~
NM1*QC*1*FUDD*ELMER*S***MI*1333333~
NM1*82*2*WECOVERWY SVCS*****FI*346608640~
REF*F8*A76B04054~
SVC*HC:H0005:HF:H9*56.70*56.52**6~
DTM*472*20040205~
CAS*CO*42*0.18*0~
REF*6R*444444~
CLP*999999*4*25.95*0*25.95*13*0000000555555555*11~
NM1*QC*1*SAM*YOSEMITE*A***MI*3333333~
NM1*82*2*ACME AGENCY*****FI*310626223~
REF*F8*H57B10401~
SVC*ZZ:M2200:HE*25.95*0**1~
DTM*472*20021224~
CAS*CR*18*25.95*0~
CAS*CO*42*0*0~
REF*6R*999999~
CLP*888888*4*162.13*0*162.13*MC*0000000456789123*11~
NM1*QC*1*SQUAREPANTS*BOB* ***MI*2222222~
NM1*82*2*BIKINI AGENCY*****FI*310626223~
REF*F8*H57B10401~
SVC*ZZ:M151000:F0*162.13*0**1.9~
DTM*472*20020920~
CAS*CO*29*162.13*0*42*0*0~
REF*6R*888888~
CLP*111111*2*56.52*18.88*0*13*0000000644444444*53~
NM1*QC*1*LEGHORN*FOGHORN*P***MI*7777777~
NM1*82*2*CHICKENHAWK SVCS*****FI*346608640~
REF*F8*A76B04054~
SVC*HC:H0005:HF:H9*56.52*18.88**6~
DTM*472*20031209~
CAS*CO*42*0*0~
CAS*OA*23*37.64*0~
REF*6R*111111~
CLP*121212*4*56.52*0*0*13*0000000646464640*53~
NM1*QC*1*EXPLORER*DORA****MI*1717171~
NM1*82*2*SWIPER AGENCY*****FI*346608640~
REF*F8*A76B04054~
SVC*HC:H0005:HF:H9*56.52*0**6~
DTM*472*20031202~
CAS*CO*42*0*0~
CAS*OA*23*57.6*0*23*-1.08*0~
REF*6R*121212~
CLP*333333*1*74.61*59.69*14.92*13*0000000688888888*55~
NM1*QC*1*BEAR*YOGI* ***MI*2222222~
NM1*82*2*JELLYSTONE SVCS*****FI*346608640~
REF*F8*A76B04054~
SVC*ZZ:A0230:HF*74.61*59.69**1~
DTM*472*20040203~
CAS*PR*2*14.92*0~
CAS*CO*42*0*0~
REF*6R*333333~
CLP*777777*25*136.9*0*0*13*0000000622222222*53~
NM1*QC*1*BIRD*TWEETY*M***MI*4444444~
NM1*82*2*GRANNY AGENCY*****FI*340716747~
REF*F8*A76B03293~
SVC*HC:H0015:HF:99:H9*136.9*0**1~
DTM*472*20030911~
CAS*PI*104*136.72*0~
CAS*CO*42*0.18*0~
REF*6R*777777~
CLP*123456*22*-42.58*-42.58*0*13*0000000657575757*11~
NM1*QC*1*SIMPSON*HOMER* ***MI*8787888~
NM1*82*2*DOH GROUP*****FI*310626223~
REF*F8*A57B04033~
SVC*HC:H0036:GT:UK*-42.58*-42.58**-2~
DTM*472*20040102~
CAS*CR*141*0*0*42*0*0*22*0*0~
CAS*OA*141*0*0~
REF*6R*123456~
CLP*090909*22*-86.76*-86.76*0*MC*0000000648484848*53~
NM1*QC*1*DUCK*DAFFY*W***MI*1245849~
NM1*82*2*ABTHSOLUTE HELP*****FI*346608640~
REF*F8*A76B04054~
SVC*HC:H0004:HF:H9*-86.76*-86.76**-4~
DTM*150*20040210~
DTM*151*20040211~
CAS*CR*22*0*0*42*0*0~
CAS*OA*22*0*0~
REF*6R*090909~
AMT*AU*86.76~
QTY*NE*53~
LQ*HE*MA92~
PLB*123456*19960930*CV:9876514*-1.27~
SE*97*07504123~
GE*1*1~
IEA*1*004075123~

Looking at your two stylesheets, the only differences is with the xsl:apply-templates
<xsl:apply-templates select="FunctionGroup/Transaction/Loop[#LoopId='2000']/Loop
[#LoopId='2100']"/>
And the respective template match
<xsl:template match="Loop[#LoopId='2100'] ">
In both cases it is only the "2100" and "2110" that differ.
To allow the first XSLT to manage both "2100" and "2110" records, replace the existing single xsl:apply-templates with these:
<xsl:apply-templates select="FunctionGroup/Transaction/Loop[#LoopId='2000']/Loop[#LoopId='2100']"/>
<xsl:apply-templates select="FunctionGroup/Transaction/Loop[#LoopId='2000']/Loop[#LoopId='2110']"/>
Then, change the template match to this, to share the template
<xsl:template match="Loop[#LoopId='2100' or #LoopId='2110'] ">
Try this (abridged) XSLT, which combines your two XSLT stylesheets into one
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="text" indent="yes"/>
<xsl:template match="Interchange">
<xsl:apply-templates select="FunctionGroup/Transaction/Loop[#LoopId='2000']/Loop[#LoopId='2100']"/>
<xsl:apply-templates select="FunctionGroup/Transaction/Loop[#LoopId='2000']/Loop[#LoopId='2110']"/>
</xsl:template>
<xsl:template match="Loop[#LoopId='2100' or #LoopId='2110'] ">
<xsl:variable name="trans" select="../../."/>
<xsl:variable name="caxx" select="."/>
<xsl:value-of select="$trans/BPR/BPR16"/>
<xsl:value-of select="','"/>
<xsl:value-of select="$caxx/N1/N102"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>

Related

Repeat position within a loop in xslt

I have two nested loops. The first loop is picking up distinct value and comparing in second loop. In second loop i am giving position() and it is coming sequential as 1,2,3 but i want it to appear as 1,1,1 during first iteration and 2,2,2 in second iteration and 3,3,3 in third iteration and so on.
XML:
<root>
<Items>
<Item>
<ItemCode>12345</ItemCode>
<ItemColor>Red</ItemColor>
<Weight>1Kg</Weight>
</Item>
<Item>
<ItemCode>19087</ItemCode>
<ItemColor>Blue</ItemColor>
<Weight>1Kg</Weight>
</Item>
</Items>
<Items>
<Item>
<ItemCode>12345</ItemCode>
<ItemColor>Yellow</ItemColor>
<Weight>1Kg</Weight>
</Item>
<Item>
<ItemCode>19087</ItemCode>
<ItemColor>Green</ItemColor>
<Weight>1Kg</Weight>
</Item>
</Items>
</root>
Required Output:
12345
1.Red
1.Yellow
19087
2.Blue
2.Green
(Or)
1.12345
Red
Yellow
2.19087
Blue
Green
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="check" match="Items" use="ItemCode" />
<xsl:template match="root/Items">
<xsl:for-each select="Item[count(. | key('check', ItemCode)[1]) = 1]">
<xsl:value-of select="ItemCode"/>
<xsl:for-each select="key('check', ItemCode)">
<xsl:value-of select="position()"/>
<xsl:value-of select="ItemColor"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I am using xslt-1.0
Your help is appreciated. Thank you!
The following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:key name="item-by-code" match="Item" use="ItemCode"/>
<xsl:template match="/root">
<xsl:for-each select="Items/Item[count(. | key('item-by-code', ItemCode)[1]) = 1]">
<xsl:value-of select="position()"/>
<xsl:text>.</xsl:text>
<xsl:value-of select="ItemCode"/>
<xsl:for-each select="key('item-by-code', ItemCode)">
<xsl:text>
</xsl:text>
<xsl:value-of select="ItemColor"/>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied yo your input example, will return:
Result
1.12345
Red
Yellow
2.19087
Blue
Green
Alternatively, you could do:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:key name="item-by-code" match="Item" use="ItemCode"/>
<xsl:template match="/root">
<xsl:for-each select="Items/Item[count(. | key('item-by-code', ItemCode)[1]) = 1]">
<xsl:variable name="i" select="position()" />
<xsl:value-of select="ItemCode"/>
<xsl:text>
</xsl:text>
<xsl:for-each select="key('item-by-code', ItemCode)">
<xsl:value-of select="$i"/>
<xsl:text>.</xsl:text>
<xsl:value-of select="ItemColor"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
to get:
12345
1.Red
1.Yellow
19087
2.Blue
2.Green

How to get a number with unique digits in XSLT 1.0?

I have below variable.
<xsl:variable name="number" select="56568"/>
Output needed : 568
I need to get a output which contains only unique digits in the number.
Any idea how to achieve this in XSLT 1.0 ?
Thanks
I don't think there is an easy way to do this - unless your processor supports some extension functions. Without it, you would have to use a recursive named template:
<xsl:template name="distinct-characters">
<xsl:param name="input"/>
<xsl:param name="output"/>
<xsl:choose>
<xsl:when test="not($input)">
<xsl:value-of select="$output"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="char" select="substring($input, 1, 1)" />
<!-- recursive call -->
<xsl:call-template name="distinct-characters">
<xsl:with-param name="input" select="substring($input, 2)"/>
<xsl:with-param name="output">
<xsl:value-of select="$output"/>
<xsl:if test="not(contains($output, $char))">
<xsl:value-of select="$char"/>
</xsl:if>
</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Example of call:
<output>
<xsl:call-template name="distinct-characters">
<xsl:with-param name="input" select="56568"/>
</xsl:call-template>
</output>
Result:
<output>568</output>
Demo: http://xsltransform.net/a9Gix1
Added:
Revisiting this after 4 years, there is a shorter and more efficient way. Instead of iterating over every character in the input, it iterates only over each distinct character:
<xsl:template name="distinct-characters">
<xsl:param name="input"/>
<xsl:if test="$input">
<xsl:variable name="char" select="substring($input, 1, 1)" />
<xsl:value-of select="$char"/>
<!-- recursive call -->
<xsl:call-template name="distinct-characters">
<xsl:with-param name="input" select="translate($input, $char, '')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Demo: http://xsltransform.net/a9Gix1/1

XSLT sort array values

I'm new on XSLT. I want to sort the following xml segment by XSLT. Does anyone know how to sort the inner array values?
<Coordinates>
<Array n="155" type="real">1909.090909090909 1894.7368421052631 1777.7777777777778 1923.076923076923 2000.0 3191.528925619835 3771.025641025641 4609.022727272727 6931.111111111111 7394.8611111111095 3149.4444444444443 4173.596491228071 6090.740740740741 7578.214285714285 7261.25 3369.7478260869566 5986.1621621621625 6515.15625 7138.875000000002 8225.714285714286 3224.5867768595035 6915.27027027027 8103.548387096775 6897.741935483871 8485.166666666666 3662.2988505747126 7968.2307692307695 7770.882352941177 6628.548387096775 8864.642857142857 3429.8863636363635 5785.285714285715 6576.428571428572 6791.8 8715.625 4015.2450980392155 7127.045454545455 6171.041666666667 9326.95652173913 10307.827586206897 3577.6136363636365 6820.000000000001 6308.913043478261 8907.0 9448.392857142857 3452.926829268293 7172.5 7280.0 8653.125 9277.692307692309 3108.3333333333335 4601.282051282052 6530.538461538462 8847.368421052632 8147.105263157895 3258.360655737705 7630.833333333335 6814.333333333333 5513.35294117647 9727.894736842105 2781.2500000000005 6974.21875 7172.5 6459.318181818182 8599.722222222223 3512.0454545454545 5203.5 7422.5 9705.454545454546 9217.631578947368 3608.7820512820513 6385.952380952381 9302.35294117647 6647.857142857143 8054.285714285715 ...
</Array>
</Coordinates>
I want to sort the real values by ascending order.
Thanks in advance.
If you are using the Xalan-J processor, you can take advantage of the EXSLT str:tokenize() extension function and do simply:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Array">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:for-each select="str:tokenize(., ' ')">
<xsl:sort select="." data-type="number" order="ascending"/>
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Otherwise you will have to tokenize the values using a recursive named template, then convert the result to a node-set before you can sort it:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Array">
<xsl:variable name="values">
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:for-each select="exsl:node-set($values)/value">
<xsl:sort select="." data-type="number" order="ascending"/>
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
<xsl:if test="$token">
<value>
<xsl:value-of select="$token"/>
</value>
</xsl:if>
<xsl:if test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
One solution is to form a variable where each tag contains value. And then you can sort it by method , which works for number in xslt 1.0 too. As i can see, your values here are separated by a space.
ok, here is my solution. credit for a part goes to Does XSLT have a Split() function?
<xsl:template match="/">
<xsl:variable name="raw-data">
<xsl:value-of select="Coordinates/Array"/>
</xsl:variable>
<xsl:variable name="ids">
<xsl:if test="$raw-data">
<xsl:call-template name="output-tokens">
<xsl:with-param name="list" select="$raw-data" />
</xsl:call-template>
</xsl:if>
</xsl:variable>
<xsl:for-each select="msxsl:node-set($ids)/id">
<xsl:sort data-type="number" order="descending" select="."/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template name="output-tokens">
<xsl:param name="list" />
<xsl:variable name="newlist" select="concat(normalize-space($list), ' ')" />
<xsl:variable name="first" select="substring-before($newlist, ' ')" />
<xsl:variable name="remaining" select="substring-after($newlist, ' ')" />
<id>
<xsl:value-of select="$first" />
</id>
<xsl:if test="$remaining">
<xsl:call-template name="output-tokens">
<xsl:with-param name="list" select="$remaining" />
</xsl:call-template>
</xsl:if>
</xsl:template>
p.s. edited - now with sort

Compare XSL values in array

I'm not sure how to title this post..
I want to compare pubDate between rows
Desired Output: Only print the pubDate when it is different from the previous row's pubDate. (my substring function returns Dec 2014, Jan 2015, etc)
Currently I have it set to print the pubDate every time. I just can't figure out how to compare the value between rows... please help!
Code excerpt:
<xsl:template match="item">
<xsl:variable name="Rows" select="channel/item"/>
<xsl:variable name="RowCount" select="count($Rows)"/>
<xsl:variable name="item_link" select="link"/>
<xsl:variable name="item_title" select="description"/>
<xsl:value-of select="$Rows"/>
<xsl:variable name="CurPosition" select="position()" />
<xsl:variable name="PrevPosition" select="position()-1" />
<xsl:variable name="RssFeedLink" select="$rss_WebPartID" />
<xsl:variable name="CurrentElement" select="concat($RssFeedLink,$CurPosition)" />
<xsl:if test="not(substring(pubDate,3,9) = 0)">
<div align="center">
<hr/>
<xsl:value-of select="substring(pubDate,3,9)" disable-output-escaping="yes"/>
</div>
</xsl:if>
<li>
<a href="{$item_link}" title="{$item_title}">
<xsl:variable name="SafeHtml">
<xsl:call-template name="GetSafeHtml">
<xsl:with-param name="Html" select="title"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$SafeHtml" disable-output-escaping="yes"/>
</a>
</li>
Here is the full code for anybody who wants it:
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
version="1.0" exclude-result-prefixes="xsl ddwrt msxsl rssaggwrt"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:rssaggwrt="http://schemas.microsoft.com/WebParts/v3/rssagg/runtime"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:rssFeed="urn:schemas-microsoft-com:sharepoint:RSSAggregatorWebPart">
<xsl:param name="rss_FeedLimit">30</xsl:param>
<xsl:param name="rss_ExpandFeed">true</xsl:param>
<xsl:param name="rss_LCID">1033</xsl:param>
<xsl:param name="rss_WebPartID">RSS_Viewer_WebPart</xsl:param>
<xsl:param name="rss_alignValue">left</xsl:param>
<xsl:param name="rss_IsDesignMode">True</xsl:param>
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="Rows" select="channel/item"/>
<xsl:variable name="RowCount" select="count($Rows)"/>
<div>
<xsl:apply-templates select="rss/channel"/>
</div>
</xsl:template>
<xsl:template match="rss/channel">
<xsl:variable name="link" select="link"/>
<xsl:variable name="description" select="description"/>
<ul>
<xsl:apply-templates select="item"/>
</ul>
</xsl:template>
<xsl:template match="item">
<xsl:variable name="Rows" select="channel/item"/>
<xsl:variable name="RowCount" select="count($Rows)"/>
<xsl:variable name="item_link" select="link"/>
<xsl:variable name="item_title" select="description"/>
<xsl:value-of select="$Rows"/>
<xsl:variable name="CurPosition" select="position()" />
<xsl:variable name="RssFeedLink" select="$rss_WebPartID" />
<xsl:variable name="CurrentElement" select="concat($RssFeedLink,$CurPosition)" />
<xsl:if test="not(substring(pubDate,3,9) = 0)">
<div align="center">
<hr/>
<xsl:value-of select="substring(pubDate,3,9)" disable-output-escaping="yes"/>
</div>
</xsl:if>
<li>
<a href="{$item_link}" title="{$item_title}">
<xsl:variable name="SafeHtml">
<xsl:call-template name="GetSafeHtml">
<xsl:with-param name="Html" select="title"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$SafeHtml" disable-output-escaping="yes"/>
</a>
</li>
</xsl:template>
<xsl:template name="GetSafeHtml">
<xsl:param name="Html"/>
<xsl:choose>
<xsl:when test="$rss_IsDesignMode = 'True'">
<xsl:value-of select="$Html"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="rssaggwrt:MakeSafe($Html)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
If you want to check the value of previous "row" you can use the preceding-sibling axis operator.
So, instead of writing this....
<xsl:if test="not(substring(pubDate,3,9) = 0)">
Write this...
<xsl:if test="not(substring(pubDate,3,9) = 0) and not(pubDate = preceding-sibling::item[1]/pubDate)">
Note the use of the [1] here. Doing preceding-sibling will return all nodes preceding the current one, and you only want the first one.
Also note, you might be tempted to write this...
<xsl:if test="not(substring(pubDate,3,9) = 0) and pubDate != preceding-sibling::item[1]/pubDate">
But this will not work for the first item element, because for that expression to be true the preceding sibling would have to exist.
Finally, this will only really work if the item elements are in pub-date order. A better approach would be to consider this a grouping problem, and group the items by date. For XSLT 1.0 you would use a technique called Muenchian Grouping.

xslt single output from a loop

I have a source file that looks like this
<company>
<ids>
<id provider="AAA">123456</id>
</ids>
<businessDetails>
<blocks>
<block channel="google.com"/>
<block channel="nokia.com"/>
<block channel="bing.com"/>
</blocks>
<registration>
<registrationNumber>1352045555</registrationNumber>
<registrationDate>1983-09-17</registrationDate>
</registration>
</businessDetails>
</company>
I need to loop through block to see if I should send the registration number. A part of my xslt looks like this
<xsl:choose>
<xsl:when test="s2:businessDetails/s2:blocks">
<xsl:for-each select="s2:businessDetails/s2:blocks/s2:block">
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(./#channel="google.com") , "true")"/>
<xsl:variable name="var:v2" select="userCSharp:LogicalEq(string(./#channel="bing.com") , "true")"/>
<xsl:choose>
<xsl:when test="($var:v1 or $var:v2)='true'">
</xsl:when>
<xsl:otherwise>
<ns0:companyOrgNumber>
<xsl:value-of select="../../s2:registration/s2:registrationNumber/text()"/>
</ns0:companyOrgNumber>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:if test="s2:businessDetails/s2:registration/s2:registrationNumber">
<ns0:companyOrgNumber>
<xsl:value-of select="s2:businessDetails/s2:registration/s2:registrationNumber/text()"/>
</ns0:companyOrgNumber>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
The problem is when I have blocks, but none of them match var:v1 or var:v2 I get several in the destination file. I only want to have one if all block are false.
It looks like you should do this instead:
<xsl:if test="s2:businessDetails/s2:blocks[not(s2:block[#channel='google.com']) and not(s2:block[#channel='bing.com'])]">
<ns0:companyOrgNumber>
<xsl:value-of select="s2:businessDetails/s2:registration/s2:registrationNumber/text()"/>
</ns0:companyOrgNumber>
</xsl:if>
You don't really need to loop through it- Just check for the absence of those nodes.

Resources