Reputation: 1824
Situation
I got a data structure like this:
<datanodes>
<data>
<id>1</id>
<dataEntries>
<dataEntry>
<name>start_date</name>
<entryValue>01-02-2020</entryValue>
</dataEntry>
<dataEntry>
<name>boarding_date</name>
<entryValue>15-02-2020</entryValue>
</dataEntry>
</dataEntries>
</data>
<data>
<id>2</id>
<dataEntries>
<dataEntry>
<name>start_date</name>
<entryValue>02-03-2020</entryValue>
</dataEntry>
<dataEntry>
<name>departure_date</name>
<entryValue>15-03-2020</entryValue>
</dataEntry>
</dataEntries>
</data>
</datanodes>
The plan is to build up a structure that has the buildup of a csv file a 'la
<table>
<row>
<col>1</col>
<col>01-02-2020</col>
<col>15-02-2020</col>
<col></col>
</row>
<row>
<col>2</col>
<col>02-03-2020</col>
<col></col>
<col>15-03-2020</col>
</row>
</table>
what i have at the moment builds up the header correctly by looping through all nodes and putting the distinct names of the data entries into a variable, and then print the names into a col list:
<xsl:variable name="headers" select="distinct-values(//name/.)" />
<xsl:for-each select="$headers">
<col><xsl:value-of select="current()"/></col>
</xsl:for-each>
Then i also can get the correct values out of the nodes matching the name via a xpath lookup
<xsl:for-each select="data">
<col><xsl:value-of select="dataEntries/dataEntry[contains(name, 'start_date')]/entryValue" /></col>
</xsl:for-each>
but since i want to keep the datastructure flexible i want to loop through the collected data entries in the variable and, if it exists in the current node print the value, otherwise print an empty tag
My idea for this was to loop through the variable, check if a node with the given name exists in the current data and if it does copy the data, otherwise just print an empty col tag.
Here is what io got so far:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="headers" select="distinct-values(//name/.)"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="datanodes">
<table>
<row>
<xsl:for-each select="$headers">
<col>
<xsl:value-of select="current()"/>
</col>
</xsl:for-each>
</row>
<xsl:for-each select="data">
<row>
<col>
<xsl:value-of select="id"/>
</col>
<xsl:for-each select="$headers">
<xsl:choose>
<xsl:when test="dataEntries/dataEntry/current()">
<col>
<xsl:value-of select="dataEntries/dataEntry[contains(name, current())]/entryValue"/>
</col>
</xsl:when>
<xsl:otherwise>
<col/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</row>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Problem
the second for-each loop i use seems to be in another scope so i cannot access the node from the outer for-each loop
even if i try:
<xsl:for-each select="$headers">
<xsl:value-of select="dataEntries/dataEntry[contains(name, 'start_date')]/entryValue"/>
</xsl:for-each>
instead of
<xsl:for-each select="$headers">
<xsl:choose>
<xsl:when test="dataEntries/dataEntry/current()">
<col>
<xsl:value-of select="dataEntries/dataEntry[contains(name, current())]/entryValue"/>
</col>
</xsl:when>
<xsl:otherwise>
<col/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
it cannot find the node. When i move it outside the for-each however the node can be found without a problem
Upvotes: 0
Views: 48
Reputation: 116993
Ty it this way?
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="/datanodes">
<xsl:variable name="headers" select="distinct-values(//name)"/>
<table>
<!-- header -->
<row>
<col>id</col>
<xsl:for-each select="$headers">
<col>
<xsl:value-of select="current()"/>
</col>
</xsl:for-each>
</row>
<!-- data -->
<xsl:for-each select="data">
<xsl:variable name="data" select="dataEntries"/>
<row>
<col>
<xsl:value-of select="id"/>
</col>
<xsl:for-each select="$headers">
<col>
<xsl:value-of select="$data/dataEntry[name=current()]/entryValue"/>
</col>
</xsl:for-each>
</row>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Or, a bit more elegant:
<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:key name="data" match="dataEntry" use="name" />
<xsl:template match="/datanodes">
<xsl:variable name="headers" select="distinct-values(//name)"/>
<table>
<!-- header -->
<row>
<col>id</col>
<xsl:for-each select="$headers">
<col>
<xsl:value-of select="current()"/>
</col>
</xsl:for-each>
</row>
<!-- data -->
<xsl:for-each select="data">
<xsl:variable name="data" select="dataEntries"/>
<row>
<col>
<xsl:value-of select="id"/>
</col>
<xsl:for-each select="$headers">
<col>
<xsl:value-of select="key('data', ., $data)/entryValue"/>
</col>
</xsl:for-each>
</row>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1