Click here to Skip to main content
15,867,838 members
Articles / Programming Languages / XSLT
Article

Digits to Charts

Rate me:
Please Sign up or sign in to vote.
4.77/5 (21 votes)
9 Jun 20063 min read 78.1K   879   60   5
This article presents several XSLT stylesheets for converting XML numerical data to eye-candy HTML bar charts.

Histogram produced by 'hist-simple' stylesheet

Introduction

This article presents several XSLT stylesheets for visualizing numerical data rows contained, as you may have guessed, within XML files. The article explains the details of stylesheet setup and the template design rationale.

Stylesheets for the following types of charts are described:

This article assumes you are familiar with XSLT 1.0 and, to some extent, CSS Level 1.0 standards.

Much in common

  • Input XML structure

    Templates are tuned to process files with the following structure:

    XML
    <root>
    
      <data date="date-string">
        <first-component-name>first-component-value</first-component-name>
        <second-component-name>second-component-value</second-component-name>
      </data>
    
      <!-- And so on ... -->
    
    </root>

    Or, if you love schemas:

    XML
    <?xml version="1.0"?>
    
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
     <xs:element name="root">
      <xs:complexType>
    
       <xs:sequence maxOccurs="unbounded">
        <xs:element name="data">
    
         <xs:complexType>
          <xs:all>
           <xs:element name="a" type="xs:decimal" minOccurs="1" maxOccurs="1"/>
           <xs:element name="b" type="xs:decimal" minOccurs="1" maxOccurs="1"/>
          </xs:all>
         </xs:complexType>
    
         <xs:attribute name="date" type="xs:date" use="required"/>
    
        </xs:element>
       </xs:sequence>
    
      </xs:complexType>
     </xs:element>
    </xs:schema>

    The following sample file is used to test all the stylesheets:

    XML
    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="stylesheet name"?>
    <root>
    
      <data date="2006-01-01">
        <a>-1.5</a>
        <b>2.5</b>
      </data>
    
      <data date="2006-01-02">
        <a>-1.0</a>
        <b>2.0</b>
      </data>
    
      <!-- Data goes on ... -->
    
      <data date="2006-01-07">
        <a>1.5</a>
        <b>1.3</b>
      </data>
    
    </root>
  • Setup

    Parameters are the same for all templates:

    XML
    <xsl:call-template name="template-name">
      <!-- Resolution, i.e. number of cells in a chart -->
      <xsl:with-param name="n" select="$resolution"/>
      <!-- Set of XML nodes containing the input data  -->
      <xsl:with-param name="nodeset" select="root/*"/>
      <!-- Color for the first component of a data set -->
      <xsl:with-param name="colorFirst">#008000</xsl:with-param>
      <!-- Color for the second component              -->
      <xsl:with-param name="colorSecond">#B22222</xsl:with-param>
      <!-- Color for the empty cells in a chart        -->
      <xsl:with-param name="colorEmpty">#DCDCDC</xsl:with-param> 
    </xsl:call-template>

    However, most of the templates need additional info on the input node set:

    • Simple and overlaid templates require the highest and lowest values for each component of the data row(s).
      XML
      <!-- For example, maximum of 'a' can be calculated this way: -->
      <xsl:variable name="a_max_special">
       <xsl:for-each select="root/data">
        <xsl:sort select="a" data-type="number" order="descending"/>
        <xsl:if test="position()=1">
         <xsl:value-of select="a"/>
        </xsl:if>
       </xsl:for-each>
      </xsl:variable>
      <xsl:variable name="a_max" select="number($a_max_special)"/>
    • Stacked templates require the value of the highest and lowest component sums within data row(s).
      XML
      <!-- In our case, maximum sum is calculated as follows: -->
      <xsl:variable name="sum_max_special">
       <xsl:for-each select="root/data">
        <xsl:sort select="sum(*)" data-type="number" order="descending"/>
        <xsl:if test="position()=1">
         <xsl:value-of select="sum(*)"/>
        </xsl:if>
       </xsl:for-each>
      </xsl:variable>
      <xsl:variable name="sum_max" select="number($sum_max_special)"/>
    • Normalized templates don't need any supplementary data.

    Although you can obtain these values during the template runtime, "the best way to compute is to pre-compute" and assign the values to appropriate variables.

  • Inner workings

    Couple of words on template design.

    • Bar charts. Bargraph-related stylesheets are made of two parts:
      • template_name - the template you usually call. This is the "outer" template, which forms the base table of the chart;
      • template2name (for bar charts, it can be disconnected with the "outer" template) - inner template, which forms the actual table row.

      Bar charts are simple HTML <TABLE>s, with <TD>s filled with appropriate colors.

    • Histograms. Histogram-related stylesheets are made of three parts:
      • template_name - the template you may usually want to call. This is the "outer" template, which forms the base table of the chart;
      • template_name_col - the template that forms the columns;
      • template_name_cat - the template that builds the cells within columns.

      Histograms are a little bit harder to build: the same old <TABLE> with a single row and a number of <TD>s, each being a data column. Each column is formed by multiple <P> tags, with the number of tags equal to the resolution of the chart. Each paragraph is filled with the appropriate color.

  • Customization

    A simple CSS block controls a chart's look-and-feel:

    HTML
    <style>
     table.bargraph // Controls bar charts
     {
      margin-top: -1px;
      padding:0;
      font-size: 15px;
      // The main controller
      // of the barchart's cell size
     }
    
     table.bargraph td.date // Controls 'date' column
     {
      width: 75px;
      text-align:left;
     }
    
     table.histogram td     // Controls histograms
     {
      width: 5px;
      font-size: 1px;
      padding-top: 10px;
     }
    
     table.histogram td p   // Controls histogram cells
     {
      width: 20px;          // Width...
      height: 3px;          // ...and height of a cell.
      line-height: 0;
      margin: 0 1px 1px 0;
      padding: 0;
      font-size: 1px;
     }
    </style>
  • Limitations
    • First visible tight spot is the number of components in a dataset that can be processed at a time. Simple and overlaid sheets can be extended for an arbitrary number of components in no time; extending others presents some problems, although shouldn't take too much time.
    • Another problem is the complexity of stylesheets. While simple, overlaid, and normalized templates are fairly undemanding, stacked charts are heavyweight ones.

Charts

Inside the accompanying archive, you'll find the following stylesheets:

  • Bar graphs.
    • Bar-simple - distinct rows (2 per single date).

      The most simple chart: comparison of components by date.

    • Bar-overlaid - overlaid rows.

      Nearly the same as the forerunner, but shows only a single row per date - components overlay each other.

    • Bar-stacked - stacked bar chart.

      Shows the contribution of individual items to the overall sum.

    • Bar-normalized - stacked and 100%-normalized bar chart.

      Shows the percentage of an individual item's contribution of the total value.

  • Histograms.
    • Hist-simple - distinct columns (2 per single date).

    • Hist-overlaid - overlaid columns.

      Note: strictly speaking, this and the two following charts cannot be called histograms; nevertheless, I'll use the MS Excel slang, which calls all 'horizontal' charts bar charts and all 'vertical' charts histograms (or column charts).

    • Hist-stacked - stacked column chart.

    • Hist-normalized - stacked and 100% normalized column chart.

History

  • February 7th, 2006 - First version of the template set; positive values only.
  • April 6th, 2006 - Second version; arbitrary range of values.
  • April 25th, 2006 - Third version. Data file schema added; bar chart stylesheets optimized (resulting HTML is ~22% smaller compared with the previous version).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer Freelance software engineer
Russian Federation Russian Federation
Dmitry Khudorozhkov began programming (and gaming) with his ZX Spectrum in 1989. Having seen and used all IBM PCs from early XT to the latest x64 machines, now Dmitry is a freelance programmer, living in Moscow, Russia. He is a graduate of the Moscow State Institute of Electronics and Mathematics (Applied Mathematics).

He is proficient in:

- C/C++ - more that 9 years of experience. Pure Win32 API/MFC desktop programming, networking (BSD/Win sockets), databases (primarily SQLite), OpenGL;

- JavaScript - more that 6 years of experience. Client-side components, AJAX, jQuery installation and customization;

- Firefox extensions (immediatelly ready for addons.mozilla.org reviewing) and Greasemonkey scripts. As an example of extensions Dmitry made you can search for FoxyPrices or WhatBird Winged Toolbar;

- XML and it's applications (last 2 years): XSLT (+ XPath), XSD, SVG, VML;

- ASP.NET/C# (webservices mostly);

Also familiar with (= entry level):

- PHP;

- HTML/CSS slicing.

Trying to learn:

- Ruby/Ruby-on-Rails;

- Czech language.

If you wish to express your opinion, ask a question or report a bug, feel free to e-mail:dmitrykhudorozhkov@yahoo.com. Job offers are warmly welcome.

If you wish to donate - and, by doing so, support further development - you can send Dmitry a bonus through the Rentacoder.com service (registration is free, Paypal is supported). Russian users can donate to the Yandex.Money account 41001132298694.

-

Comments and Discussions

 
GeneralExcellent! Pin
RichardGrimmer11-Apr-06 23:47
RichardGrimmer11-Apr-06 23:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.