Multiple XSLt Transforms?

R

rush

I have a DTD that defines new elements "mytextfield" and "mysn", and
does it as an extension to XHTML. The idea is that my XML markup is
actually valid XHTML according to my DTD. This all works just fine.

After getting the DTD to work, I defined a XSL stylesheet that would
transform my markup into XHTML that would display correctly in a
browser. At first this meant that everywhere I encontered a
"mytextfield" element in the markup, I would transform it into a
<input type="text" /> element in the output, and preserve whatever
attributes were on the "mytextfield" element. Again, this worked just
fine.

My next step was to define the "mysn" element. A "mysn" is actually a
collection of my custom elements, each of which has a XHTML (browser)
representation. The simplified example below shows mysn as a
mytextfield
with a custom text label. I could have written the transform so that
the output is in terms of standard XHTML elements, but what I want to
do is define the mysn transformation in terms of my underlying
elements,
then use their transformations to create the XHTML that the browser
will
display nicely. This is also because I have a case where my original
markup will be written in terms of the more abstract elements, such as
mysn, but I need to transform it into the less abstract but still
custom
elements (mytextfield).

For instance, if this is my original (simplified) markup:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="myxform.xsl" type="text/xsl"?>
<!DOCTYPE html SYSTEM "mydtd.dtd">
<html><head></head>
<body><form>
<p><mytextfield size="30" name="FirstName" />First Name</p>
<mysn />
</form></body>
</html>


I would like the intermediate transform to be:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="myxform.xsl" type="text/xsl"?>
<!DOCTYPE html SYSTEM "mydtd.dtd">
<html><head></head>
<body><form>
<p><mytextfield size="30" name="FirstName" />First Name</p>x
<p><mytextfield name="NewSerialNum" size="40"/>Please enter your
serial number</p>
</form></body>
</html>

But I want the transform that the browser sees to be:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="myxform.xsl" type="text/xsl"?>
<!DOCTYPE html SYSTEM "mydtd.dtd">
<html><head></head>
<body><form>
<p><input type="text" size="30" name="FirstName" />First Name</p>
<p><input type="text" name="NewSerialNum" size="40"/>Please enter
your serial number</p>
</form></body>
</html>

Here is the form of the XSL stylesheet that I want to use:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:eek:utput method="html" version="4.0" />

<!--========================================================
Template for matching an mytextfield element in a form.
Morph it into a text input, copying some of the attributes.
============================================================-->
<xsl:template match="form//mytextfield">
<xsl:element name="input">
<xsl:attribute name="type">
<xsl:text>text</xsl:text>
</xsl:attribute>

<xsl:for-each select="@id | @size | @maxlength | @name">
<xsl:attribute name="{name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:for-each>

</xsl:element>
</xsl:template>

<!--=================================================
Template for matching an mysn elementiwithin a form.
Turn it into a mytextfield with a known name
======================================================-->
<xsl:template priority="1.0" match="form//mysn">
<xsl:element name="p">
<mytextfield name="NewSerialNum" size="40"/>
<xsl:text>Please enter your serial number</xsl:text>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

The actual usage scenario is much more complicated than this. People
that I do not know and cannot easily interact with will be writing the
markup. I need a way to validate what they write, but I would really
like it if they could just display it with a web browser.

I have spent a couple of days reading and searching the web, looking
for examples. I have also tried using entitities, <xsl:include>, and
variations on named templates. It looks like XSLT version 2.0 will
handle this case, but that 1.0 probably can't. Does anyone know of
some clever way to implement such two stage transformations using
version 1.0?

Thanks and sorry for the long post,
Rush
 
D

David Carlisle

<xsl:template match="form//mytextfield">
<xsl:element name="input">
<xsl:attribute name="type">
<xsl:text>text</xsl:text>
</xsl:attribute>

<xsl:for-each select="@id | @size | @maxlength | @name">
<xsl:attribute name="{name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:for-each>

</xsl:element>
</xsl:template>


That could be written much more simply as

<xsl:template match="mytextfield">
<input type="text">
<xsl:copy-of select="@id | @size | @maxlength | @name"/>
</input>
</xsl:template>


To answer your question:

It looks like XSLT version 2.0 will
handle this case, but that 1.0 probably can't. Does anyone know of
some clever way to implement such two stage transformations using
version 1.0?

the standard XSLT 1.0 way to do two transforms is just simply to use two
xslt stylesheets and call one then the other. Even in a browser setting
this is possible with a bit of javascript.

Alternatively you may be able to do the two transforms within one
stylesheet by first transforming into a varibale and then applying the
templates of the second transform to that variable. this however relies
on a node-set() extension function to convert the result tree fragment
in the variable to a node set suitable for input to the second pass.
Pretty much every XSLT engine has this extension (the notable exception
being the transformiix engine in mozilla)

David
 
R

rush

Thanks for the reply, David. Comments and followup questions are
inline, if you care to spend any more time on this. I am new to
this XML/XSL stuff and I don't yet know what all the pieces are,
much less how to put them all together. I really appreciate the help.
That could be written much more simply as

This is cool! I didn't realize you could use copy-of with attributes.
Thanks.
To answer your question:


the standard XSLT 1.0 way to do two transforms is just simply to use two
xslt stylesheets and call one then the other. Even in a browser setting
this is possible with a bit of javascript.

You wouldn't care to elaborate a little bit here, would you?
Alternatively you may be able to do the two transforms within one
stylesheet by first transforming into a varibale and then applying the
templates of the second transform to that variable. this however relies
on a node-set() extension function to convert the result tree fragment
in the variable to a node set suitable for input to the second pass.
Pretty much every XSLT engine has this extension (the notable exception
being the transformiix engine in mozilla)

David

I found this:
http://www-106.ibm.com/developerworks/xml/library/x-tipxsltmp.html
which showed exactly how to do this with node-set(). I tried it using
xsltproc
and it worked like a charm! Firefox won't deal with it (as you
mentioned),
but I can figure out some way to deal with that.

- Rush
 
D

David Carlisle

You wouldn't care to elaborate a little bit here, would you?


The js interface to XSLT in moz is here

http://www.mozilla.org/projects/xslt/js-interface.html

IE has something similar.
Basically the idea is you use that interface to apply your first
transform, you then get a DOM which you stuff into a second transform
that produces a DOM with (X)HTML elements which you then allow to drop
through to the browser's renderer.

David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top