SVG and xslt

Scalable Vector Graphics

1. SVG graphics with XSL
2. Visualizing XML trees with XSLT and SVG
3. Working with Graphs using xml and xsl
4. SVG and namespace
5. SVG graphs
6. How to embed SVG into HTML output.
7. SVG tree

1.

SVG graphics with XSL

Max Dunn

There are also XSLT->SVG charting stylesheets by John Morrison in Batik CVS: See the Apache site

The main batik site is: Batik site

There is also a tutorial at IBM Developerworks in the Education section which covers both a bar graph and a pie chart, by Doug Tidwell part 2 (and also part 3 XML to PDF).

The Link is as follows (although you may have to do the free registration first!) and I am also trying to do that myself at the moment!: http://www-106.ibm.com/developerworks/education/transforming-xml/xmltosvg/in dex.html

Is anyone aware of an XSL and/or SVG based "diagramming" tool? You can try "dia". it's a freeware diagramming tool (has unix and windows variant) and stores it's images in xml. It has flow diagrams, as well.

2.

Visualizing XML trees with XSLT and SVG

DaveP

On southard.net wizard Jeff Southard demos his very nice XSLTs visualizing XML trees in SVG.

If you don't have it, install the Adobe SVG Viewer first http://www.adobe.com/svg/viewer/install/main.html for Win+Mac, http://www.adobe.com/svg/viewer/install/old.html for Linux.

Mouse around the SVGs to see the node values.

Here are the sourcefiles.

3.

Working with Graphs using xml and xsl

Zeynep Gunal

Maybe by using SVG?

Take a look at that: ibm website.

4.

SVG and namespace

Michael Kay

The SVG DTD sneakily changes the default namespace for the SVG elements by including a default value for the xmlns attribute.

Try an xsl:copy-of on the whole document to see what the actual namespaces are.

or Look at the DTD.

If it defines something like

<!ATTLIST eee xmlns "a.namespace.uri" #FIXED>

then in your stylesheet you must use the same namespace to match this element. What's more, you must give it a prefix. For example

<xsl:stylesheet .... xmlns:a="a.namespace.uri">

<xsl:template match="a:eee">
  <xsl:value-of select="a:fff"/>

5.

SVG graphs

Steve Muench

There's an example of an SVG Bar Chart stylesheet at: olabs The XML document (in this particular case, dynamically generated off a SQL query, server-side) on which the stylesheet operates is here The stylesheet uses a Java extension function to make use of the java.awt.Color object as part of its algorithm to pick a range of "cool" colors for the bars, but you can easily rip this detail out of the stylesheet.

A similar example is explained in detail in my book.

Kurt Cagle adds:

Take a look at my site - I wrote a routine that converts XML into an SVG graph using XSLT. It's pretty straightforward, and you're welcome to use the code.

6.

How to embed SVG into HTML output.

DaveP

Use:

  
   <EMBED width="500" height="48" name="logotransform"
   pluginspage="http://www.adobe.com/svg/viewer/install/"
     src="logo2.svg" type="image/svg-xml"/> 

Where logo2.svg is the SVG file you want to show.

7.

SVG tree

Wendell Piez

Draws an SVG "tree structure" representing the XSLT/XPath infoset of an arbitrary input document.

Distribute and alter freely. Please acknowledge your sources. (You could use this stylesheet by importing it into your own and overriding its variable settings.)

Includes a named template from Jeni Tennison's and Mike Brown's "ASCII Art" Tree Viewing stylesheet.

By Wendell Piez, Mulberry Technologies, February 2001. Revised July 2001.

I changed many of the global variables to parameters, and added one for $max-text-length, so text nodes will now truncate (the default is 32 characters).

You still have to try it and make adjustments based on the size and structure of your document.


 <xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

<!-- Draws an SVG "tree structure" representing the XSLT/XPath
     infoset of an arbitrary input document.
     
     Distribute and alter freely.
     Please acknowledge your sources.
     (You could use this stylesheet by importing it into
      your own and overriding its variable settings.)
     
     Includes a named template from Jeni Tennison's and
     Mike Brown's "ASCII Art" Tree Viewing stylesheet.

     By Wendell Piez, Mulberry Technologies, February 2001

-->

<!-- When targeting FOP, include the namespace declaration
     xmlns="http://www.w3.org/2000/svg" -->

<xsl:output method="xml" indent="yes" />

<!-- amend or comment this out if you want to see 
    any whitespace-only text nodes -->
<xsl:strip-space elements="*"/>

<xsl:param name="across-start" select="6"/>
<!-- a left margin -->

<xsl:param name="down-start" select="4"/>
<!-- a top margin -->

<xsl:param name="across-interval" select="14"/>
<!-- size of each horizontal step -->

<xsl:param name="text-allowance" select="360"/>
<!-- extra space to the right to allow 
    content of text nodes some room -->

<xsl:param name="max-text-length" select="32"/>
<!-- maximum number of characters to allow to show of a text node -->

<xsl:param name="down-interval" select="18"/>
<!-- size of each vertical step -->

<xsl:param name="line-thickness" select="1"/>

<xsl:param name="writing-bump-over" select="6"/>
<xsl:param name="writing-bump-up" select="-3"/>
<!-- allow for positioning of node labels -->

<!-- the following are parameters for styling: -->
<xsl:param name="background-color" select="'lemonchiffon'"/>

<xsl:param name="tree-color" select="'#8B4513'"/>

<xsl:param name="text-font-style" 
    select="'font-size: 12; font-family: Courier'"/>

<xsl:param name="text-color" select="'#8A2BE2'"/>

<xsl:param name="element-font-style" 
    select="'font-size: 14; font-family: serif'"/>

<xsl:param name="element-color" select="'#006400'"/>

<xsl:param name="attribute-font-style" 
    select="'font-size: 9; font-family: sans-serif'"/>

<xsl:param name="attribute-color" select="'#4682B4'"/>

<xsl:param name="code-font-style" 
    select="'font-size: 9; font-family: sans-serif'"/>

<xsl:param name="PI-color" select="'#228B22'"/>

<xsl:param name="comment-color" select="'#B22222'"/>

<!-- the following allow adjustments to the symbols
     representing nodes: -->
<xsl:param name="element-dot-radius" select="2.5"/>

<xsl:param name="text-box-width" select="3"/>

<xsl:param name="text-box-height" select="5"/>

<!-- calculates the depth of the deepest ancestor
     (so we have an idea of how many levels deep the tree
     will be): a 'max' trick -->
<xsl:variable name="deepest">
  <!-- returns the depth (in ancestors) of the deepest node(s) -->
  <xsl:for-each select="//node()[not(node())]">
    <xsl:sort select="count(ancestor-or-self::*)" 
    order="descending" data-type="number"/>
    <xsl:if test="position()=1">
      <xsl:value-of select="count(ancestor-or-self::*)"/>
    </xsl:if>
  </xsl:for-each>
</xsl:variable>

<!-- for the initial viewbox -->
<xsl:variable name="full-width" 
    select="($across-interval * ($deepest +2)) + 
    (2 * $across-start) + $text-allowance"/>

<xsl:variable name="full-height" 
    select="((count(//node()) + 2) * $down-interval) + 
    (2 * $down-start)"/>

<xsl:variable name="apos">'</xsl:variable>

<!-- internal functions to calculate position for any node -->

<xsl:template name="get-x-coordinate">
  <xsl:param name="node" select="/*"/>
  <xsl:value-of select="(count
    ($node/ancestor-or-self::node()) * $across-interval) 
    + $across-start"/>
</xsl:template>

<xsl:template name="get-y-coordinate">
  <xsl:param name="node" select="/*"/>
  <xsl:value-of select="(count($node/preceding::node()|
    $node/ancestor-or-self::node()) * $down-interval) + $down-start"/>
</xsl:template>

<!-- -->

<!-- root template -->

<xsl:template match="/">
  <svg width="{$full-width}" height="{$full-height}" >
    <rect x="0" y="0" width="{$full-width}" 
    height="{$full-height}" 
    style="fill:{$background-color}"/>
    <g>
      <xsl:apply-templates select="." mode="label">
        <xsl:with-param name="self-x" 
    select="$across-start + $across-interval"/>
        <xsl:with-param name="self-y" 
    select="$down-start + $down-interval"/>
      </xsl:apply-templates>
      <xsl:apply-templates/>
    </g>
  </svg>
</xsl:template>

<!-- -->

<!-- template for any child node -->

<xsl:template match="node()">
  <!-- since we're going to draw a line from the parent
       to the node, we first need to ask "do you know
       where your parents are?" -->
  <xsl:variable name="parent-x">
    <xsl:call-template name="get-x-coordinate">
      <xsl:with-param name="node" select=".."/>
    </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="parent-y">
    <xsl:call-template name="get-y-coordinate">
      <xsl:with-param name="node" select=".."/>
    </xsl:call-template>
  </xsl:variable>
  <!-- then we need to know where we ourselves are at -->
  <xsl:variable name="self-x">
    <xsl:call-template name="get-x-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="self-y">
    <xsl:call-template name="get-y-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:variable>
  <!-- now we can draw the line -->
  <xsl:call-template name="drawpath">
    <xsl:with-param name="fromX" select="$parent-x"/>
    <xsl:with-param name="fromY" select="$parent-y"/>
    <xsl:with-param name="toX" select="$self-x"/>
    <xsl:with-param name="toY" select="$self-y"/>
  </xsl:call-template>
  <!-- place a label on the node 
    (each node type gets a different label) -->
  <xsl:apply-templates select="." mode="label">
    <xsl:with-param name="self-x" select="$self-x"/>
    <xsl:with-param name="self-y" select="$self-y"/>
  </xsl:apply-templates>
  <!-- descend to the next level down -->
  <xsl:apply-templates/>
</xsl:template>

<!-- label for each node type -->

<xsl:template match="*|/" mode="label">
  <!-- the default parameters are gratuitous: just being safe -->
  <xsl:param name="self-x">
    <xsl:call-template name="get-x-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:param>
  <xsl:param name="self-y">
    <xsl:call-template name="get-y-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:param>
  <xsl:if test="..">
    <!-- element nodes get a little dot -->
    <circle cx="{$self-x}" cy="{$self-y}" 
    r="{$element-dot-radius}" 
    style="stroke:none; fill:{$tree-color}"/>
  </xsl:if>
  <text x="{$self-x + $writing-bump-over}" 
    y="{$self-y - $writing-bump-up}"
        style="{$element-font-style}; 
    stroke:none; fill:{$element-color}">
    <xsl:if test="not(..)">
      <!-- the root node gets labeled with a / -->
      <xsl:text>/</xsl:text>
    </xsl:if>
    <xsl:value-of select="local-name()"/>
    <xsl:if test="@*">
      <!-- any attribute nodes are written out too -->
      <tspan style="{$attribute-font-style}; 
    stroke:none; fill:{$attribute-color}">
        <xsl:for-each select="@*">
            <xsl:text>&#xA0;</xsl:text>
            <xsl:value-of select="local-name()"/>
            <xsl:text>="</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>"</xsl:text>
        </xsl:for-each>
      </tspan>
    </xsl:if>
  </text>
</xsl:template>

<xsl:template match="text()" mode="label">
  <xsl:param name="self-x">
    <xsl:call-template name="get-x-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:param>
  <xsl:param name="self-y">
    <xsl:call-template name="get-y-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:param>
  <!-- text nodes are marked with a little box -->
  <rect x="{$self-x - ($text-box-width div 2)}"  
    y="{$self-y - ($text-box-height div 2)}"  
    width="{$text-box-width}" 
    height="{$text-box-height}" 
    style="stroke:{$tree-color}; 
    fill:{$tree-color}"/>
  <text x="{$self-x + $writing-bump-over}" 
    y="{$self-y - $writing-bump-up}"
        style="{$text-font-style}; 
    stroke:none; fill:{$text-color}">
    <xsl:text>"</xsl:text>
    <xsl:value-of select="substring(.,1,$max-text-length)"/>
    <!-- truncate the text node to $max-text-length -->
    <xsl:if test="string-length(.) &gt; $max-text-length">
      <!-- add an ellipsis if necessary -->
      <xsl:text>...</xsl:text>
    </xsl:if>
<!-- replace the value-of with this call
     if you want or need to escape whitespace characters
    <xsl:call-template name="escape-ws">
      <xsl:with-param name="text" select="." />
    </xsl:call-template>
-->
    <xsl:text>"</xsl:text>
  </text>
</xsl:template>

<xsl:template match="processing-instruction()" mode="label">
  <xsl:param name="self-x">
    <xsl:call-template name="get-x-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:param>
  <xsl:param name="self-y">
    <xsl:call-template name="get-y-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:param>
  <!-- PI nodes a marked with a little arrow -->
  <polygon points="{$self-x + ($text-box-width div 2)},
    {$self-y},{$self-x - ($text-box-width div 2)},
    {$self-y - $text-box-width},
    {$self-x - ($text-box-width div 2)},
    {$self-y + $text-box-width}" style="fill:
    {$tree-color}"/>
  <text x="{$self-x + $writing-bump-over}" 
    y="{$self-y - $writing-bump-up}"
        style="{$code-font-style}; stroke:none; 
    fill:{$PI-color}">
    <xsl:text/>&lt;?<xsl:value-of 
    select="concat(local-name(), ' ', .)"/>?&gt;
    <xsl:text/>
  </text>
</xsl:template>

<xsl:template match="comment()" mode="label">
  <xsl:param name="self-x">
    <xsl:call-template name="get-x-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:param>
  <xsl:param name="self-y">
    <xsl:call-template name="get-y-coordinate">
      <xsl:with-param name="node" select="."/>
    </xsl:call-template>
  </xsl:param>
  <!-- comment nodes are marked with a triangle -->
  <polygon points="{$self-x - ($text-box-width div 2)},
    {$self-y},{$self-x + ($text-box-width div 2)},
    {$self-y - $text-box-width},
    {$self-x + ($text-box-width div 2)},
    {$self-y + $text-box-width}" 
    style="fill:{$tree-color}"/>
  <text x="{$self-x + $writing-bump-over}" 
    y="{$self-y - $writing-bump-up}"
        style="{$code-font-style}; stroke:none; fill:{$comment-color}">
    <xsl:text/>
&lt;!-- <xsl:value-of select="."/> --&gt;<xsl:text/>
  </text>
</xsl:template>

<!-- template to draw the line from one node 
    to the next ... feel free to enhance ... -->

<xsl:template name="drawpath">
  <xsl:param name="fromX" select="10"/>
  <xsl:param name="fromY" select="10"/>
  <xsl:param name="toX" select="20"/>
  <xsl:param name="toY" select="20"/>
  <g style="stroke:{$tree-color}; 
    stroke-width:{$line-thickness}; stroke-linecap:round" >
    <line x1="{$fromX}"  y1="{$fromY}" x2="{$fromX}" y2="{$toY}" />
    <line x1="{$fromX}"  y1="{$toY}" x2="{$toX}" y2="{$toY}" />
  </g>
</xsl:template>


<!-- recursive template to escape backslashes, 
    apostrophes, newlines and tabs -->
<!-- gratefully duplicated from Jeni Tennison's 
    and Mike Brown's ASCII Art-
     Tree Viewing stylesheet. -->

<xsl:template name="escape-ws">
    <xsl:param name="text" />
    <xsl:choose>
        <xsl:when test="contains($text, '\')">
            <xsl:call-template name="escape-ws">
                <xsl:with-param name="text" 
    select="substring-before($text, '\')" />
            </xsl:call-template>
            <xsl:text>\\</xsl:text>
            <xsl:call-template name="escape-ws">
                <xsl:with-param name="text" 
    select="substring-after($text, '\')" />
            </xsl:call-template>
        </xsl:when>
        <xsl:when test="contains($text, $apos)">
            <xsl:call-template name="escape-ws">
                <xsl:with-param name="text" 
    select="substring-before($text, $apos)" />
            </xsl:call-template>
            <xsl:text>\'</xsl:text>
            <xsl:call-template name="escape-ws">
                <xsl:with-param name="text" 
    select="substring-after($text, $apos)" />
            </xsl:call-template>
        </xsl:when>
        <xsl:when test="contains($text, '&#xA;')">
            <xsl:call-template name="escape-ws">
                <xsl:with-param name="text" 
    select="substring-before($text, '&#xA;')" />
            </xsl:call-template>
            <xsl:text>\n</xsl:text>
            <xsl:call-template name="escape-ws">
                <xsl:with-param name="text" 
    select="substring-after($text, '&#xA;')" />
            </xsl:call-template>
        </xsl:when>
        <xsl:when test="contains($text, '&#x9;')">
            <xsl:value-of select="substring-before($text, '&#x9;')" />
            <xsl:text>\t</xsl:text>
            <xsl:call-template name="escape-ws">
                <xsl:with-param name="text" 
    select="substring-after($text, '&#x9;')" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise><xsl:value-of select="$text" /></xsl:otherwise>
    </xsl:choose>
</xsl:template>


</xsl:stylesheet>