Reputation: 79
I am trying to merge two XML files "a.xml" and "b.xml" into a HTML table using XSLT 1.0. Both files contain elements called "event" that each have a "time" attribute with a dateTime value attached to them. I want the HTML table to be sorted chronologically. Whereas the time attributes of file "a.xml" are formated correctly (CCYY-MM-DDTHH:MM:SS.msmsms), the time attributes of "b.xml" are not (CCYY-DDDTHH:MM:SS.msmsmsZ) and thus I am using some concats and substring functions to construct the correct format for the "time" attributes of the "b.xml" elements. My question is now: How can I use the original "time" attributes of "a.xml" and the corrected attributes of "b.xml" for sorting the rows of the HTML table?
I already tried using parameters for storing the correctly formated "time" attributes. I also tried using node-sets to tackle the issue in two steps (i.e. converting "b.xml" attributes first, saving result and then creating the HTML from the intermediate file), but neither of these two ways worked for me. Lastly I tried sorting the HTML table on load of the page with a JavaScript, but the table is too big for doing it this way on each page load.
I am happy about every hint on a functionality of XSLT that could help me. I have to stick with XSLT1.0, though and can't use XSLT2.0 for this project.
a.xml
<?xml version="1.0" encoding="UTF-8"?>
<data>
<event time="2019-02-03T06:00:00.000"></event>
<event time="2019-02-01T06:00:00.000"></event>
</data>
b.xml before formating
<?xml version="1.0" encoding="UTF-8"?>
<data>
<event time="2019-035T06:00:00.000"></event>
<event time="2019-033T06:00:00.000"></event>
</data>
b.xml after formating
<?xml version="1.0" encoding="UTF-8"?>
<data>
<event time="2019-02-04T06:00:00.000"></event>
<event time="2019-02-02T06:00:00.000"></event>
</data>
current transform.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table>
<xsl:apply-templates select="/Adata/event|document('b.xml')/Bdata/event">
<xsl:sort select="@time"/>
</xsl:apply-templates>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Bdata/event">
<!--Here I have some long operation to change the date format and save it as parameter "correctFormat"-->
<xsl:attribute name="time">
<xsl:value-of select="$correctFormat"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="//event">
<tr>
<td><xsl:value-of select="@time"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
expected output out.html
<html>
<body>
<table>
<tr><td>2019-02-01T06:00:00.000</td></tr>
<tr><td>2019-02-02T06:00:00.000</td></tr>
<tr><td>2019-02-03T06:00:00.000</td></tr>
<tr><td>2019-02-04T06:00:00.000</td></tr>
</table>
</body>
</html>
EDIT
Date conversion code
As requested I share as well my code for the conversion. I am using the exslt dates and time namespace by adding inside the header
<xsl:template match="data/event">
<xsl:param name="daysToAdd" select="concat('P',substring(@time,6,3),'D')"/>
<xsl:param name="startOfYear" select="concat(substring(@time,1,4),'-01-00')"/>
<xsl:param name="formatedDate">
<xsl:call-template name="date:add">
<xsl:with-param name="date-time" select="$startOfYear" />
<xsl:with-param name="duration" select="$daysToAdd" />
</xsl:call-template>
<xsl:value-of select="substring(@time,9,13)"/>
</xsl:param>
<xsl:copy>
<xsl:attribute name="time">
<xsl:value-of select="$formatedDate"/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
Upvotes: 1
Views: 97
Reputation: 117003
Consider the following example (minimized to the problem presented in your question):
XML
<data>
<event time="2019-02-03T06:00:00.000"></event>
<event time="2019-02-01T06:00:00.000"></event>
</data>
b.xml
<data>
<event time="2019-035T06:00:00.000"></event>
<event time="2019-033T06:00:00.000"></event>
</data>
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="*"/>
<xsl:template match="/data">
<!-- CONVERT B -->
<xsl:variable name="b">
<xsl:for-each select="document('b.xml')/data/event">
<xsl:copy>
<xsl:attribute name="time">
<!-- the missing conversion part goes here -->
</xsl:attribute>
</xsl:copy>
</xsl:for-each>
</xsl:variable>
<!-- OUTPUT -->
<xsl:copy>
<xsl:for-each select="event | exsl:node-set($b)/event">
<xsl:sort select="@time" data-type="text" order="ascending"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<data>
<event time="2019-02-01T06:00:00.000"/>
<event time="2019-02-02T06:00:00.000"/>
<event time="2019-02-03T06:00:00.000"/>
<event time="2019-02-04T06:00:00.000"/>
</data>
Upvotes: 2