Search code examples
xmlxslttabulate

XLS Transformation from XML in particular table order


I have the XML file below for which I'm trying to create a XSLT template to tabulate some nodes. May someone could help me out please.

<Main>
    <Document>Doc.1</Document>
    <Cini>DDFR</Cini>
    <List>
        <SubList>
            <CdTa>ABC</CdTa>
            <NN>XYZ</NN>
            <ND>
                <RiS>
                    <RiN>
                        <NSE14>
                            <MNRs>
                                <MRD>
                                    <NR>
                                        <N1>393</N1>
                                        <N2>720</N2>
                                        <SNR>
                                            <NR_i>203</NR_i>
                                            <NR_f>49994</NR_f>
                                        </SNR>
                                    </NR>
                                </MRD>
                                <MRD>
                                    <NR>
                                        <N1>687</N1>
                                        <N2>345</N2>
                                        <SNR>
                                            <NR_i>55005</NR_i>
                                            <NR_f>1229996</NR_f>
                                        </SNR>
                                    </NR>
                                </MRD>
                            </MNRs>
                            <GNRs>
                                <RD>
                                    <NR>
                                        <N1>649</N1>
                                        <N2>111</N2>
                                        <SNR>
                                            <NR_i>55400</NR_i>
                                            <NR_f>877</NR_f>
                                        </SNR>
                                    </NR>
                                </RD>
                            </GNRs>
                            <MSNRs>
                                <NR>
                                    <N1>748</N1>
                                    <N2>5624</N2>
                                    <SNR>
                                        <NR_i>8746</NR_i>
                                        <NR_f>7773</NR_f>
                                    </SNR>
                                </NR>
                                <NR>
                                    <N1>124</N1>
                                    <N2>54</N2>
                                    <SNR>
                                        <NR_i>8847</NR_i>
                                        <NR_f>5526</NR_f>
                                    </SNR>
                                </NR>
                            </MSNRs>
                        </NSE14>
                        <NSE12>
                            <MBB>990</MBB>
                            <MRB>123</MRB>
                        </NSE12>
                        <MGE13>
                            <TBB>849</TBB>
                            <TRB>113</TRB>
                        </MGE13>
                    </RiN>
                </RiS>
            </ND>
        </SubList>
    </List>
</Main>

And this XSLT code

<?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 border="1">
<tr bgcolor="#FFF833">
      <th style="text-align:left">MNRs</th>
      <th style="text-align:left">GNRs</th>
      <th style="text-align:left">MSNRs</th>
</tr>
    <tr bgcolor="#9acd32">
      <th style="text-align:left">N1</th>
      <th style="text-align:left">N2</th>
      <th style="text-align:left">NR_i</th>
      <th style="text-align:left">NR_f</th>
      <th style="text-align:left">N1</th>
      <th style="text-align:left">N2</th>
      <th style="text-align:left">NR_i</th>
      <th style="text-align:left">NR_f</th>
      <th style="text-align:left">N1</th>
      <th style="text-align:left">N2</th>
      <th style="text-align:left">NR_i</th>
      <th style="text-align:left">NR_f</th>
    </tr>

    <xsl:for-each select="//MNRs//NR">
    <tr>
      <td><xsl:value-of select="N1"/></td>
      <td><xsl:value-of select="N2"/></td>
      <xsl:for-each select="SNR">
          <td><xsl:value-of select="NR_i"/></td>
          <td><xsl:value-of select="NR_f"/></td>
      </xsl:for-each>
    </xsl:for-each>

    <xsl:for-each select="//GNRs//NR">
      <td><xsl:value-of select="N1"/></td>
      <td><xsl:value-of select="N2"/></td>
      <xsl:for-each select="SNR">
          <td><xsl:value-of select="NR_i"/></td>
          <td><xsl:value-of select="NR_f"/></td>
      </xsl:for-each>
    </xsl:for-each>

    <xsl:for-each select="//MSNRs//NR">
      <td><xsl:value-of select="N1"/></td>
      <td><xsl:value-of select="N2"/></td>
      <xsl:for-each select="SNR">
          <td><xsl:value-of select="NR_i"/></td>
          <td><xsl:value-of select="NR_f"/></td>
      </xsl:for-each>
    </tr>
    </xsl:for-each>
  </table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Whit the current XSLT code I'm getting this output that is not the structure I woul like to obtain since I'm only getting some values. The thing is there are 3 parents nodes with the same children names. The parent nodes are MNRs, GNRs and MSNRs

+------+------+-------+---------+----+----+------+------+----+----+------+------+
| MNRs | GNRs | MSNRs |         |    |    |      |      |    |    |      |      |
+------+------+-------+---------+----+----+------+------+----+----+------+------+
| N1   | N2   | NR_i  | NR_f    | N1 | N2 | NR_i | NR_f | N1 | N2 | NR_i | NR_f |
+------+------+-------+---------+----+----+------+------+----+----+------+------+
| 393  | 720  | 203   | 49994   |    |    |      |      |    |    |      |      |
+------+------+-------+---------+----+----+------+------+----+----+------+------+
| 687  | 345  | 55005 | 1229996 |    |    |      |      |    |    |      |      |
+------+------+-------+---------+----+----+------+------+----+----+------+------+

And I would like to get this output:

+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+
|             MNRs              |          GNRs            |           MSNRs          |
+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+
| N1   | N2   | NR_i  | NR_f    | N1  | N2  | NR_i  | NR_f | N1  | N2   | NR_i | NR_f |
+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+
| 393  | 720  | 203   | 49994   | 649 | 111 | 55400 | 877  | 748 | 5624 | 8746 | 7773 |
+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+
| 687  | 345  | 55005 | 1229996 |     |     |       |      | 124 | 54   | 8847 | 5526 |
+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+ 

Thanks for any help.


Solution

  • This is not at all trivial, esp. in XSLT 1.0. I would suggest you try it this way:

    XSL 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:template match="/">
        <html> 
            <body>
                <table border="1" width="80%">
                    <!-- header -->
                    <tr>
                        <th colspan="4">MNRs</th>
                        <th colspan="4">GNRs</th>
                        <th colspan="4">MSNRs</th>
                    </tr>
                    <tr>
                        <!-- MNRs -->
                        <th>N1</th>
                        <th>N2</th>
                        <th>NR_i</th>
                        <th>NR_f</th>
                        <!-- GNRs -->
                        <th>N1</th>
                        <th>N2</th>
                        <th>NR_i</th>
                        <th>NR_f</th>
                        <!-- MSNRs -->
                        <th>N1</th>
                        <th>N2</th>
                        <th>NR_i</th>
                        <th>NR_f</th>
                    </tr>
                    <!-- data -->
                    <xsl:call-template name="rows">
                        <xsl:with-param name="MNRs" select="//MNRs//NR"/>
                        <xsl:with-param name="GNRs" select="//GNRs//NR"/>
                        <xsl:with-param name="MSNRs" select="//MSNRs//NR"/>
                    </xsl:call-template>
                </table>
            </body>
        </html>     
    </xsl:template>
    
    <xsl:template name="rows">
        <xsl:param name="MNRs"/>
        <xsl:param name="GNRs"/>
        <xsl:param name="MSNRs"/>
        <xsl:param name="i" select="1"/>
        <xsl:if test="$MNRs[$i] or $GNRs[$i] or $MSNRs[$i]">
            <tr>
                <!-- MNRs -->
                <td>
                    <xsl:value-of select="$MNRs[$i]/N1"/>
                </td>
                <td>
                    <xsl:value-of select="$MNRs[$i]/N2"/>
                </td>
                <td>
                    <xsl:value-of select="$MNRs[$i]/SNR/NR_i"/>
                </td>
                <td>
                    <xsl:value-of select="$MNRs[$i]/SNR/NR_f"/>
                </td>
                <!-- GNRs -->
                <td>
                    <xsl:value-of select="$GNRs[$i]/N1"/>
                </td>
                <td>
                    <xsl:value-of select="$GNRs[$i]/N2"/>
                </td>
                <td>
                    <xsl:value-of select="$GNRs[$i]/SNR/NR_i"/>
                </td>
                <td>
                    <xsl:value-of select="$GNRs[$i]/SNR/NR_f"/>
                </td>
                <!-- MSNRs -->
                <td>
                    <xsl:value-of select="$MSNRs[$i]/N1"/>
                </td>
                <td>
                    <xsl:value-of select="$MSNRs[$i]/N2"/>
                </td>
                <td>
                    <xsl:value-of select="$MSNRs[$i]/SNR/NR_i"/>
                </td>
                <td>
                    <xsl:value-of select="$MSNRs[$i]/SNR/NR_f"/>
                </td>
            </tr>
            <!-- recursive call -->
            <xsl:call-template name="rows">     
                <xsl:with-param name="MNRs" select="$MNRs"/>
                <xsl:with-param name="GNRs" select="$GNRs"/>
                <xsl:with-param name="MSNRs" select="$MSNRs"/>
                <xsl:with-param name="i" select="$i + 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    
    </xsl:stylesheet>
    

    When applied to your example input, the result will be:

    Result

    <html>
    <body>
    <table border="1" width="80%">
    <tr>
    <th colspan="4">MNRs</th>
    <th colspan="4">GNRs</th>
    <th colspan="4">MSNRs</th>
    </tr>
    <tr>
    <th>N1</th>
    <th>N2</th>
    <th>NR_i</th>
    <th>NR_f</th>
    <th>N1</th>
    <th>N2</th>
    <th>NR_i</th>
    <th>NR_f</th>
    <th>N1</th>
    <th>N2</th>
    <th>NR_i</th>
    <th>NR_f</th>
    </tr>
    <tr>
    <td>393</td>
    <td>720</td>
    <td>203</td>
    <td>49994</td>
    <td>649</td>
    <td>111</td>
    <td>55400</td>
    <td>877</td>
    <td>748</td>
    <td>5624</td>
    <td>8746</td>
    <td>7773</td>
    </tr>
    <tr>
    <td>687</td>
    <td>345</td>
    <td>55005</td>
    <td>1229996</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td>124</td>
    <td>54</td>
    <td>8847</td>
    <td>5526</td>
    </tr>
    </table>
    </body>
    </html>
    

    rendered as:

    enter image description here