Various
I'm trying to remove the h1 from my source with the "except" and it
doesn't work.
ex:<xsl:copy-of select="* except
(//xhtml:div[@class='border']//xhtml:h1)" />
When I do the same logic to class=border section it work??
<xsl:copy-of select="* except(//xhtml:div[@class='border'])" />
What I'm I missing, with the except for the removal of that section
h1???
source:
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
</head>
<body>
<!--googleoff:all-->
<div class="page">
<div class="center">
<div class="border">
<h1>
<a name="cont" id="cont">
Aviation Security </a>
</h1>
<p>The Government of Canada has committed more than programs include the
following:</p>
</div>
</div>
</div>
</body>
</html>
Mike Kay answers
<xsl:copy-of select="* except X"/> means "make an exact copy of all the children, except any child selected by
the expression X (which should not be copied at all).
I suspect you are misunderstanding it to mean "copy all the children,
modifying them as you do so to leave out any nodes selected by X".
Clearly that doesn't work: the select expression selects all the children,
then unselects some of them, then xsl:copy-of copies all those that remain. Wendell Piez adds
What you are missing is an understanding of XPath syntax and how it is relating to your tree architecture.
It becomes clearer if you expand your XPaths into long syntax. You are currently using abbreviated syntax.
So --
First the XPath that is working for you:
* except(//xhtml:div[@class='border'])
is short for
child::* except
(/descendant-or-self::node()/child::xhtml:div[attribute::class='border']) This is saying: "copy all children, excluding from this set any members of the set of xhtml:div[@class='border'] elements anywhere in the document".
Now the XPath that isn't working:
* except (//xhtml:div[@class='border']//xhtml:h1) This is short for
child::* except
(/descendant-or-self::node()/child::xhtml:div[attribute::class='border']
/descendant-or-self::node()/child::xhtml:h1) This is saying: "copy all children, excluding from this set any members of the set of xhtml:h1 descendants of xhtml:div[@class='border'] elements anywhere in the document"
Your stylesheet is doing this. Since no xhtml:h1 elements are children of the context node where the expression is evaluated (whichever xhtml:div[@class='center'] has matched your template), all the children are copied. (There are some among the descendants of the children you have asked to copy, but the 'except' operation doesn't work that way.)
In order to accomplish your filtering, you can't simply use a copy-of instruction, since xsl:copy-of simply copies subtrees from your source document without change. That is, you can exclude branches from being copied by using XPath as in your first case, but having decided to copy a branch using xsl:copy-of, you can't also modify it. In order to do this, you need to use a somewhat more sophisticated approach. Your problem is actually a good example of what we call a "modified identity transform", since the result is just a modified version of the source. It could be done in a stylesheet with two templates like this:
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="xhtml:h1"/>
How does this work? You need to read up on templates and the xsl:apply-template instruction.
The idea of the "context node" and its relation to the evaluation of XPath is also critical. Note that if you apply templates to attributes and child nodes in the 'remove' mode, you also have to match them in 'remove' mode to have them copied (or removed).
I left the 'remove' mode off the templates I then wrote to illustrate. |