XSLT to HTML table problem

Discussion in 'XML' started by kanpeter, Oct 12, 2010.

  1. kanpeter

    kanpeter Guest

    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>
     
    kanpeter, Oct 12, 2010
    #1
    1. Advertising

  2. kanpeter wrote:
    > 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).


    --

    Martin Honnen
    http://msmvps.com/blogs/martin_honnen/
     
    Martin Honnen, Oct 12, 2010
    #2
    1. Advertising

  3. kanpeter

    kanpeter Guest

    On Oct 12, 11:50 pm, Martin Honnen <> wrote:
    > kanpeter wrote:
    > > 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).
    >
    > --
    >
    >         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.
     
    kanpeter, Oct 12, 2010
    #3
  4. kanpeter

    kanpeter Guest

    On Oct 13, 12:31 am, kanpeter <> wrote:
    > On Oct 12, 11:50 pm, Martin Honnen <> wrote:
    >
    >
    >
    > > kanpeter wrote:
    > > > 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).

    >
    > > --

    >
    > >         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".
     
    kanpeter, Oct 12, 2010
    #4
  5. kanpeter wrote:

    > 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>


    --

    Martin Honnen
    http://msmvps.com/blogs/martin_honnen/
     
    Martin Honnen, Oct 12, 2010
    #5
  6. kanpeter wrote:

    > 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).

    --

    Martin Honnen
    http://msmvps.com/blogs/martin_honnen/
     
    Martin Honnen, Oct 15, 2010
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David Williams
    Replies:
    2
    Views:
    1,184
    Jacob Yang [MSFT]
    Aug 12, 2003
  2. Stylus Studio
    Replies:
    0
    Views:
    775
    Stylus Studio
    Aug 3, 2004
  3. Rio
    Replies:
    4
    Views:
    1,250
  4. T. Sander
    Replies:
    2
    Views:
    680
    William Park
    Aug 20, 2004
  5. Eric
    Replies:
    1
    Views:
    2,075
    Pavel Lepin
    Feb 29, 2008
Loading...

Share This Page