Search

Hi all,

I have following XML, and I need to display a table with the contents. I hope sb can help me.

<friends>
<table name="Me">
  <column name="ID">1</column>
  <column name="Name">Doe</column>
  <column name="FName">John</column>
</table>
<table name="Friends">
  <column name="ID">1</column>
  <column name="Name">Doe</column>
  <column name="FName">Jane</column>
  <column name="email">jane at doe.com</column>
</table>
<table name="Friends">
  <column name="ID">2</column>
  <column name="Name">Doe</column>
  <column name="FName">Mike</column>
  <column name="email">mike at doe.com</column>
</table>
</friends>

The result should look like this

<h1>Me</h1>
<table>
<tr><th>ID</th><th>Name</th><th>FName</th></tr>
<tr><td>1</td><td>Doe</td><td>John</td></tr>
</table>
<h1>Friends</h1>
<table>
<tr><th>ID</th><th>Name</th><th>FName</th><th>email</th></tr>
<tr><td>1</td><td>Doe</td><td>Jane</td><td>jane at doe.com</td></tr>
<tr><td>2</td><td>Doe</td><td>Mike</td><td>mike at doe.com</td></tr>
</table>

My approach:

  <xsl:key 
    name="col-by-Name" 
    match="Column" 
    use="@Name" 
  />

  <xsl:key 
    name="tab-by-Name" 
    match="Table" 
    use="@Name" 
  />

<xsl:template match="/data/friends">
<ul>
<!-- distinct table names -->

    <xsl:for-each select="
      Table[
        count(
          . | key('tab-by-Name', @Name)[1]
        ) = 1
      ]
    ">
    <li>
      <xsl:value-of select="@Name"/>
      <xsl:value-of select="' - '"/>
      <!-- simple: the item count is the node count of the key -->
      <xsl:value-of select="
        count(
          key('tab-by-Name', @Name)
        )
      "/>
      <xsl:variable name="current" select="@Name" />
      <ul>
      <xsl:value-of select="'&#10;'"/>
      <xsl:variable name="endheader" select="false" />
      <xsl:for-each select="../Table [@Name = $current]/*">
        <xsl:if test="position() = 1 and @Name = 'ID'">&lt;ul&gt;</xsl:if> 
        <xsl:if test="position() &gt; 1 and @Name = 'ID'">&lt;/ul&gt;&lt;ul&gt;</xsl:if>
        <li><xsl:value-of select="@Name" /> : <xsl:value-of select="." /></li>
        <xsl:if test="position()=last()">&lt;/ul&gt;</xsl:if>
      </xsl:for-each>
      </ul>
    </li>
    </xsl:for-each>
</ul>
</xsl:template>

But this is only an apporach as it is far from a table.

If sb could help me, how to get

  1. the headings (@Name)
  2. the table data (values)

Thanks for your help in advance.

The last - how can i put in above xsl in the xsl-if:

'<ul>' instead of &lt;ul&gt; 

?

@tirili - Try this. I’m using the Muenchian Method for grouping.

Here’s your XML…

<?xml version="1.0" encoding="UTF-8"?>
<friends>
    <table name="Me">
        <column name="ID">1</column>
        <column name="Name">Doe</column>
        <column name="FName">John</column>
    </table>
    <table name="Friends">
        <column name="ID">1</column>
        <column name="Name">Doe</column>
        <column name="FName">Jane</column>
        <column name="Email">jane at doe.com</column>
    </table>
    <table name="Friends">
        <column name="ID">2</column>
        <column name="Name">Doe</column>
        <column name="FName">Mike</column>
        <column name="Email">mike at doe.com</column>
    </table>
</friends>

Here’s the XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
    <xsl:key name="table-rows" match="table" use="@name"/>
    <xsl:template match="/">
        <xsl:apply-templates select="friends/table[count(.|key('table-rows',@name)[1])=1]" mode="group"></xsl:apply-templates>
    </xsl:template>
    <xsl:template match="table" mode="group">
        <h2>
            <xsl:value-of select="@name"/>
        </h2>
        <table>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Fname</th>
                <th>Email</th>
            </tr>
            <xsl:apply-templates select="key('table-rows',@name)" mode="item"/>
        </table>
    </xsl:template>
    <xsl:template match="table" mode="item">
        <tr>
            <xsl:apply-templates select="column"/>
        </tr>
    </xsl:template>
    <xsl:template match="column">
        <td><xsl:value-of select="."/></td>
    </xsl:template>
</xsl:stylesheet>

Here’s the output…

<h2>Me</h2>
<table>
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Fname</th>
    <th>Email</th>
  </tr>
  <tr>
    <td>1</td>
    <td>Doe</td>
    <td>John</td>
  </tr>
</table>
<h2>Friends</h2>
<table>
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Fname</th>
    <th>Email</th>
  </tr>
  <tr>
    <td>1</td>
    <td>Doe</td>
    <td>Jane</td>
    <td>jane at doe.com</td>
  </tr>
  <tr>
    <td>2</td>
    <td>Doe</td>
    <td>Mike</td>
    <td>mike at doe.com</td>
  </tr>
</table>

Thanks for the hint. But how can I produce the headings automatically from the @name attribute? What if I have different counts of “column”? As you see, in first we do not have the column “email”.

Got it! Sorry about that. Try this…

XML

<?xml version="1.0" encoding="UTF-8"?>
<friends>
    <table name="Me">
        <column name="ID">1</column>
        <column name="Name">Doe</column>
        <column name="FName">John</column>
    </table>
    <table name="Friends">
        <column name="ID">1</column>
        <column name="Name">Doe</column>
        <column name="FName">Jane</column>
        <column name="Email">jane at doe.com</column>
    </table>
    <table name="Friends">
        <column name="ID">2</column>
        <column name="Name">Doe</column>
        <column name="FName">Mike</column>
        <column name="Email">mike at doe.com</column>
    </table>
</friends>

XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
    <xsl:key name="table-rows" match="table" use="@name"/>

    <xsl:template match="/">
        <xsl:apply-templates select="friends/table[count(.|key('table-rows',@name)[1])=1]" mode="group"/>
    </xsl:template>
    <xsl:template match="table" mode="group">
        <xsl:param name="table-name" select="@name"/>
        <h2>
            <xsl:value-of select="@name"/>
        </h2>
        <table>
            <tr>
                <xsl:apply-templates select="column[../@name=$table-name]" mode="row-header-item"></xsl:apply-templates>
            </tr>
            <xsl:apply-templates select="key('table-rows',@name)" mode="item"/>
        </table>
    </xsl:template>
    <xsl:template match="table" mode="item">
        <tr>
            <xsl:apply-templates select="column" mode="detail"/>
        </tr>
    </xsl:template>

    <xsl:template match="column" mode="row-header-item">
        <th><xsl:value-of select="@name"/></th>
    </xsl:template>
    <xsl:template match="column" mode="detail">
        <td><xsl:value-of select="."/></td>
    </xsl:template>
</xsl:stylesheet>

Output

<h2>Me</h2>
<table>
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>FName</th>
  </tr>
  <tr>
    <td>1</td>
    <td>Doe</td>
    <td>John</td>
  </tr>
</table>
<h2>Friends</h2>
<table>
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>FName</th>
    <th>Email</th>
  </tr>
  <tr>
    <td>1</td>
    <td>Doe</td>
    <td>Jane</td>
    <td>jane at doe.com</td>
  </tr>
  <tr>
    <td>2</td>
    <td>Doe</td>
    <td>Mike</td>
    <td>mike at doe.com</td>
  </tr>
</table>

Perfect! Thank you.

Thomas.

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details