Re: [xsl] SVG object creation with XSLT using successive abstraction layers

Subject: Re: [xsl] SVG object creation with XSLT using successive abstraction layers
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Thu, 03 Nov 2005 17:08:27 -0500
Luis,

I've done this -- in fact, in a similar application, in which descriptive XML tagging is rendered into SVG.

But in order to achieve it seamlessly, I used XSLT 2.0 (then draft, now a Candidate Recommendation from W3C -- that is, not finished yet but getting there). XSLT 2.0 presents a better environment for this kind of thing because it provides for transparent processing of its results in a single run of a stylesheet. This makes the pipelining that Jon described much easier.

You can see this described, sketchily, at http://www.xslt.com/html/xsl-list/2005-08/msg00507.html, but the idea is simple: a template matching a higher-order object simply generates the basic object(s) from it, then applies templates to it/them to render them down into the final (SVG) format.

So let's say you have a higher-order object 'xbox' like this

<xbox x="40" y="20" width="300" stroke-width="6"/>

which is defined as being a more succinct version of a collection of basic objects

<box x="40" y="30" width="300" height="150"/>
<drawX x="40" y="30" width="300" height="150" stroke-width="6"/>

which in turn render into SVG

<svg:rect class="box" x="40" y="30" width="300" height="150"/>
<svg:path d="M 40 30 L 340 180 M 40 180 L 340 30" stroke-width="6"/>

You could have

<xsl:template match="box">
  <svg:rect class="box" width="{@width}" height="{@height}">
    <xsl:copy-of select="@x|@y"/>
  </svg:rect>
</xsl:template>

<xsl:template match="drawX">
  <xsl:variable name="x1" select="@x"/>
  <xsl:variable name="x2" select="@x + @width"/>
  <xsl:variable name="y1" select="@y"/>
  <xsl:variable name="x2" select="@y + @height"/>
  <svg:path d="M {$x1} {$y1} L {$x2} {$y2} M {$x1} {$y2} L {$x2} {$y1}">
    <xsl:copy-of select="@stroke-width"/>
  </svg:path>
</xsl:template>

and then

<xsl:template match="xbox">
  <xsl:variable name="expanded">
    <box height="{@width div 2}">
      <xsl:copy-of select="@x | @y | @width"/>
    </box>
    <drawX height="{@width div 2}">
      <xsl:copy-of select="@x | @y | @width | @stroke-width"/>
    </drawX>
  </xsl:variable>
  <xsl:apply-templates select="$expanded"/>
</xsl:template>

So the "higher order" object is rendered by expanding it into a variable, and then applying templates to that variable as if it was part of the source from which it was derived.

It works fine. As the link above suggests, I've been calling this technique "micropipelining"; it's basically a variant of what's been called "multiphase processing". Just take some care to make sure higher-order objects devolve properly into more primitive ones, or you may get into endless loops.

This can also be done in 1.0 with a little more work, if you're willing to use a node-set() extension function.

Cheers,
Wendell

At 01:29 PM 11/3/2005, Jon wrote:
I'd suggest perhaps considering pipelining (executing a series of
stylesheets, each one using the output of the last).  It's difficult
to recommend anything specific without knowing details of the system.
But essentially something checks the results of the transformation,
and if it still contains higher, run the stylesheet on it again.  I
suggest this because I've found converting into SVG tends to be easier
as a sequence of transformations.



====================================================================== Wendell Piez mailto:wapiez@xxxxxxxxxxxxxxxx Mulberry Technologies, Inc. http://www.mulberrytech.com 17 West Jefferson Street Direct Phone: 301/315-9635 Suite 207 Phone: 301/315-9631 Rockville, MD 20850 Fax: 301/315-8285 ---------------------------------------------------------------------- Mulberry Technologies: A Consultancy Specializing in SGML and XML ======================================================================

Current Thread