Snath
Snath

Reputation: 35

xsl help for html table

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

Answers (2)

Marrow父
Marrow父

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

vv01f
vv01f

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

Related Questions