I'm trying to produce a XML file with a certain structure but I'm stuck,
This is my input XML file:
<report>
<page name="Simple MasterPage">
<table id="__bookmark_1">
<table-band band-type="BAND_HEADER">
<row>
<cell>
<label>PERSONNAME</label>
</cell>
<cell>
<label>PERSONID</label>
</cell>
<cell>
<label>NUMELEM</label>
</cell>
<cell>
<label>CREATIONDATE</label>
</cell>
<cell>
<label>CREATIONDATE</label>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>1</data>
</cell>
<cell>
<data>2018-06-21</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>2</data>
</cell>
<cell>
<data>2018-06-21</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>3</data>
</cell>
<cell>
<data>2018-06-21</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>4</data>
</cell>
<cell>
<data>2018-06-21</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>5</data>
</cell>
<cell>
<data>2018-06-21</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>Marie</data>
</cell>
<cell>
<data>p2</data>
</cell>
<cell>
<data>6</data>
</cell>
<cell>
<data>2018-06-21</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>Marie</data>
</cell>
<cell>
<data>p2</data>
</cell>
<cell>
<data>7</data>
</cell>
<cell>
<data>2018-06-21</data>
</cell>
</row>
</table-band>
</table>
</page>
</report>
This is the XSLT I'm using to transform it, that user @Parfait teached me how to build on a very similar post:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" omit-xml-declaration="no" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/report/page/table">
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" versao="1.0">
<!--Para comecar da 2 tabela-->
<xsl:apply-templates select="table-band[position() > 1] "/>
</entry>
</xsl:template>
<xsl:template name="top_build-attrib">
<xsl:param name="label_val"/>
<xsl:param name="attrib_nm"/>
<xsl:variable name="row_num" select="count(table-band[1]/row/cell[label=$label_val]/preceding-sibling::*)+1"/>
<xsl:attribute name="{$attrib_nm}"><xsl:value-of select="table-band[2]/row/cell[position()=$row_num]/data"/></xsl:attribute>
</xsl:template>
<xsl:template name="build-attrib">
<xsl:param name="label_val"/>
<xsl:param name="attrib_nm"/>
<xsl:variable name="row_num" select="count(ancestor::table/table-band[1]/row/cell[label=$label_val]/preceding-sibling::*)+1"/>
<xsl:attribute name="{$attrib_nm}"><xsl:value-of select="row/cell[position()=$row_num]/data"/></xsl:attribute>
</xsl:template>
<xsl:template name="elem_value">
<xsl:param name="label_val"/>
<xsl:variable name="row_num" select="count(ancestor::table/table-band[1]/row/cell[label=$label_val]/preceding-sibling::*)+1"/>
<xsl:value-of select="row/cell[position()=$row_num]/data"/>
</xsl:template>
<xsl:template match="table-band">
<person>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONNAME</xsl:with-param>
<xsl:with-param name="attrib_nm">personName</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONID</xsl:with-param>
<xsl:with-param name="attrib_nm">personID</xsl:with-param>
</xsl:call-template>
<listOfElements>
<element>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">NUMELEM</xsl:with-param>
<xsl:with-param name="attrib_nm">numElem</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">CREATIONDATE</xsl:with-param>
<xsl:with-param name="attrib_nm">creationDate</xsl:with-param>
</xsl:call-template>
</element>
</listOfElements>
</person>
</xsl:template>
</xsl:stylesheet>
And this this the result I get:
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" versao="1.0">
<person personID="p1" personName="John">
<listOfElements>
<element creationDate="2018-06-21" numElem="1"/>
</listOfElements>
</person>
<person personID="p1" personName="John">
<listOfElements>
<element creationDate="2018-06-21" numElem="2"/>
</listOfElements>
</person>
<person personID="p1" personName="John">
<listOfElements>
<element creationDate="2018-06-21" numElem="3"/>
</listOfElements>
</person>
<person personID="p1" personName="John">
<listOfElements>
<element creationDate="2018-06-21" numElem="4"/>
</listOfElements>
</person>
<person personID="p1" personName="John">
<listOfElements>
<element creationDate="2018-06-21" numElem="5"/>
</listOfElements>
</person>
<person personID="p2" personName="Marie">
<listOfElements>
<element creationDate="2018-06-21" numElem="6"/>
</listOfElements>
</person>
<person personID="p2" personName="Marie">
<listOfElements>
<element creationDate="2018-06-21" numElem="7"/>
</listOfElements>
</person>
</entry>
But the result I'm looking for and that am required to prodocue is this one:
<?xml version="1.0" encoding="utf-8"?>
<entry>
<person personID="p1" personName="John">
<listOfElements>
<element creationDate="2018-06-21" numElem="1" />
<element creationDate="2018-06-21" numElem="2" />
<element creationDate="2018-06-21" numElem="3" />
<element creationDate="2018-06-21" numElem="4" />
<element creationDate="2018-06-21" numElem="5"/>
</listOfElements>
</person>
<person personID="p2" personName="Marie">
<listOfElements>
<element creationDate="2018-06-21" numElem="6" />
<element creationDate="2018-06-21" numElem="7" />
</listOfElements>
</person>
</entry>
Meaning that the I'm not being able to produce the listOfElements
like I should, I'm printing a new person
node instead of "joining" the element
nodes in the same person
node (inside the listOfElements
node)
I know that the solution must have something to do with comparing the presonID
or personName
attributes, but I'm just not getting there...
I really need some help guys, thank you!
EDIT
I tried addin the xsl:for-each-group
before each element
tag but I still get the same result. Did the following:
<listOfElements>
<xsl:for-each-group select="table-band[@band-type='BAND_DETAIL']/row" group-by="cell[2]/data">
<element>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">NUMELEM</xsl:with-param>
<xsl:with-param name="attrib_nm">numElem</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">CREATIONDATE</xsl:with-param>
<xsl:with-param name="attrib_nm">creationDate</xsl:with-param>
</xsl:call-template>
</element>
</xsl:for-each-group>
</listOfElements>
EDIT I changed the input xml and output, meaning that the input xml lost the NUMDOC and CREATIONDATE elements, and gained a new one, ELEMENTTYPE,
So, I lost the grouping factor I used in the inner for-each-group
, that was NUMDOC
, like @Parfait teached me. Now I don't know how to group the elements with only having the ELEMENTTYPE
. Note that I want to be able to have, for the same person, different elements with the same ELEMENTTYPE
, so this can't be use for the factor in the for-each-group
, or can it?
INPUT XML:(UPDATED)
<report>
<page name="Simple MasterPage">
<table id="__bookmark_1">
<table-band band-type="BAND_HEADER">
<row>
<cell>
<label>PERSONNAME</label>
</cell>
<cell>
<label>PERSONID</label>
</cell>
<cell>
<label>ELEMENTTYPE</label>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>001</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>001</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>002</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>001</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>John</data>
</cell>
<cell>
<data>p1</data>
</cell>
<cell>
<data>002</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>Marie</data>
</cell>
<cell>
<data>p2</data>
</cell>
<cell>
<data>001</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>Marie</data>
</cell>
<cell>
<data>p2</data>
</cell>
<cell>
<data>001</data>
</cell>
</row>
</table-band>
</table>
</page>
</report>
So the output I wanna get is:
<?xml version="1.0" encoding="utf-8"?>
<entry>
<person personID="p1" personName="John">
<listOfElements>
<element elementType="001" />
<element elementType="001" />
<element elementType="002" />
<element elementType="001" />
<element elementType="002" />
</listOfElements>
</person>
<person personID="p2" personName="Marie">
<listOfElements>
<element elementType="001" />
<element elementType="001" />
</listOfElements>
</person>
</entry>
I don't know what to use in the inner for-each-group
, before , like @Parfait showed me, I used NUMDOC
, but now I don't have anything to distinguish between docs!
Thanks!
Alexandre Jacinto
Consider applyling a two-layered
<xsl:for-each-group>
in your last template of current XSLT, pointing to the PERSONNAME and NUMELEM corresponding position in first<table-band>
:XSLT Fiddle Demo
Here is a minimal stylesheet incorporating my suggestion made in a comment (with the grouping key adjusted to take the data value from the second cell):
At https://xsltfiddle.liberty-development.net/bdxtq7 where Saxon 9.8 HE is used the result for your sample is