XSLT to HTML table problem

K

kanpeter

given an xml file:
<data>
<invoices>
<invoice type="A">111</invoice>
<invoice type="B">222</invoice>
<invoice type="C">333</invoice>
</invoices>
<invoices>
<invoice type="C">444</invoice>
<invoice type="B">555</invoice>
<invoice type="A">666</invoice>
</invoices>
<invoices>
<invoice type="C">777</invoice>
<invoice type="A">999</invoice>
</invoices>
</data>

how can i write an xslt to output the following?

<table border="1">
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
<tr>
<td>111</td>
<td>222</td>
<td>333</td>
</tr>
<tr>
<td>666</td>
<td>555</td>
<td>444</td>
</tr>
<tr>
<td>999</td>
<td>--</td>
<td>777</td>
</tr>
</table>
 
M

Martin Honnen

kanpeter said:
given an xml file:
<data>
<invoices>
<invoice type="A">111</invoice>
<invoice type="B">222</invoice>
<invoice type="C">333</invoice>
</invoices>
<invoices>
<invoice type="C">444</invoice>
<invoice type="B">555</invoice>
<invoice type="A">666</invoice>
</invoices>
<invoices>
<invoice type="C">777</invoice>
<invoice type="A">999</invoice>
</invoices>
</data>

how can i write an xslt to output the following?

<table border="1">
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
<tr>
<td>111</td>
<td>222</td>
<td>333</td>
</tr>
<tr>
<td>666</td>
<td>555</td>
<td>444</td>
</tr>
<tr>
<td>999</td>
<td>--</td>
<td>777</td>
</tr>
</table>

Here is an XSLT 2.0 stylesheet that should do the job (assuming the
first "invoices" element has the complete set of "type" values (e.g. A,
B, C) you want to output):

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">

<xsl:eek:utput method="html" indent="yes"/>

<xsl:key name="k1" match="invoices/invoice" use="@type"/>

<xsl:template match="data">
<table border="1">
<xsl:variable name="types" as="xs:string*"
select="invoices[1]/invoice/@type"/>
<thead>
<tr>
<xsl:for-each select="$types">
<th>
<xsl:value-of select="."/>
</th>
</xsl:for-each>
</tr>
</thead>
<tbody>
<xsl:for-each select="invoices">
<tr>
<xsl:variable name="ci" as="element(invoices)" select="."/>
<xsl:for-each select="$types">
<td>
<xsl:value-of select="if (key('k1', ., $ci)) then
key('k1', ., $ci) else '--'"/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>

</xsl:stylesheet>

You can run XSLT 2.0 with Saxon 9 (http://saxon.sourceforge.net),
AltovaXML Tools (http://www.altova.com/altovaxml.html), XQSharp
(http://www.xqsharp.com/) and some other processors (Intel, IBM).
 
K

kanpeter

kanpeter said:
given an xml file:
<data>
   <invoices>
      <invoice type="A">111</invoice>
      <invoice type="B">222</invoice>
      <invoice type="C">333</invoice>
   </invoices>
   <invoices>
      <invoice type="C">444</invoice>
      <invoice type="B">555</invoice>
      <invoice type="A">666</invoice>
   </invoices>
   <invoices>
      <invoice type="C">777</invoice>
      <invoice type="A">999</invoice>
   </invoices>
</data>
how can i write an xslt to output the following?
<table border="1">
      <tr>
         <th>A</th>
         <th>B</th>
         <th>C</th>
      </tr>
      <tr>
         <td>111</td>
         <td>222</td>
         <td>333</td>
      </tr>
      <tr>
         <td>666</td>
         <td>555</td>
         <td>444</td>
      </tr>
      <tr>
         <td>999</td>
         <td>--</td>
         <td>777</td>
      </tr>
</table>

Here is an XSLT 2.0 stylesheet that should do the job (assuming the
first "invoices" element has the complete set of "type" values (e.g. A,
B, C) you want to output):

<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="2.0"
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
   exclude-result-prefixes="xs">

   <xsl:eek:utput method="html" indent="yes"/>

   <xsl:key name="k1" match="invoices/invoice" use="@type"/>

   <xsl:template match="data">
     <table border="1">
       <xsl:variable name="types" as="xs:string*"
select="invoices[1]/invoice/@type"/>
       <thead>
         <tr>
           <xsl:for-each select="$types">
             <th>
               <xsl:value-of select="."/>
             </th>
           </xsl:for-each>
         </tr>
       </thead>
       <tbody>
         <xsl:for-each select="invoices">
           <tr>
             <xsl:variable name="ci" as="element(invoices)" select="."/>
             <xsl:for-each select="$types">
               <td>
                 <xsl:value-of select="if (key('k1', .., $ci)) then
key('k1', ., $ci) else '--'"/>
               </td>
             </xsl:for-each>
           </tr>
         </xsl:for-each>
       </tbody>
     </table>
   </xsl:template>

</xsl:stylesheet>

You can run XSLT 2.0 with Saxon 9 (http://saxon.sourceforge.net),
AltovaXML Tools (http://www.altova.com/altovaxml.html), XQSharp
(http://www.xqsharp.com/) and some other processors (Intel, IBM).

Actually, i want to make the table header contains sorted distinct
values of attribute "type" of element invoice.
 
K

kanpeter

Here is an XSLT 2.0 stylesheet that should do the job (assuming the
first "invoices" element has the complete set of "type" values (e.g. A,
B, C) you want to output):
<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="2.0"
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
   exclude-result-prefixes="xs">
   <xsl:eek:utput method="html" indent="yes"/>
   <xsl:key name="k1" match="invoices/invoice" use="@type"/>
   <xsl:template match="data">
     <table border="1">
       <xsl:variable name="types" as="xs:string*"
select="invoices[1]/invoice/@type"/>
       <thead>
         <tr>
           <xsl:for-each select="$types">
             <th>
               <xsl:value-of select="."/>
             </th>
           </xsl:for-each>
         </tr>
       </thead>
       <tbody>
         <xsl:for-each select="invoices">
           <tr>
             <xsl:variable name="ci" as="element(invoices)" select="."/>
             <xsl:for-each select="$types">
               <td>
                 <xsl:value-of select="if (key('k1', ., $ci)) then
key('k1', ., $ci) else '--'"/>
               </td>
             </xsl:for-each>
           </tr>
         </xsl:for-each>
       </tbody>
     </table>
   </xsl:template>
</xsl:stylesheet>

You can run XSLT 2.0 with Saxon 9 (http://saxon.sourceforge.net),
AltovaXML Tools (http://www.altova.com/altovaxml.html), XQSharp
(http://www.xqsharp.com/) and some other processors (Intel, IBM).

        Martin Honnen
       http://msmvps.com/blogs/martin_honnen/

Actually, i want to make the table header contains sorted distinct
values of attribute "type" of element invoice.

Actually, i want to make the table header contains sorted distinct
values of attribute "type" of element invoice and the first invoice
element not necessarily contain all distinct values of "type".
 
M

Martin Honnen

kanpeter said:
Actually, i want to make the table header contains sorted distinct
values of attribute "type" of element invoice and the first invoice
element not necessarily contain all distinct values of "type".

Then change the template as follows:

<xsl:template match="data">
<table border="1">
<xsl:variable name="types" as="xs:string*">
<xsl:perform-sort
select="distinct-values(invoices/invoice/@type/xs:string(.))">
<xsl:sort select="."/>
</xsl:perform-sort>
</xsl:variable>
<thead>
<tr>
<xsl:for-each select="$types">
<th>
<xsl:value-of select="."/>
</th>
</xsl:for-each>
</tr>
</thead>
<tbody>
<xsl:for-each select="invoices">
<tr>
<xsl:variable name="ci" as="element(invoices)" select="."/>
<xsl:for-each select="$types">
<td>
<xsl:value-of select="if (key('k1', ., $ci)) then
key('k1', ., $ci) else '--'"/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
 
M

Martin Honnen

kanpeter said:
Why do i need to use exclude-result-prefixes="xs" ?

With XSLT 2.0 you often use the XML schema namespace
http://www.w3.org/2001/XMLSchema and associate it with the prefix "xs".
If you don't want it to be output on literal result elements you need to
use exclude-result-prefixes="xs", as you need to do for other prefixes
(besides the prefix associated with the XSLT namespace
http://www.w3.org/1999/XSL/Transform that is automatically excluded).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top