Transform generic Measures into SVG Line Graph

The stylesheet buildSVGLineChart.xsl will take a source document in the proper format – with a graphData root element, sets- and set-child elements and finally measure-elements that contain the actual graphdata – and transform it to a SVG object: a proper line chart. Here I will show a few sections from this stylesheet:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xlink="http://www.w3.org/2000/xlink/namespace/"
                version="1.0">
  <xsl:output method="image/svg+xml" omit-xml-declaration="yes"/>
  <xsl:template match="/graphData">
    <xsl:variable name="max">
      <xsl:value-of select="maxy"/>
    </xsl:variable>
    <xsl:variable name="min">
      <xsl:value-of select="miny"/>
    </xsl:variable>
    <xsl:variable name="maxx">
      <xsl:value-of select="maxx"/>
    </xsl:variable>
    <xsl:variable name="minx">
      <xsl:value-of select="minx"/>
    </xsl:variable>
    <svg width="1200" height="1200">
      <defs>
        <!-- definitions of different types of markers -->
        <g id="star" transform="scale(0.21)">
          <polyline points="48,16,16,96,96,48,0,48,80,96">
          </polyline>
        </g>
        <g id="triangle" transform="scale(0.7)">
          <path id="Triangle" d="M 0 25 L 10 15 L 20 25 z" style="stroke:none"/>
       </g>
        <g id="square" transform="scale(1)">
          <rect width="18" height="18">
          </rect>
        </g>
        <g id="rectangle" transform="scale(1)">
          <rect width="7" height="22">
          </rect>
        </g>
        </defs>
      <!-- create some room around the graph (border of 150 wide to the left and 50 high on top) -->
      <g transform="translate(150,50) scale(0.5)">
        <!--Heading-->
        <text x="5" y="-40" text-anchor="left" font-weight="bolder"
              font-size="40" fill="maroon" text-decoration="underline">
          <xsl:value-of select="title"/>
        </text>
        <!--Caption (Vertical)-->
        <g transform="translate(-220, 80) rotate(270, 0, 0)">
          <text x="0" y="0" text-anchor="middle" font-weight="bolder"
                font-size="36" fill="black">
            <xsl:value-of select="ytitle"/>
          </text>
        </g>
        <!--Caption (Horizontal)-->
        <text x="1070" y="1000" font-size="36" font-weight="bolder" fill="black">
          <xsl:value-of select="xtitle"/>
        </text>
        <!-- Now Draw the main X and Y axis -->
        <g style="stroke-width:5; stroke:black">
          <!-- X Axis -->
          <path d="M 0 1000 L 1000 1000 Z"/>
          <!-- Y Axis -->
          <path d="M 0 0 L 0 1000 Z"/>
        </g>
        <xsl:for-each select="sets/set"> <!-- match the /graphData/sets/set elements in the source document -->
          ... (left out: writing the markers and labels on the x-axis and y-axis )
          <!-- go and draw the line of the chart itself -->
          <g>
      <xsl:attribute name="style">
        stroke:<xsl:value-of select="@color"/>;stroke-width: 3; fill : none;
      </xsl:attribute>
            <!-- draw a line from the previous to each new point -->
            <xsl:for-each select="measure">
              <xsl:variable name="x">
                <xsl:value-of select=" 1000* ((xvalue - ($minx)) div ($maxx - $minx))"/>
              </xsl:variable>
              <xsl:variable name="y">
                    <xsl:value-of select="1000 - 1000* ((yvalue - ($min)) div ($max - $min))"/>
              </xsl:variable>
              <xsl:if test="not(../@showline='false')">
                <xsl:if test="(position() > 1)">
                  <line>
                    <xsl:attribute name="x1">
                      <xsl:value-of select=" 1000* ((preceding-sibling::measure[position()=1]/xvalue - ($minx)) div ($maxx - $minx))"/>
                    </xsl:attribute>
                    <xsl:attribute name="y1">
                          <xsl:value-of select="1000 - 1000* ((preceding-sibling::measure[position()=1]/yvalue - ($min)) div ($max - $min))"/>
                    </xsl:attribute>
                    <xsl:attribute name="x2">
                      <xsl:value-of select="$x"/>
                    </xsl:attribute>
                    <xsl:attribute name="y2">
                      <xsl:value-of select="$y"/>
                    </xsl:attribute>
                  </line>
                </xsl:if>
              </xsl:if>
              <xsl:if test="xgrid = 'true'">
                <xsl:call-template name="gridline">
                  <xsl:with-param name="x1" select="$x"/>
                  <xsl:with-param name="y1" select="$y"/>
                  <xsl:with-param name="type">vertical</xsl:with-param>
                </xsl:call-template>
              </xsl:if>
              <xsl:if test="ygrid = 'true'">
                <xsl:call-template name="gridline">
                  <xsl:with-param name="x1" select="$x"/>
                  <xsl:with-param name="y1" select="$y"/>
                  <xsl:with-param name="type">horizontal</xsl:with-param>
                  <xsl:with-param name="yaxis">
                    <xsl:choose>
                      <xsl:when test="yvalue">1</xsl:when>
                      <xsl:otherwise>2</xsl:otherwise>
                    </xsl:choose>
                  </xsl:with-param>
                </xsl:call-template>
              </xsl:if>
            </xsl:for-each> <!-- measure -->
          </g>
        </xsl:for-each> <!-- sets -->
            <!-- now again traverse all measures to place markers
                 by doing this in a second go, we ensure (according to the 'painters algoritm'
                 (see: http://wiki.svg.org/index.php/ChangingDrawingOrder)) that the annotations
                 and markers are on top of everything else.
                 -->
        <xsl:for-each select="sets/set">
            <xsl:for-each select="measure">
              <xsl:variable name="x">
                <xsl:value-of select=" 1000* ((xvalue - ($minx)) div ($maxx - $minx))"/>
              </xsl:variable>
              <xsl:variable name="y">
                    <xsl:value-of select="1000 - 1000* ((yvalue - ($min)) div ($max - $min))"/>
              </xsl:variable>
             <g >
               <xsl:attribute name="style">stroke:<xsl:value-of select="../@color"/> stroke-width: 3; fill : none;</xsl:attribute>
              <!-- draw a marker -->
              <xsl:call-template name="marker">
                <xsl:with-param name="x" select="$x"/>
                <xsl:with-param name="y" select="$y"/>
                <xsl:with-param name="marker" select="../@marker-type"/>
                <xsl:with-param name="color" select="../@color"/>
              </xsl:call-template>
           </g>
            </xsl:for-each>  <!-- measures in set -->
        </xsl:for-each> <!-- sets -->
        ... (left out: creation of the legend-box)

      </g>
    </svg>
  </xsl:template>

  ... (left out: templates for labels and markers on the x-axis and y-axis)
  <xsl:template name="marker">
    <xsl:param name="x"/>
    <xsl:param name="y"/>
    <xsl:param name="marker">circle</xsl:param>
    <xsl:param name="color">red</xsl:param>
    <g  transform="scale(1)">
      <xsl:attribute name="style">
        stroke:<xsl:value-of select="$color"/>;fill:<xsl:value-of select="$color"/>
      </xsl:attribute>
      <xsl:choose>
        <xsl:when test="$marker='square'">
          <use xlink:href="#square">
            <xsl:attribute name="x">
              <xsl:value-of select="$x -9"/>
            </xsl:attribute>
            <xsl:attribute name="y">
              <xsl:value-of select="$y -9"/>
            </xsl:attribute>
          </use>
        </xsl:when>
        <xsl:when test="$marker='triangle'">
          <use xlink:href="#triangle">
            <xsl:attribute name="x">
              <xsl:value-of select="$x -9"/>
            </xsl:attribute>
            <xsl:attribute name="y">
              <xsl:value-of select="$y -9"/>
            </xsl:attribute>
          </use>
        </xsl:when>
        <xsl:when test="$marker='rectangle'">
          <use xlink:href="#rectangle">
            <xsl:attribute name="x">
              <xsl:value-of select="$x -4"/>
            </xsl:attribute>
            <xsl:attribute name="y">
              <xsl:value-of select="$y -4"/>
            </xsl:attribute>
          </use>
        </xsl:when>
        <xsl:when test="$marker='star'">
          <use xlink:href="#star">
            <xsl:attribute name="x">
              <xsl:value-of select="$x -9"/>
            </xsl:attribute>
            <xsl:attribute name="y">
              <xsl:value-of select="$y -9"/>
            </xsl:attribute>
          </use>
        </xsl:when>
        <xsl:when test="$marker='diamond'">
          <!-- diamond is just a square rotated about its own center for 45 degrees -->
          <use xlink:href="#square">
            <xsl:attribute name="x">
              <xsl:value-of select="$x -9"/>
            </xsl:attribute>
            <xsl:attribute name="y">
              <xsl:value-of select="$y -9"/>
            </xsl:attribute>
            <xsl:attribute name="transform">
               rotate(45,<xsl:value-of select="$x"/>,<xsl:value-of select="$y "/>)
            </xsl:attribute>
          </use>
        </xsl:when>
        <xsl:when test="$marker='circle'">
          <circle r="9">
            <xsl:attribute name="cx">
              <xsl:value-of select="$x"/>
            </xsl:attribute>
            <xsl:attribute name="cy">
              <xsl:value-of select="$y"/>
            </xsl:attribute>
          </circle>
        </xsl:when>
        <xsl:when test="$marker='smallcircle'">
          <circle r="4">
            <xsl:attribute name="cx">
              <xsl:value-of select="$x"/>
            </xsl:attribute>
            <xsl:attribute name="cy">
              <xsl:value-of select="$y"/>
            </xsl:attribute>
          </circle>
        </xsl:when>
        <xsl:otherwise>
        </xsl:otherwise>
      </xsl:choose>
    </g>
  </xsl:template>
  <xsl:template name="gridline">
    <xsl:param name="x1"/>
    <xsl:param name="y1"/>
    <xsl:param name="type"/>
    <xsl:param name="yaxis">1</xsl:param>
    <line style="fill:none; stroke:#B0B0B0; stroke-width:2; stroke-dasharray:2 4">
      <xsl:attribute name="x1">
        <xsl:value-of select="$x1"/>
      </xsl:attribute>
      <xsl:choose>
        <xsl:when test="$type='horizontal'">
          <xsl:attribute name="x2"><xsl:value-of select="($yaxis -1)* 1000 "/></xsl:attribute>
          <xsl:attribute name="y2">
            <xsl:value-of select="$y1"/>
          </xsl:attribute>
        </xsl:when>
        <xsl:otherwise>
          <xsl:attribute name="y2">1000</xsl:attribute>
          <xsl:attribute name="x2">
            <xsl:value-of select="$x1"/>
          </xsl:attribute>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:attribute name="y1">
        <xsl:value-of select="$y1"/>
      </xsl:attribute>
    </line>
  </xsl:template>
  <!-- end gridline -->
  </xsl:stylesheet>

The result of the transformation with this stylesheet to the SVG object can be downloaded here:EmpSalLineGraph.svg. The graph that is displayed as a result from these transformations:
Simple Line-chart for Employee Salaries (no annotations, no tooltip and no second y-axis)