RE: [xsl] XHTML to XHTML transform

Subject: RE: [xsl] XHTML to XHTML transform
From: "M. David Peterson" <m.david@xxxxxxxxxx>
Date: Fri, 2 Apr 2004 11:33:52 -0700
Hey Jeff,

Apply-templates is exactly what you want to do... and youre on the right
track with the output tag.  XSLT 1.0 support HTML, XML, and TEXT output.
The HTML output is not XHTML compliant in 99.100% of the cases and as
such you need to use XML and then set omit-xml-declaration to yes in the
xsl:output element to ensure the browser doesn't try to process it as
XML instead of XHTML.  So your xsl:output tag should read <xsl:output
method="xml" omit-xml-declaration="yes"/>

Now, as far as parsing through your data file and transforming the trick
is matching each element node name to a template using the match
attribute.  You start the process from your first template as such.

<xsl:template match="/">
	<xsl:apply-templates select="*"/>
</xsl:template>

In actual fact you don't even need to use the select attribute if you
are going to process the entire tree.  Either way in your case will
work.

Now just go through and create an xsl:template with a match attribute
equal to the name of the element you want to match for every element.
So in the case of <BOX> you would do the following:

<xsl:template match="box">

within your template you now tell the process what you want to copy into
the output.  In the case of <BOX> you want to copy an element called
<DIV>.  So you use the xsl:element element to do that.  For example:

<xsl:element name="DIV">

Now, before you close the xsl:element element you need to add the value
of the DIV element as well as any attributes that need to go in there as
well.  In the case where it is an exact match as far as attribute names
just use xs:copy-of and use "@*" in the select attribute. For examplte

<xsl:copy-of select="@*/> will copy all of the attributes of the current
context node, in this case "BOX", into the element "DIV" in the output.

But wait!  Don't  close that tag!  ;)  The next step in applying
recursive templates to the body of your source data is to tell it to
keep going.  Now you may be saying "but don't we want to print the value
of the text contained within the BOX tag (now to be the DIV tag)?"  Yes,
we do, but xsl:apply-templates is going to take care of that for us.
The reason?  <xsl:apply-templates/> will search for the next element
within the current Result Tree Fragment, which in this case is any tags
contained within the "BOX" element.  As soon as it finds one it will
continue the processing but not before it deposits the text content that
came before that tag first.  Sounds weird, I know, but it makes sense
when you think of it from the stand point of a processor.  Its looking
for valid mark up tags, not text.  It doesn't know what to do with just
plain text (well, if its starts with the "<" sign it does but that's the
whole point) so it just leaves it behind.  It may seem like a bug but it
is by design and for good reason.  Imagine the confusion that the
processor would create if it carried all that extra text along with it
if the user forgot to "grab" the data with <xsl:value-of>!  Wouldn't be
pretty...

Now, you can close that xsl:element tag.

Ok, so now you've continued your recursion process by adding an
xsl:apply-templates to the mix to ensure processing of the tags
contained within the tags takes place.  So you should now have a
template that looks like this...

<xsl:template match="BOX">
	<xsl:element name="DIV">
		<xsl:copy-of select="@*/>
		<xsl:apply-templates/>
	</xsl:element>
</xsl:template>

The output of this transform would look like this(ill make up some
attributes given there are none in your example data  -- there is in
your output so ill just assume that those are the correct attributes):

<DIV id="box">
	rest of the elements and attributes that are matched to either
this or another template.

</DIV>

So, there you have it...  make sure you use the xsl:apply-templates in
every template to ensure continued recursive processing and youll be all
set.

Hope this helps!  And to all of those who are reading this that I have
promised either an email or help with a solution I apologize for not
getting those to you sooner.  Ive been out with a client the last two
days and have only had a few moments to check email without enough time
to reply/respond properly.  I will go through the last 2 days of list
mail and see what I may have missed.  Hopefully I will get to that
before the end of the day but please forgive me if it takes until the
weekend to get caught up!

Best of luck Jeffrey!  Feel free to respond with more questions
(remembering to check the archives first -- there sometimes hard to find
what you want but at least give it an effort first and then feel free to
come back with more questions.  If not me then no doubt one of the many
many experts in here will be more than happy to help point you along in
the right direction)

Best regards,

<M:D/>
 


-----Original Message-----
From: Jeffrey Moss [mailto:jeff@xxxxxxxxxxxx] 
Sent: Friday, April 02, 2004 10:56 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] XHTML to XHTML transform

I want to create XHTML files and run them through some transforms to
turn
things like this:

<BODY>
<BOX>
    <TITLE>Title</TITLE>
    Hello World
    <FOOTER>Footer</FOOTER>
</BOX>
</BODY>

Into this:

<BODY>
<DIV ID="box">
    <DIV ID="top">
        <DIV ID="topleft">
        <DIV ID="topright">
        <SPAN ID="title">Title</SPAN>
    </DIV>
    Hello World
    <DIV ID="bottom">
        <DIV ID="bottomleft">
        <DIV ID="bottomright">
        <SPAN ID="footer">Footer</SPAN>
    </DIV>
</DIV>
</BODY>

XHTML content to remain intact, even stuff inside the "footer" element,
and
everything. I'm pretty sure this will require the <apply-templates />
tag
all over the place, which is fine.

I have tried a number of different approaches already. I played around
with
the xmlns:xhtml namespace in my XSL file (not sure if I ever did this
correctly, I don't think I fully understand what namespaces do).

I tried XSL copy in my templates but there doesn't seem to be a way to
say
"apply templates or else copy node and apply templates"

I also tried to define a template that matches "*" for any unmatched
node,
and copy the element and parameters and then apply templates on the
content.

I also played with the xsl:output tag to see if I could get that to do
something cool, but no.

Please help!

-Jeff

Current Thread