A use of SVG in HTML

I have a Python script that provides a web interface to some particular 

It responds to HTTP requests by executing the application (with certain 
input parameters coming from the request) to generate some data. It 
creates an HTML table displaying the data, and executes Graphviz to 
produce a pretty picture of the same data.

To avoid executing the application more times that necessary, and to 
avoid adding some complex caching logic into the script, it has to 
return the table and graph in a single HTTP response.

To allow decent-quality zooming of the graph, it is generated with 
Graphviz's SVG output option. (This also keeps the file size down - the 
uncompressed SVG is about 20% of the size of an equivalent PNG.)

To have the SVG automatically take up the right amount of space on the 
page, and to allow easy 'view source' debugging of the SVG, it is output 
inline in the HTML response (instead of in a base64 data: URI).

The Graphviz SVG output is first parsed into a DOM in Python. The <svg> 
element is extracted (hence removing the <!DOCTYPE> etc), then modified 
a bit (removing some links and styles, changing some title text, etc), 
then serialised (using the DOM library's standard XML serialiser) and 
concatenated into the XHTML response string.

A later version of this system added some client-side interactivity. The 
HTML code contains something like:

     function mouseover() {
         this.childNodes[1].setAttribute('class', 'hovered');
     window.onload = function () {
         var a = document.getElementsByTagNameNS(
             'http://www.w3.org/2000/svg', 'a');
         for (var i = 0; i < a.length; ++i) {
             a[i].onmouseover = mouseover; // plus similar for mouseout
     ellipse.hovered { fill: #ff6 !important; }
     path.hovered { stroke: #f00 !important; stroke-width: 2px; }

For SVG in text/html, it would be good if the same code still worked - I 
don't want to have to remember two different ways of processing DOMs, 
and I don't want to learn about CSS namespaces.

The HTML response can contain multiple SVG graphs. Since they are all 
generated independently by Graphviz, they all have a <g id="graph0" ...> 
(plus lots of other common IDs). It would take far too much effort to 
uniquify the IDs and fix up all the references (particularly since the 
references can be in style="url(#...)" too).

Currently I never use the IDs, so that doesn't matter, but this will 
break if the SVG starts containing ID references (e.g. for <defs>) or if 
I start using getElementById, so it would be good if this overlapping ID 
situation could be handled well. (E.g. references inside an <svg>-rooted 
subtree could preferentially match IDs in the same subtree, before 
looking outside to the whole HTML document.)

The interactive script also needs to extract some data from graph nodes 
(a list of paths leading to that node) when the user selects them, to 
display in an HTML table. Currently it does something very much like:

   <svg xmlns:custom="custom-data" ...>
     <g custom:paths="[[0,1,2],[3,4,2]]" .../>

where the Python script adds the custom:paths attribute, and the 
onmouseover script does getAttributeNS('custom-data', 'paths') and 
parses and processes the data. I don't much care about conformance, but 
I need some way to attach arbitrary data to elements, and it shouldn't 
be harder than adding an attribute.

This would all be slightly nicer if I didn't have to spend time looking 
up the XHTML namespace and making sure the whole HTML part of the 
response was well-formed XML. It isn't a compelling case for supporting 
SVG in text/html, since it works alright as application/xhtml+xml, but 
if SVG is supported to some extent then it would be nice to support this 
case too, rather than only supporting simple cases and telling people to 
go away and use XHTML if they want something fancier.

Philip Taylor

Received on Sunday, 16 March 2008 01:00:17 UTC