Reputation: 35
Newbie to xslt. I have a xml file which cannot be changed and looks like the below. id attribute will exist in all elements, but the other variables may or may not exist. Any help to approach representing this in xslt is greatly appreciated! Thanks!
<A>
<B>
<att id="1" var1="ABC" var2="DEF" />
<att id="2" var2="FGD" />
<att id="3" var1="ABC" var3="KQR" />
</B>
<C>
<att id="5" var1="ABC" var2="DEF" />
<att id="8" var3="FGD" />
<att id="9" var1="ABC" var4="KQR" />
</C>
<D>
<att id="11" var1="ABC" var2="DEF" />
<att id="13" var5="FGD" var6="TRE" />
<att id="14" var1="ABC" var3="KQR" />
</D>
</A>
I would like to create HTML tables that looks like the below:
A (Header)
B (Sub-Header)
--------------------------
|ID | Var1 | Var2 | Var3 |
|1 | ABC | DEF | |
|2 | | FGD | |
|3 | ABC | | KQR |
--------------------------
C (Sub-Header)
---------------------------------
|ID | Var1 | Var2 | Var3 | Var4 |
|5 | ABC | DEF | |
|8 | | | FGD | |
|9 | ABC | | | KQR |
---------------------------------
D (Sub-Header)
----------------------------------------
|ID | Var1 | Var2 | Var3 | Var5 | Var6 |
|11 | ABC | DEF | | | |
|13 | | | | FGD | TRE |
|14 | ABC | | KQR | | |
----------------------------------------
Upvotes: 1
Views: 193
Reputation: 407
Wow, tricky one... grouping in XSLT 1.0 (as the question was tagged) within a scope and on attribute names.
Something like this seems to work...
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:key name="kAttsByGrandparent" match="@*[not(local-name() = 'id')]" use="generate-id(ancestor::*[2])"/>
<xsl:key name="kDistinctAttsByGrandparent" match="@*[not(local-name() = 'id')]" use="concat(generate-id(ancestor::*[2]), '||', local-name())"/>
<xsl:key name="distinct" match="att" use="."/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="*">
<h1>
<xsl:value-of select="local-name()"/>
</h1>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*[att]">
<h1>
<xsl:value-of select="local-name()"/>
</h1>
<xsl:variable name="vGrandparentId" select="generate-id()"/>
<xsl:variable name="vDistinctAttNames" select="key('kAttsByGrandparent', $vGrandparentId)[generate-id() = generate-id(key('kDistinctAttsByGrandparent', concat($vGrandparentId, '||', local-name()))[1])]"/>
<table border="1">
<!-- header row -->
<tr>
<th>
<xsl:text>ID</xsl:text>
</th>
<xsl:for-each select="$vDistinctAttNames">
<xsl:sort select="local-name()"/>
<th>
<xsl:value-of select="local-name()"/>
</th>
</xsl:for-each>
</tr>
<xsl:apply-templates select="att">
<xsl:with-param name="pDistinctAttNames" select="$vDistinctAttNames"/>
</xsl:apply-templates>
</table>
<xsl:apply-templates select="*[not(local-name() = 'att')]"/>
</xsl:template>
<xsl:template match="att">
<xsl:param name="pDistinctAttNames"/>
<tr>
<td>
<xsl:value-of select="@id"/>
</td>
<xsl:variable name="vThisElement" select="."/>
<xsl:for-each select="$pDistinctAttNames">
<xsl:sort select="local-name()"/>
<td>
<xsl:variable name="vAttName" select="local-name()"/>
<xsl:value-of select="$vThisElement/@*[local-name() = $vAttName]"/>
</td>
</xsl:for-each>
</tr>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 372
I did go with https://www.w3schools.com/xml/tryxslt.asp online and xsltproc
on cli.
XSLT-File
<?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>
<h1>A</h1>
<h2>B</h2>
<table border="1">
<tr><th>id</th><th>var1</th><th>var2</th><th>var3</th></tr>
<xsl:for-each select="/A/B/att">
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="@var1"/></td>
<td><xsl:value-of select="@var2"/></td>
<td><xsl:value-of select="@var3"/></td>
</tr>
</xsl:for-each>
</table>
<h2>C</h2>
<table border="1">
<tr><th>id</th><th>var1</th><th>var2</th><th>var3</th><th>var4</th></tr>
<xsl:for-each select="/A/C/att">
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="@var1"/></td>
<td><xsl:value-of select="@var2"/></td>
<td><xsl:value-of select="@var3"/></td>
<td><xsl:value-of select="@var4"/></td>
</tr>
</xsl:for-each>
</table>
<h2>D</h2>
<table border="1">
<tr><th>id</th><th>var1</th><th>var2</th><th>var3</th><th>var5</th><th>var6</th></tr>
<xsl:for-each select="/A/D/att">
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="@var1"/></td>
<td><xsl:value-of select="@var2"/></td>
<td><xsl:value-of select="@var3"/></td>
<td><xsl:value-of select="@var5"/></td>
<td><xsl:value-of select="@var6"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
You can call it e.g. xsltproc template.xslt data.xml
.
Upvotes: 0