Reputation: 1723
My question is a bit similar to XML to HTML table with XSLT .
I have a dictionary defined as follows in XML:
<dictionary>
<languages>
<language>en</language>
<language>ja</language>
</languages>
<entries>
<entry id="1">
<en>Test</en>
<ja>テスト</ja>
</entry>
<entry id="2">
<en>Test2</en>
<ja>テスト2</en>
</entry>
</entries>
</dictionary>
And I would like the following output in XHTML:
<table>
<thead>
<tr>
<th>en</th>
<th>ja</th>
</tr>
</thead>
<tbody>
<tr>
<td>Test</td>
<td>テスト</td>
</tr>
<tr>
<td>Test2</td>
<td>テスト2</td>
</tr>
</tbody>
</table>
I adapted the answer from XML to HTML table with XSLT as follows:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="//dictionary/entries">
<table><xsl:apply-templates select="entry"/></table>
</xsl:template>
<xsl:template match="entry[1]">
<thead><tr><xsl:apply-templates select="*" mode="header"/></tr></thead>
<xsl:call-template name="standardRow"/>
</xsl:template>
<xsl:template match="entry" name="standardRow">
<tbody><tr><xsl:apply-templates select="*"/></tr></tbody>
</xsl:template>
<xsl:template match="entry/*">
<td><xsl:apply-templates select="node()"/></td>
</xsl:template>
<xsl:template match="entry/*" mode="header">
<th><xsl:value-of select="name()"/></th>
</xsl:template>
</xsl:stylesheet>
The thing is that I might have inputs as follows:
<dictionary>
<languages>
<language>en</language>
<language>ja</language>
<language>id</language>
</languages>
<entries>
<entry id="1">
<en>Test</en>
<ja>テスト</ja>
</entry>
<entry id="2">
<ja>テスト2</ja>
<en>Test2</en>
<id>uji2</id>
</entry>
</entries>
</dictionary>
As you might have understood, XSLT takes the first entry
node to define the column names and the column id
is not generated. Moreover, if the language order is changed in entry
the <td>
do not appear in order.
With the input above, I would like the following output:
<table>
<thead>
<tr>
<th>en</th>
<th>ja</th>
<th>id</th>
</tr>
</thead>
<tbody>
<tr>
<td>Test</td>
<td>テスト</td>
<td></td>
</tr>
<tr>
<td>Test2</td>
<td>テスト2</td>
<td>Uji2</td>
</tr>
</tbody>
</table>
This is my first time using XSLT and I do not really know how I could do this. I guess I could use the languages
node. Please note that the XML input format is flexible and I would welcome any suggestions even if I need to change the format.
Upvotes: 0
Views: 1557
Reputation: 167506
Here is a sample stylesheet:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes"/>
<xsl:key name="k1" match="entry/*" use="concat(generate-id(..), '|', local-name())"/>
<xsl:variable name="languages" select="/dictionary/languages/language"/>
<xsl:template match="dictionary">
<xsl:apply-templates select="entries"/>
</xsl:template>
<xsl:template match="entries">
<table>
<thead>
<tr>
<xsl:apply-templates select="$languages" mode="header"/>
</tr>
</thead>
<tbody>
<xsl:apply-templates/>
</tbody>
</table>
</xsl:template>
<xsl:template match="language" mode="header">
<th>
<xsl:value-of select="."/>
</th>
</xsl:template>
<xsl:template match="entry">
<tr>
<xsl:apply-templates select="$languages">
<xsl:with-param name="entry" select="current()"/>
</xsl:apply-templates>
</tr>
</xsl:template>
<xsl:template match="language">
<xsl:param name="entry"/>
<td>
<xsl:value-of select="key('k1', concat(generate-id($entry), '|', .))"/>
</td>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1