Please critique my solution: rendering HTML table using sparse data

Discussion in 'XML' started by Sandros, Nov 4, 2004.

  1. Sandros

    Sandros Guest

    Background: I'm collecting usability statistics for a group of
    applications. Each count has the following attributes: date,
    application, major heading, minor heading, count. My intent is
    to pull this back as XML and render it in to an HTML table.

    I have all this working and all the files are below. I would
    value any feedback.

    A simple example of the data looks like this:

    <counts-report>
    <counts date="2004-10-07">
    <application name="App A">
    <major name="Major A">
    <minor name="Minor A">1</minor>
    <minor name="Minor C">7</minor>
    </major>
    </application>
    </counts>
    <counts date="2004-10-08">
    <application name="App A">
    <major name="Major A">
    <minor name="Minor A">1</minor>
    <minor name="Minor B">3</minor>
    </major>
    <major name="Major B">
    <minor name="Minor A">15</minor>
    </major>
    </application>
    </counts>
    </counts-report>

    The output I am looking for is something like:

    +------------+---------------------------------------+
    | | App A |
    | +---------------------------------------+
    | | Major A | Major B |
    | +---------+---------+---------+---------+
    | | Minor A | Minor B | Minor C | Minor A |
    +------------+---------+---------+---------+---------+
    | 2004-10-07 | 1 | | | |
    +------------+---------+---------+---------+---------+
    | 2004-10-07 | 1 | 3 | 7 | 15 |
    +------------+---------+---------+---------+---------+
    | Totals | 2 | 3 | 7 | 15 |
    +------------+---------+---------+---------+---------+



    Now I looked around for solutions that would let me tabularize
    truely sparese data but didn't have any luck and no elegant
    solutions came to mind.

    The only solution I could come up with was to somehow massage the
    data beforehand. The two choices I explored were

    1) Turning it in to a non-sparse data set
    2) Put a "domain" entry in front listing the union of all

    I went with #2 (mainly because for real world data #1 would
    inflate the size of the file significantly). So the final file
    looks like:


    <counts-report>
    <domain>
    <application name="App A">
    <major name="Major A">
    <minor name="Minor A"/>
    <minor name="Minor B"/>
    <minor name="Minor C"/>
    </major>
    <major name="Major B>
    <minor name="Minor A"/>
    </major>
    </application>
    </domain>
    <counts date="2004-10-07">
    <application name="App A">
    <major name="Major A">
    <minor name="Minor A">1</minor>
    <minor name="Minor C">7</minor>
    </major>
    </application>
    </counts>
    <counts date="2004-10-08">
    <application name="App A">
    <major name="Major A">
    <minor name="Minor A">1</minor>
    <minor name="Minor B">3</minor>
    </major>
    <major name="Major B">
    <minor name="Minor A">15</minor>
    </major>
    </application>
    </counts>
    </counts-report>

    The XSLT I am using is at the end of this message. This is my
    first non-trivial XSLT experiment so I would appreciate any
    comments. A couple of specific questions:

    1) I wanted to put &nbsp; in blank cells instead of "-". I
    couldn't get the parsers to accept the &nbsp; (verbatim) in
    the xslt file (line 60)

    2) I used two templates for minor and non-minor table headers
    because the colpan value was comming out to zero when (@line
    27 & 34... referenced at 11, 12, and 13).

    3) I access the actual data for each row by constructing a
    path expression using each "minor" entry found in the
    domain (line 55).

    I would also value any stylistic comments.

    Thanks in advance for any help

    Charlie


    1: <?xml version="1.0" encoding="UTF-8"?>
    2: <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    3: <xsl:eek:utput method="html" version="1.0" encoding="UTF-8"
    indent="yes"/>
    4: <xsl:template match="/counts-report">
    5: <html>
    6: <head>
    7: <title>My Table</title>
    8: </head>
    9: <body>
    10: <table border="1" cellpadding="5">
    11: <tr> <th rowspan="3">Date</th> <xsl:apply-templates
    mode="header" select="domain/application"/> </tr>
    12: <tr> <xsl:apply-templates mode="header"
    select="domain/application/major"/> </tr>
    13: <tr> <xsl:apply-templates mode="header"
    select="domain/application/major/minor"/> </tr>
    14:
    15: <xsl:apply-templates mode="data" select="counts"/>
    16:
    17: <tr>
    18: <th> Totals </th>
    19: <xsl:apply-templates mode="totals"
    select="domain/application/major/minor"/>
    20: </tr>
    21:
    22: </table>
    23: </body>
    24: </html>
    25: </xsl:template>
    26:
    27: <xsl:template mode="header" match="*">
    28: <xsl:element name="th">
    29: <xsl:attribute name="colspan"><xsl:value-of
    select="count(.//minor)"/></xsl:attribute>
    30: <xsl:value-of select="@name"/>
    31: </xsl:element>
    32: </xsl:template>
    33:
    34: <xsl:template mode="header" match="minor">
    35: <xsl:element name="th">
    36: <xsl:value-of select="@name"/>
    37: </xsl:element>
    38: </xsl:template>
    39:
    40: <xsl:template mode="data" match="counts">
    41: <xsl:variable name="rownum" select="position()"/>
    42:
    43: <xsl:element name="tr">
    44: <xsl:if test="$rownum mod 2 = 0">
    45: <xsl:attribute name="style">background-color: rgb(0, 204,
    204);</xsl:attribute>
    46: </xsl:if>
    47:
    48: <th> <xsl:value-of select="@date"/> </th>
    49:
    50: <xsl:for-each
    select="/counts-report/domain/application/major/minor">
    51: <xsl:variable name="app" select="../../@name"/>
    52: <xsl:variable name="major" select="../@name"/>
    53: <xsl:variable name="minor" select="@name"/>
    54:
    55: <xsl:variable name="value"
    select="/counts-report/counts[$rownum]/application[@name=$app]/major[@name=$major]/minor[@name=$minor]"/>
    56:
    57: <td>
    58: <xsl:choose>
    59: <xsl:when test="$value"> <xsl:value-of
    select="$value"/> </xsl:when>
    60: <xsl:eek:therwise> - </xsl:eek:therwise>
    61: </xsl:choose>
    62: </td>
    63:
    64: </xsl:for-each>
    65:
    66: </xsl:element>
    67:
    68: </xsl:template>
    69:
    70: <xsl:template mode="totals" match="minor">
    71: <xsl:param name="app" select="../../@name"/>
    72: <xsl:param name="major" select="../@name"/>
    73: <xsl:param name="minor" select="@name"/>
    74:
    75: <td>
    76: <xsl:value-of
    select="sum(/counts-report/counts/application[@name=$app]/major[@name=$major]/minor[@name=$minor])"/>
    77: </td>
    78: </xsl:template>
    79:
    80: </xsl:stylesheet>
     
    Sandros, Nov 4, 2004
    #1
    1. Advertising

  2. 1) I wanted to put &nbsp; in blank cells instead of "-". I
    couldn't get the parsers to accept the &nbsp; (verbatim) in
    the xslt file (line 60)

    This is the most FFF FAQ on xsl-list (which maintains a faq at
    www.dpawson.co.uk)

    XML only predefines 5 entities (amp quot apos lt gt) so if you want to
    use any other you need to redefine them in a DD and reference that DTD
    in a doc type. In this case you don't need an entity at all you just
    want to but a no break space into the result tree which is character 160
    so
    & # 1 6 0 ;
    (without the spaces) if outputting html this will probably come out as
    the entity nbsp but it may come out as character data (depending on your
    processor) either way it will work in a browser.


    You don't need to use xsl:element unless you are generating element
    names dynamically so

    <xsl:element name="th">
    36: <xsl:value-of select="@name"/>
    37: </xsl:element>

    could more easily be written

    <th>
    36: <xsl:value-of select="@name"/>
    37: </th>

    almost certainly makes no difference to the processing speed or anything
    else though, just easier to read.

    David
     
    David Carlisle, Nov 4, 2004
    #2
    1. Advertising

  3. Sandros

    John Fereira Guest

    (Sandros) wrote in
    news::


    >
    > 1) I wanted to put &nbsp; in blank cells instead of "-". I
    > couldn't get the parsers to accept the &nbsp; (verbatim) in
    > the xslt file (line 60)


    Replace &nbsp; with  

    There are a couple of other solutions I prefer to use:

    Create a transparent.gif image that is 1 pixel wide and 1 pixel high.

    Whenever you need white space use it in an img tag with scaled height width
    values:

    <img src="transparent.gif" width="10" height="5" alt=" " border="0" />

    Alternatively, use can use css styles:

    <td style="background-image: url(transparent.gif); background-repeat:repeat-
    x;" width="20"></td>
     
    John Fereira, Nov 5, 2004
    #3
  4. Sandros

    GIMME Guest

    Regarding style.

    It's my opinion that xhtml should look as much as possible as html
    and that the number of templates should be kept to a minimum.

    Some of what you do as a template I'd recommend doing "in line".

    That way if you can turn the project over to an html person.

    It reads easier too. (Lines 11-14 look messy.)
     
    GIMME, Nov 5, 2004
    #4
    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. Peter Mount
    Replies:
    4
    Views:
    1,001
    Peter Mount
    Jan 31, 2006
  2. KK
    Replies:
    2
    Views:
    709
    Big Brian
    Oct 14, 2003
  3. Trent Mick

    Re: creating sparse files on win32

    Trent Mick, Jul 15, 2003, in forum: Python
    Replies:
    0
    Views:
    502
    Trent Mick
    Jul 15, 2003
  4. Andrew Francis
    Replies:
    0
    Views:
    450
    Andrew Francis
    Jun 28, 2006
  5. aaragon
    Replies:
    3
    Views:
    1,046
    aaragon
    Feb 16, 2009
Loading...

Share This Page