XSLT Index of groups created by for-each-group - xslt

I need to divide a long table into smaller tables using for-each-group with the group-ending-with attribute. Inside each table I need to have the index of that group but I cannot find out which variable is available for that - if there is one.
Sample xml:
<table>
<row type='A'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='A'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='A'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='A'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
</table>
Desired output:
<table>
<title>Table 1</title>
<row type='A'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
</table>
<table>
<title>Table 2</title>
<row type='A'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
</table>
<table>
<title>Table 3</title>
<row type='A'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
</table>
<table>
<title>Table 4</title>
<row type='A'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
<row type='B'><cell>Some value</cell>
</table>
I have the grouping done, but I cannot find a way to get the index to put into the table titles. Maybe it is trivial but the search words group and index do not give any useful result.

Use the position() function.
No code, since no code was provided - and neither the sample input nor the expected output are well-formed XML.
(Addition by Michael Kay): Last para of ยง14.1 https://www.w3.org/TR/xslt-30/#element-for-each-group reads: -
"The sequence constructor contained in the xsl:for-each-group element
is evaluated once for each of the groups, in processing order. The
sequences that result are concatenated, in processing order, to form
the result of the xsl:for-each-group element. Within the sequence
constructor, the context item is the initial item of the relevant
group, the context position is the position of this group in the
processing order of the groups, and the context size is the number of
groups. This has the effect that within the sequence constructor, a
call on position() takes successive values 1, 2, ... last()."

Related

XSLT combine multiple list from one file to table

I need help with merging several tables of one file into one output.
The files that I get processed perfectly according to the XSLT schema that is listed below. But today I received an interesting file that was not processed as I wanted.
source file
<?xml version="1.0" encoding="utf-8"?>
<extdata user="test">
<scheme name="Order">
<data>
<s>
<d name="CashOrder">
<f name="ActionDate" type="Date" />
<f name="AddressId" type="String" />
<f name="CompanyId" type="String" />
</d>
</s>
<o>
<d name="CashOrder">
<r>
<f>2022-01-24T00:00:00</f>
<f>10234</f>
<f>10234</f>
</r>
<r>
<f>2022-01-24T00:00:00</f>
<f>52817</f>
<f>52817</f>
</r>
<r>
<f>2022-01-24T00:00:00</f>
<f>58259</f>
<f>58259</f>
</r>
</d>
</o>
</data>
<data>
<s>
<d name="OrderOption">
<f name="OrderDate" type="Date" />
<f name="OrderNumber" type="String" />
</d>
</s>
<o>
<d name="OrderOption">
<r>
<f>2022-01-24T00:00:00</f>
<f>WE30395.c17639</f>
</r>
<r>
<f>2022-01-24T00:00:00</f>
<f>WE30395.c17639</f>
</r>
<r>
<f>2022-01-24T00:00:00</f>
<f>WE30395.c17639</f>
</r>
</d>
</o>
</data>
</scheme>
</extdata>
my XSLT (here they helped me with writing.there was a problem with the recursive processing of the hierarchy)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/extdata/scheme">
<ValueTable xmlns="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:for-each select="data/s/d/f | data/s/d/d/f">
<column>
<Name xsi:type="xs:string">
<xsl:value-of select="#name" />
</Name>
<ValueType>
<xsl:if test="#type= 'String'">
<Type>xs:string</Type>
<StringQualifiers>
<Length>150</Length>
<AllowedLength>Variable</AllowedLength>
</StringQualifiers>
</xsl:if>
<xsl:if test="#type= 'Date'">
<Type>xs:dateTime</Type>
<DateQualifiers>
<DateFractions>DateTime</DateFractions>
</DateQualifiers>
</xsl:if>
<xsl:if test="#type= 'Decimal' or #type= 'Currency'">
<Type>xs:decimal</Type>
<NumberQualifiers>
<Digits>20</Digits>
<FractionDigits>4</FractionDigits>
<AllowedSign>Any</AllowedSign>
</NumberQualifiers>
</xsl:if>
<xsl:if test="#type= 'Integer'">
<Type>xs:decimal</Type>
<NumberQualifiers>
<Digits>20</Digits>
<FractionDigits>0</FractionDigits>
<AllowedSign>Any</AllowedSign>
</NumberQualifiers>
</xsl:if>
</ValueType>
</column>
</xsl:for-each>
<xsl:for-each select="data/o/d/r">
<row>
<xsl:for-each select=".//f">
<Value>
<xsl:value-of select="." />
</Value>
</xsl:for-each>
</row>
</xsl:for-each>
</ValueTable>
</xsl:template>
</xsl:stylesheet>
output now
<ValueTable xmlns="http://v8.1c.ru/8.1/data/core"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<column>
<Name xsi:type="xs:string">ActionDate</Name>
<ValueType>
<Type>xs:dateTime</Type>
<DateQualifiers>
<DateFractions>DateTime</DateFractions>
</DateQualifiers>
</ValueType>
</column>
<column>
<Name xsi:type="xs:string">AddressId</Name>
<ValueType>
<Type>xs:string</Type>
<StringQualifiers>
<Length>150</Length>
<AllowedLength>Variable</AllowedLength>
</StringQualifiers>
</ValueType>
</column>
<column>
<Name xsi:type="xs:string">CompanyId</Name>
<ValueType>
<Type>xs:string</Type>
<StringQualifiers>
<Length>150</Length>
<AllowedLength>Variable</AllowedLength>
</StringQualifiers>
</ValueType>
</column>
<column>
<Name xsi:type="xs:string">OrderDate</Name>
<ValueType>
<Type>xs:dateTime</Type>
<DateQualifiers>
<DateFractions>DateTime</DateFractions>
</DateQualifiers>
</ValueType>
</column>
<column>
<Name xsi:type="xs:string">OrderNumber</Name>
<ValueType>
<Type>xs:string</Type>
<StringQualifiers>
<Length>150</Length>
<AllowedLength>Variable</AllowedLength>
</StringQualifiers>
</ValueType>
</column>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>10234</Value>
<Value>10234</Value>
</row>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>52817</Value>
<Value>52817</Value>
</row>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>58259</Value>
<Value>58259</Value>
</row>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>WE30395.c17639</Value>
</row>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>WE30395.c17639</Value>
</row>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>WE30395.c17639</Value>
</row>
</ValueTable>
need
<ValueTable xmlns="http://v8.1c.ru/8.1/data/core"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<column>
<Name xsi:type="xs:string">ActionDate</Name>
<ValueType>
<Type>xs:dateTime</Type>
<DateQualifiers>
<DateFractions>DateTime</DateFractions>
</DateQualifiers>
</ValueType>
</column>
<column>
<Name xsi:type="xs:string">AddressId</Name>
<ValueType>
<Type>xs:string</Type>
<StringQualifiers>
<Length>150</Length>
<AllowedLength>Variable</AllowedLength>
</StringQualifiers>
</ValueType>
</column>
<column>
<Name xsi:type="xs:string">CompanyId</Name>
<ValueType>
<Type>xs:string</Type>
<StringQualifiers>
<Length>150</Length>
<AllowedLength>Variable</AllowedLength>
</StringQualifiers>
</ValueType>
</column>
<column>
<Name xsi:type="xs:string">OrderDate</Name>
<ValueType>
<Type>xs:dateTime</Type>
<DateQualifiers>
<DateFractions>DateTime</DateFractions>
</DateQualifiers>
</ValueType>
</column>
<column>
<Name xsi:type="xs:string">OrderNumber</Name>
<ValueType>
<Type>xs:string</Type>
<StringQualifiers>
<Length>150</Length>
<AllowedLength>Variable</AllowedLength>
</StringQualifiers>
</ValueType>
</column>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>10234</Value>
<Value>10234</Value>
<Value>2022-01-24T00:00:00</Value>
<Value>WE30395.c17639</Value>
</row>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>52817</Value>
<Value>52817</Value>
<Value>2022-01-24T00:00:00</Value>
<Value>WE30395.c17639</Value>
</row>
<row>
<Value>2022-01-24T00:00:00</Value>
<Value>58259</Value>
<Value>58259</Value>
<Value>2022-01-24T00:00:00</Value>
<Value>WE30395.c17639</Value>
</row>
</ValueTable>
Briefly, the structure can be described as follows
I mean this is how I got it
<table>
<header>
<column1>
<column2>
<column3>
<column4>
<column5>
<header>
<row>
value1
value2
value3
</row>
<row>
value4
value5
</row>
</table>
but it should be like this
<table>
<header>
<column1>
<column2>
<column3>
<column4>
<column5>
</header>
<row>
value1
value2
value3
value4
value5
</row>
</table>
The example is rather confusing because many values are identical and it's hard to see what goes where. It's also not clear if there can be more data elements and if so, what should the result be then.
AFAICT, this produces the expected result for the given example. For clarity, I have omitted the header part, which seems to be working fine.
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes" />
<xsl:template match="/extdata/scheme">
<ValueTable xmlns="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- header -->
<!-- data -->
<xsl:for-each select="data[1]/o/d/r">
<row>
<xsl:variable name="i" select="position()"/>
<xsl:for-each select="//data/o/d/r[$i]/f">
<Value>
<xsl:value-of select="." />
</Value>
</xsl:for-each>
</row>
</xsl:for-each>
</ValueTable>
</xsl:template>
</xsl:stylesheet>

Sort specific xml nodes

In the below XML, I need to sort only a specific segment - attrGroupMany name="allergenRelatedInformation" based on the grand child values. And the rest of the XML should be generated as it is with just this segment sorted.
FDA
BIG 8
So all allergenSpecificationAgency that has "FDA" and allergenSpecificationName has "BIG 8" should come before "FDA" and "TREE_NUTS". Please suggest how to achieve this in XSLT. Thanks.
<ns:MT_TradeItemsExport xmlns:ns="test">
<Header version="2.1">
<CreationDateTime>2017-02-09T14:19:03.566Z</CreationDateTime>
<MessageID>0072745000010_9f9cd85e-6d30-4152-a51f-d8491df45486</MessageID>
</Header>
<Payload>
<ItemRegistration>
<attr name="numberOfServingsPerPackage">4.0</attr>
</ItemRegistration>
<attrGroupMany name="organicClaim">
<row>
<attr name="organicTradeItemCode">2</attr>
<attrMany name="organicClaimAgencyCode">
<value>6</value>
</attrMany>
</row>
</attrGroupMany>
<attrGroupMany name="allergenRelatedInformation">
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AC</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AE</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AF</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AM</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AN</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AP</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AY</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">TREE_NUTS</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">TN</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">UW</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
</attrGroupMany>
</Payload>
You can use xsl:perform-sort or xsl:apply-templates together with xsl:sort, to sort the row children use
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="attrGroupMany[#name ='allergenRelatedInformation']">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="row">
<xsl:sort select="attr[#name = 'allergenSpecificationAgency']"/>
<xsl:sort select="attr[#name = 'allergenSpecificationName']"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:transform>
http://xsltransform.net/ejivdHR

XSL Required: Merging content of next cell based on attribute of the current cell

I have a Table it has two column.
Based on First column's rowmerge and rowspan attribute it should merge the values of next column.
RowMerged attribute is to find out whether cells are merged.
RowSpan attribute is to find-out how many cells are merged.
If Rowspan is 0 then that cells is merged with above one.
In the below example we give input as 5 Rows and it will return 3 row as output.
ie) First two rows are merged into single and the content of second column which is not merged should be copied to the above one.
Concerned main on content of cell not the attribute.
Sample Input:
<Table Name="abc">
<TBODY>
<Row>
<Cell RowMerged="T" RowSpan="2"><Element>ABC</Element></Cell>
<Cell><Element>21</Element></Cell>
</Row>
<Row>
<Cell RowMerged="T" RowSpan="0"></Cell>
<Cell><Element>ABC</Element></Cell>
</Row>
<Row>
<Cell RowMerged="F" RowSpan="1"><Element>PQR</Element></Cell>
<Cell><Element>19</Element></Cell>
</Row>
<Row>
<Cell RowMerged="T" RowSpan="2"><Element>XYZ</Element></Cell>
<Cell><Element>99</Element></Cell>
</Row>
<Row>
<Cell RowMerged="T" RowSpan="0"></Cell>
<Cell><Element>Sample</Element></Cell>
</Row>
</TBODY>
</Table>
Sample Output:
<Table Name="abc">
<TBODY>
<Row>
<Cell RowMerged="F" RowSpan="1"><Element>ABC</Element></Cell>
<Cell><Element>21ABC</Element></Cell>
</Row>
<Row>
<Cell RowMerged="F" RowSpan="1"><Element>PQR</Element></Cell>
<Cell><Element>19</Element></Cell>
</Row>
<Row>
<Cell RowMerged="F" RowSpan="1"><Element>XYZ</Element></Cell>
<Cell><Element>99Sample</Element></Cell>
</Row>
</TBODY>
</Table>
You may try something like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row">
<xsl:variable name="rows" select="Cell[1]/#RowSpan"/>
<xsl:copy>
<Cell RowMerged="F" RowSpan="1">
<xsl:apply-templates select="Cell[1]/*" />
</Cell>
<Cell>
<Element>
<xsl:apply-templates select="Cell[2]/Element/node()" />
<xsl:apply-templates select="following-sibling::Row[position() < $rows]/Cell[2]/Element/node()" />
</Element>
</Cell>
</xsl:copy>
<xsl:apply-templates select="Row[Cell[1][#RowSpan > 0]]" />
</xsl:template>
<xsl:template match="TBODY">
<xsl:apply-templates select="Row[Cell[1][#RowSpan > 0]]" />
</xsl:template>
</xsl:stylesheet>
With following output:
<Table Name="abc">
<Row>
<Cell RowMerged="F" RowSpan="1">
<Element>ABC</Element>
</Cell>
<Cell>
<Element>21ABC</Element>
</Cell>
</Row>
<Row>
<Cell RowMerged="F" RowSpan="1">
<Element>PQR</Element>
</Cell>
<Cell>
<Element>19</Element>
</Cell>
</Row>
<Row>
<Cell RowMerged="F" RowSpan="1">
<Element>XYZ</Element>
</Cell>
<Cell>
<Element>99Sample</Element>
</Cell>
</Row>
</Table>

Issue in integarting two xslt templates rowmerge and tag removal

We have two diffrent scenario we got answers in the forum
Xslt for table content replacement only in Tbody
(We need to retrieve ref tag inside para in Thead We need to remove ref tag inside para in Tbody. For last cell we should not perform this ref removal. ie) should behave like thead)
writing xslt for the below scenario
(Rule: for merged rows: copy content of primary merged cell to other cells in merged rows.)
But while integrating/testing we have a problem. after integrating we are not getting the expected output.ie) Tag removel is done on the first row but in the merged row it is noit heppening.
Could someone help us in this regard.
Sample Input:
<?xml version="1.0" encoding="UTF-8"?>
<TABLE align="CENTER" >
<THEAD editable="T">
<ROW editable="F">
<CELL rowmerged="F" ><Para appdisplaytext=" ">S.No </Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Role</Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment</Para></CELL>
</ROW>
</THEAD>
<TBODY editable="T">
<ROW editable="F">
<CELL rowmerged="T" ><Para appdisplaytext=" "><refint>S.No1 </refint> </Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name1</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" "> <refint>Role1</refint></Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment1</Para> </CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="T" ><Para appdisplaytext=" "></Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name2</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Role2</Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment2</Para> </CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="F" ><Para appdisplaytext=" ">S.No 3</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name3</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" "><refint>Role3</refint></Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment3</Para></CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="F" ><Para appdisplaytext=" ">S.No 4</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name4</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Role4</Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment4</Para></CELL>
</ROW>
</TBODY>
</TABLE>
XSLT Tried:
<?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="no" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="table">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="TBODY/ROW/CELL[position()!=last()]/Para/refint">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="//TABLE//Para[not(normalize-space())][../#rowmerged='T']">
<xsl:variable name="cellnum" select="count(../preceding-sibling::CELL) + 1"/>
<xsl:variable name="matchingCells" select=" ../../preceding-sibling::ROW/CELL[$cellnum]/Para"/>
<xsl:copy-of select="$matchingCells[normalize-space()][last()]"/>
</xsl:template>
</xsl:transform>
Expected Output:
<?xml version="1.0" encoding="UTF-8"?>
<TABLE align="CENTER" >
<THEAD editable="T">
<ROW editable="F">
<CELL rowmerged="F" ><Para appdisplaytext=" ">S.No </Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Role</Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment</Para></CELL>
</ROW>
</THEAD>
<TBODY editable="T">
<ROW editable="F">
<CELL rowmerged="T" ><Para appdisplaytext=" ">S.No1 </Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name1</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Role1</Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment1</Para></CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="T" ><Para appdisplaytext=" ">S.No1 </Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name2</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Role2</Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment2</Para></CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="F" ><Para appdisplaytext=" ">S.No 3</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name3</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Role3</Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment3</Para></CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="F" ><Para appdisplaytext=" ">S.No 4</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Name4</Para></CELL>
<CELL rowmerged="F" ><Para appdisplaytext=" ">Role4</Para></CELL>
<CELL colmerged="F" ><Para appdisplaytext=" " >Comment4</Para></CELL>
</ROW>
</TBODY>
</TABLE>
we got:
<?xml version="1.0" encoding="UTF-8"?>
<TABLE align="CENTER">
<THEAD editable="T">
<ROW editable="F">
<CELL rowmerged="F"><Para appdisplaytext=" ">S.No </Para></CELL>
<CELL rowmerged="F"> <Para appdisplaytext=" ">Name</Para></CELL>
<CELL rowmerged="F"> <Para appdisplaytext=" ">Role</Para></CELL>
<CELL colmerged="F"><Para appdisplaytext=" ">Comment</Para></CELL>
</ROW>
</THEAD>
<TBODY editable="T">
<ROW editable="F">
<CELL rowmerged="T"><Para appdisplaytext=" ">S.No1 </Para></CELL>
<CELL rowmerged="F"><Para appdisplaytext=" ">Name1</Para></CELL>
<CELL rowmerged="F"><Para appdisplaytext=" ">Role1</Para></CELL>
<CELL colmerged="F"><Para appdisplaytext=" ">Comment1</Para></CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="T"><Para appdisplaytext=" "><refint>S.No1 </refint> </Para> </CELL> (We are getting ref int here.)
<CELL rowmerged="F"> <Para appdisplaytext=" ">Name2</Para> </CELL>
<CELL rowmerged="F"> <Para appdisplaytext=" ">Role2</Para> </CELL>
<CELL colmerged="F"> <Para appdisplaytext=" ">Comment2</Para> </CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="F"> <Para appdisplaytext=" ">S.No 3</Para> </CELL>
<CELL rowmerged="F"> <Para appdisplaytext=" ">Name3</Para> </CELL>
<CELL rowmerged="F"> <Para appdisplaytext=" ">Role3</Para> </CELL>
<CELL colmerged="F"> <Para appdisplaytext=" ">Comment3</Para> </CELL>
</ROW>
<ROW editable="F">
<CELL rowmerged="F"> <Para appdisplaytext=" ">S.No 4</Para> </CELL>
<CELL rowmerged="F"> <Para appdisplaytext=" ">Name4</Para> </CELL>
<CELL rowmerged="F"> <Para appdisplaytext=" ">Role4</Para> </CELL>
<CELL colmerged="F"> <Para appdisplaytext=" ">Comment4</Para> </CELL>
</ROW>
</TBODY>
</TABLE>
The issue occurs in this template
<xsl:template match="//TABLE//Para[not(normalize-space())][../#rowmerged='T']">
<xsl:variable name="cellnum" select="count(../preceding-sibling::CELL) + 1"/>
<xsl:variable name="matchingCells" select="../../preceding-sibling::ROW/CELL[$cellnum]/Para"/>
<xsl:copy-of select="$matchingCells[normalize-space()][last()]"/>
</xsl:template>
When you match an "empty" Para element, where rowmerged is "T", then you copy the corresponding Para from the preceding ROW. But because you are using xsl:copy-of this will copy it without any further transformation. xsl:copy-of copies from the input tree, and does not take into account any transformation you may previously done on that node (which is in the output, not the input).
Try using xsl:apply-templates instead:
<xsl:template match="//TABLE//Para[not(normalize-space())][../#rowmerged='T']">
<xsl:variable name="cellnum" select="count(../preceding-sibling::CELL) + 1"/>
<xsl:variable name="matchingCells" select="../../preceding-sibling::ROW/CELL[$cellnum]/Para"/>
<xsl:apply-templates select="$matchingCells[normalize-space()][last()]"/>
</xsl:template>
By using xsl:apply-templates it will apply any transforms on the nodes you are selecting at this point.
EDIT: If you only want to copy the children of the Para node, try this template which copies the Para node being matched, but copies the children from the previous sibling.
<xsl:template match="//TABLE//Para[not(normalize-space())][../#rowmerged='T']">
<xsl:variable name="cellnum" select="count(../preceding-sibling::CELL) + 1"/>
<xsl:variable name="matchingCells" select="../../preceding-sibling::ROW/CELL[$cellnum]/Para"/>
<xsl:copy>
<xsl:apply-templates select="#*" />
<xsl:apply-templates select="$matchingCells[normalize-space()][last()]/node()"/>
</xsl:copy>
</xsl:template>

XSL: Issue with tokenizing in the for loop

I am using the following stylesheet for displaying a table in the excel workbook with the data. I am not able to get the desired result instead it is displaying as differently as given below.
Suggestions Pls?
The stylesheet used:
<xsl:stylesheet>
<xsl:template match="/">
<xsl:variable name="test1" select="str:tokenize('1$,$2$,$3$,$4$,$5','$,$')" />
<xsl:variable name="test2" select="str:tokenize('a$,$b$,$c$,$d$,$e','$,$')" />
<xsl:for-each select="str:split('1a$,$2b$,$3c$,$4d$,$5e','$,$')>
<row>
<cell Index="1">
<xsl:value-of select="$test1[position()]" />
</cell>
<cell Index="2">
<xsl:value-of select="$test2[position()]" />
</cell>
</row>
</xsl:for-each>
</xsl:template>
Expected Result:
1 a
2 b
3 c
4 d
5 e
Where as the result displayed as
a b
c d
e
It seems like the it is displaying the latest tokenize values.
How to get respected values.
Good question, +1.
It seems to me that instead of:
<xsl:value-of select="$test1[position()]" />
this must be:
<xsl:value-of select="$test1[position() = current()]" />
Exactly the same observation holds for the second <xsl:value-of>
Explanation:
Any expression
$var[position()]
is equivalent to:
$var
because position() can only have values >= 1 and [position()] means the boolean value of position() , and the boolean value of any non-negative number by definition is true().
If we want to select the $k-th node in the node-set $var, in XPath 1.0, which is weakly-typed and it isn't known that $k holds an integer, we have to write:
$var[position() = $k]
Here is a complete, corresponding 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 omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="test1" select=
"tokenize('1$,$2$,$3$,$4$,$5','\$,\$')" />
<xsl:variable name="test2" select=
"tokenize('a$,$b$,$c$,$d$,$e','\$,\$')" />
<xsl:for-each select="tokenize('1a$,$2b$,$3c$,$4d$,$5e','\$,\$')">
<row>
<cell Index="1">
<xsl:value-of select="$test1[position()]" />
</cell>
<cell Index="2">
<xsl:value-of select="$test2[position()]" />
</cell>
</row>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied on any XML document (ignored), the wanted, correct result is produced:
<row xmlns:xs="http://www.w3.org/2001/XMLSchema">
<cell Index="1">1 2 3 4 5</cell>
<cell Index="2">a b c d e</cell>
</row>
<row xmlns:xs="http://www.w3.org/2001/XMLSchema">
<cell Index="1">1 2 3 4 5</cell>
<cell Index="2">a b c d e</cell>
</row>
<row xmlns:xs="http://www.w3.org/2001/XMLSchema">
<cell Index="1">1 2 3 4 5</cell>
<cell Index="2">a b c d e</cell>
</row>
<row xmlns:xs="http://www.w3.org/2001/XMLSchema">
<cell Index="1">1 2 3 4 5</cell>
<cell Index="2">a b c d e</cell>
</row>
<row xmlns:xs="http://www.w3.org/2001/XMLSchema">
<cell Index="1">1 2 3 4 5</cell>
<cell Index="2">a b c d e</cell>
</row>