Re: [xsl] deep "copy-of" a source fragment

Subject: Re: [xsl] deep "copy-of" a source fragment
From: Terence Kearns <terencek@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 05 Sep 2002 16:07:30 +1000
Dion, you are so spot on.

I did exactly as you said and it worked (see reply post to dave. I read your post after I read Daves's). This has been an extremely valuable lesson for me. I've spent some time reading up on XSL (on the bus, so not much experimentation) and I should have known about the namespace stuff but it just didn't twig - despite have spent hours and hours labouring over the problem.

Your explanation was very well put and should be posted at
http://www.dpawson.co.uk/xsl/sect2/N1930.html
IMHO

Thanks for the elaboration.

PS. Next time I will post the source as well. I didn't want to clutter the post too much - but it is better to have too much information than too little.

Dion Houston wrote:
Hi Terence!

Welcome to the list!

This was a highly tricky one, and since you didn't give us a sample of
your XML it took me a while to figure it out...  The problem is not what
you think it is, though :)

Before giving you the answer, the first thing that puzzled me was how it
could copy just text nodes...  With <xsl:value-of> this is extremely
easy, but not so with <xsl:copy-of> (for sake of trivia, <xsl:copy-of
select="text()"/> should do the trick).  The other question was how
changing your XPath expression didn't change anything...

Peter (below) hit the first issue perfectly.  The problem is that your
xsl:copy-of ---WASN'T DOING ANYTHING---!  Changing the match expression
was causing the default template rule for text to run which was copying
your text nodes.  This was giving the illusion of your statement copying
just the text.

The bigger question is WHY wasn't the copy-of doing anything.  This was
actually trickier, and I haven't seen the answer posted yet.  If you
take a look at HTML Tidy's XHTML output, you should see the following
line:

<html xmlns="http://www.w3.org/1999/xhtml";>

The key here (as dozens of people will tell you) is that a namespace is
in use, even though it is the default.  This causes every XPath
expression without a prefix to fail (this is a FAQ).  To solve this,
simply change your XSLT to:

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

     <xsl:template match="x:body">
         <xsl:copy-of select="node()"/> <!-- copies the children
exclusive of body -->
     </xsl:template>

     <!-- change the default text rule to not output text -->
     <xsl:template match="text()"/>
</xsl:stylesheet>

Thanks for the puzzler, and HTH!

Dion
-----Original Message-----
From: Peter Davis [mailto:pdavis152@xxxxxxxxx] Sent: Wednesday, September 04, 2002 12:06 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] deep "copy-of" a source fragment


On Tuesday 03 September 2002 23:48, Terence Kearns wrote:

but if I change
	match="/"
to
	match="/html/body"

then I get leaf nodes again :(
I also tried

...


makes no difference if I change

	select="node()"
to
	select="."
or
	select="@*|node()"

Is there no way at all to copy a fragment from the source tree onto

the


result tree?!


The problem is, if you have:

<xsl:template match="/html/body">
  ...
</xsl:template>

then the default template will be applied to all the nodes that aren't
part of /html/body. The default template is to copy text nodes and ignore
everything else, so that might explain your problem.


Instead of changing select to select="node()" and match="/html/body",
you should try,


<xsl:template match="/">
  <xsl:copy-of select="html/body/node()"/>
</xsl:template>

If that doesn't work, then I don't know what's wrong.

An alternative to using copy-of is to use the "identity template", which
can look something like this (untested):


<!-- ignore all nodes unless otherwise specified -->
<xsl:template match="node()" priority="0"/>

<xsl:template match="/html/body//@* | /html/body//node()">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates select="node()"/>
  </xsl:copy>
</xsl:template>

You might want to go this route if you ever want to apply other
templates to specific elements in the /html/body//* tree. Using xsl:copy-of doesn't
allow you to modify the output of the copy with other templates. If you don't


think you'll ever need to apply other templates, then copy-of should
work fine.




--
my staff profile:
http://www.canberra.edu.au:8888/cn%3dKearns%20Mr%20T.%2c%20ou%3dClient%20Services%20Division%2c%20o%3dUniversity%20of%20Canberra%2c%20c%3dAU



XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list


Current Thread