1. | Select and match |
| Mike Brown Certain instructions have a select attribute, others have a
match attribute, but never both. You "select" a set of nodes
that you want to process. You declare that a template
"matches" nodes that have a certain pattern.
An XSLT processor starts at the root node and finds the
template that best matches that node. It executes the
instructions in that template. Then it is done. An
apply-templates instruction in that one template tells the
processor to select another set of nodes and, for each of
those nodes, find the template that best matches it and
execute the instructions in it. Many templates may match a
given node; there are rules in the spec for determining
which template will be chosen.
Templates are not executed in a specific order. Templates
only say "if the XSLT processor decides that this
template provides the best match for the node *that it is
already looking at*, here are some instructions to
execute." They are like subroutines, whereas the main
program is hidden inside the XSLT processor.
|
2. | Using parameter with xsl:for-each |
| David Carlisle
you can't in standard xsl evaluate a string as an xpath
expresion. you have <xsl:value-of select="$selectpath"/> but you passed it a string: "Resources/Resource"
so it is equivalent to
<xsl:value-of select="'Resources/Resource'"/>
Mike Brown expands:
To restate what David Carlisle was saying, if an expression that
identifies a node-set is expected, the only kind of variable you can use
in the expression is one that is itself a node-set. You can't use a string
that resembles an expression that, if evaluated as an expression, would
return a node-set.
So you can never define a string like 'foo/bar' and then put that in an
expression like /path/to/$yourstring/and/beyond. You can, however, use
non-node-set variables in predicates. So if you had, say, variable $x that
was the string 'foo', /path/to/*[name()=$x] wouldn't be out of the
question.
|
3. | Invalid predicate |
| Gary L Peskin
Why is it that a predicate is not allowed when I do something like <xsl:variable name="foo" select=".[@id=1]"/> I mean if the current node has an 'id' attribute numerically equal to the
number 1, then $foo will be the current node; otherwise it will be an
empty node-set, right? Both SAXON and XT gripe at me for having a
predicate after . at all. I can't even say ".[true()]"! What's the deal?
I don't see anything in XPath prohibiting this. Try self::node()[@id=1] The "." is an AbbreviatedStep (production [12]) and cannot be followed
by a predicate according to production [4]. That production requires
AxisSpecifier NodeTest Predicate* so "." is not just self::node(), it is an abbreviation of the
*step* self::node() -- axis, node test, and any predicates inclusive.
Makes sense, then, but isn't obvious by the prose portion of the XPath
spec.
Mike Kay adds:
"." is an abbreviated step, not an abbreviated the-part-of-the-step-before
the-predicates. Why that should be, I don't know, but that's what XPath
says.
|
4. | footnotes |
| Jeni Tennison
>What I need to do is to process all FN elements located prior to the current
><P> element, BUT after the last set of <FN> elements I already processed!
I guess that your XML looks something like:
<doc>
<FN id="fn1">
<P>Footnote 1</P>
</FN>
<P id="para1">Paragraph 1</P>
<section>
<FN id="fn2">
<P>Footnote 2</P>
</FN>
<H1>Heading</H1>
<P id="para2">Paragraph 2</P>
</section>
</doc>
In other words:
(a) FNs are always associated with (and processed alongside) Ps, not with
any other elements
(b) FNs may not immediately precede their respective P
If this is the case, given that your current node is a P element, you can
get the FN elements between it and the previous P using:
preceding::FN[generate-id(following::P[1]) =
generate-id(current())] In other words:
any FN element that precedes the current element in the source document
such that:
the unique ID for the immediately following P of the FN is the same as
the unique ID of the current (P) element [You don't have to generate-id()s if you have some other natural identifier
for the P elements, like an 'id' attribute.]
So, you could probably use something like:
<xsl:template match="P">
<xsl:apply-templates />
<xsl:apply-templates
select="preceding::FN[generate-id(following::P[1]) =
generate-id(current())]" />
</xsl:template>
<xsl:template match="FN">
<p /><xsl:value-of select="P" />
</xsl:template>
The reason I've done away with the 'Dump Footnotes' named template was that
it's not really necessary: you can just select the FNs that you want to
process within the 'P'-matching template as above rather than passing them
as a parameter to a template. Of course you can change it back if you want
to :)
|
5. | Unknown element selection (parent is known) |
| Oliver Becker
> How do I select a record without knowing the
> name of it. What I know is the name of the parent,
>
> <PARENT>
> <???>Donald Ball</???>
> <???>23</???>
> </PARENT>
PARENT/*
selects all children of the PARENT element
PARENT/*[1]
selects only the first child
> Another thing i do not know is the number of elements.
count(PARENT/*) |
6. | Selecting only specific elements |
| Miloslav Nic
Source
<a>
<b>some text</b>
<b>some more text</b>
<b>some other text</b>
<b>some last text</b>
<c>some c text</c>
</a>
Wanted output
<a>
<bset>
<b>some text</b>
<b>some more text</b>
<b>some other text</b>
<b>some last text</b>
</bset>
<c>some c text</c>
</a>
Try
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="a">
<a>
<xsl:apply-templates select="*"/>
</a>
</xsl:template>
<xsl:template match="b">
<xsl:if test="not(name(preceding-sibling::*[1])='b')">
<bset>
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::*[1]" mode="set"/>
</bset>
</xsl:if>
</xsl:template>
<xsl:template match="b" mode="set">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::*[1]" mode="set"/>
</xsl:template>
<xsl:template match="*" mode="set"/>
<xsl:template match="*">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
It needs some more work to make it really general, but I hope it
will give you some ideas.
|
7. | Determining if the first child is a specific element |
| David Carlisle
> I need to know if the first child of a node is an
> element (para, in this case). The test needs to be done in the parent's
> <template> element, prior to an <apply-templates/>. Is there a
> straightforward <if> test I can use for this case?
<xsl:if test="*[1][self::para]">David</xsl:if> Jeni Tennison expands:
It's not clear whether you want to know whether it's a specific
element (a para element) or an element rather than some other type of
node (e.g. text or a comment).
You can get the first child node using the XPath:
child::node()[1]
You can get the first child element using the XPath:
child:*[1]
You can test whether something is an element using the test:
self::*
You can test whether something is a para element using the test:
self::para
So, you can find the first child node that is an element using the
XPath:
child::node()[1][self::*]
If the first child node is not an element, then no nodes will be
selected with this XPath. Within an xsl:if test, a node set with no
nodes in it evaluates as false() while one that does hold nodes
evaluates as true(). So, to test whether the first child node of
the current node is an element, use:
<xsl:if test="child::node()[1][self::*]">
...
</xsl:if>
Mike Brown cautions here
Also be careful in this case that you have accounted for the possibility of
any whitespace-only text nodes. So, for example, if your document read:
<CHAPTER>
<para>Here's my first child element, a para.</para>
...
</CHAPTER>
Jeni's test above will fail on account of the whitespace-only text node
preceding the para element (it contains a carriage return and two space
characters).
Adjust for this by saying
<xsl:strip-space elements="CHAPTER"/>
at the top level, or altering your test (somewhat horribly) to:
<xsl:if test="child::node()[not(.=normalize-space(.))][1][self::para]">
...
</xsl:if>
Jeni Continues:
To test whether the first child element of the current node is a para
element, use:
<xsl:if test="child::*[1][self::para]">
...
</xsl:if>
Wendell Piez wraps it up:
But of course after seeing Mike Kay's nice test in another thread, I
realized a slightly more elegant and efficient version would be
<xsl:if test="child::node()[normalize-space(.)][1][self::para]">
...
</xsl:if>
...which reveals further complications (funny how these things are). We
have to make sure it's skipped only if it's a whitespace-only _text_ node
(not, say, an empty element node). So....
<xsl:if test="child::node()[not(self::text()) or
normalize-space(.)][1][self::para]">
...
</xsl:if>
The first predicate evaluates to true if the child node is not a text node
or if it has a non-whitespace string value. The second chooses the first of
these. The third checks to see whether it's a para element.
For evident reasons, that <xsl:strip-space .../> at the top level will be
preferable, if you can use it.
|
8. | Unique element values only |
| Jeni Tennison
> I've tried manipulating the order of the ACHFee element with
> <xsl:sort select="feeLevelBottom"/> and so-on. I've used every
> combination of preceding::, following::, following-sibling:: that I
> can come up with, but I still cannot make ONLY UNIQUE cell contents
> be displayed
Here's what you're missing: axes *always* operate on the structure of
the original XML, it don't matter how much you sort or what axes you
try.
At the moment you trying to do (roughly)
for each ACHfee
sorted according to feeLevelBottom
if you haven't already processed something with the same
feeLevelBottom
then process this one
Instead, you need to turn it around so that you only select the first
ACHfees with a particular feeLevelBottom in the first place, iterate
over them, and sort *them* according to the feeLevelBottom.
For example:
<xsl:for-each select="//ACHFee
[not(feeLevelBottom =
preceding::ACHFee/feeLevelBottom)]">
<xsl:sort select="feeLevelBottom" />
...
</xsl:for-each>
You may find it more efficient to use the Muenchian Method to get the
list of fees with unique feeLevelBottoms. Define a key:
<xsl:key name="fees"
match="ACHFee"
use="number(feeLevelBottom)" />
And then select the ACHFees with unique feeLevelBottom values with:
<xsl:for-each
select="//ACHFee
[count(.|key('fees', number(feeLevelBottom))[1]) = 1]">
<xsl:sort select="feeLevelBottom" />
...
</xsl:for-each>
|
9. | XPath expression for every child but one |
| Francis Norton and Jeni Tennison
> Is it possible to have an XPath expression that means "every child but one"
> E.g. every child except <title>
Yes, I think this came up fairly recently - the other solution is a bit
non-obvious:
<xsl:apply-templates select="*[not(self::title)]"/>
Jeni adds
Or, generally better because it avoids namespace problems:
<xsl:apply-templates select="*[not(self::title)]" />
|
10. | How to check is element has children |
| Michael Kay
I need to test if an element has children
Assuming it is the current element: xsl:if test="node()" for any children, or
xsl:if test="*" for element children.
|
11. | Pruning nodes not required |
| Jeni Tennison
> I would like to be able to generate a stylesheet that will produce
> output documents that exclude all nodes that are not matched by any
> of the xpath expressions.
The first thing is to work out a stylesheet that does what you want
with the expressions hard-coded into it...
> From an algorithm point of view, one solution is to create a
> node-set collection of all nodes that should be copied to the output
> document.
OK, so first work out which nodes have been selected by the
expressions:
<xsl:variable name="selected-nodes"
select="//product/@sku | //product/cost"/>
Then to work out which nodes should therefore be copied - that's all
those nodes that are selected, plus their ancestors: <xsl:variable name="copied-nodes"
select="$selected-nodes | $selected-nodes/ancestor::*"/>
Now, starting from the top (the document element is always the first
in the list of copied nodes), we want to work through the document. If
the element is in the list of selected nodes, then we just want to
copy it completely. Otherwise, we want to copy the element, copy any
attributes that are in the list of selected nodes, and apply templates
to any of its children that are in the list of nodes to be copied.
Now, working out whether a node is in a set of nodes involves a bit of
set manipulation - if you count how many nodes there are in the set
that's the union of the node and the node set, and it's the same as
the number of nodes in the node set, then the node has to be in the
node set. So to work out whether the context node is in the set of
$selected-nodes, I can use:
count(.|$selected-nodes) = count($selected-nodes)
Since $selected-nodes and $copied-nodes are known up front, I'll
create variables that indicate how many nodes are in each of them: <xsl:variable name="nselected-nodes" select="count($selected-nodes)" />
<xsl:variable name="ncopied-nodes" select="count($copied-nodes)"/>
So the template looks like:
<xsl:template match="*">
<xsl:choose>
<!-- this node is one of the selected nodes -->
<xsl:when test="count(.|$selected-nodes) = $nselected-nodes">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<!-- copy attributes that are selected nodes -->
<xsl:copy-of select="@*[count(.|$selected-nodes) =
$nselected-nodes]"/>
<!-- apply templates to nodes that are to be copied -->
<xsl:apply-templates select="node()[count(.|$copied-nodes) =
$ncopied-nodes]"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
And there you have it. That stylesheet will take the input you
specified and give the output you specified.
Now all you have to do is create a stylesheet that creates it. In
fact most of it is static, so you could bundle it out to a separate
stylesheet and include it rather than create it dynamically. The only
thing that isn't static is the creation of the $selected-nodes
variable:
<xsl:variable name="selected-nodes"
select="//product/@sku | //product/cost"/>
Assuming that you're using oxsl as the namespace prefix for your XSLT
namespace alias, then you need to create an oxsl:variable with a name
attribute equal to selected-nodes:
<oxsl:variable name="selected-nodes">
...
</oxsl:variable>
The select attribute is created dynamically by iterating over the
various expressions that you have (I'll assume their held in an $exprs
variable):
<oxsl:variable name="selected-nodes">
<xsl:attribute name="select">
<xsl:for-each select="$exprs">
<xsl:value-of select="." />
<xsl:if test="position() != last()"> | </xsl:if>
</xsl:for-each>
</xsl:attribute>
</oxsl:variable>
You should be able to create the rest of the stylesheet very
straight-forwardly. |
12. | Pruning nodes not in xpath list |
| Jeni Tennison
> I would like to be able to generate a stylesheet that will produce
> output documents that exclude all nodes that are not matched by any
> of the xpath expressions. The first thing is to work out a stylesheet that does what you want
with the expressions hard-coded into it... > From an algorithm point of view, one solution is to create a
> node-set collection of all nodes that should be copied to the output
> document.
OK, so first work out which nodes have been selected by the
expressions: <xsl:variable name="selected-nodes"
select="//product/@sku | //product/cost"/>
Then to work out which nodes should therefore be copied - that's all
those nodes that are selected, plus their ancestors:
<xsl:variable name="copied-nodes"
select="$selected-nodes | $selected-nodes/ancestor::*"/>
Now, starting from the top (the document element is always the first
in the list of copied nodes), we want to work through the document. If
the element is in the list of selected nodes, then we just want to
copy it completely. Otherwise, we want to copy the element, copy any
attributes that are in the list of selected nodes, and apply templates
to any of its children that are in the list of nodes to be copied.
Now, working out whether a node is in a set of nodes involves a bit of
set manipulation - if you count how many nodes there are in the set
that's the union of the node and the node set, and it's the same as
the number of nodes in the node set, then the node has to be in the
node set. So to work out whether the context node is in the set of
$selected-nodes, I can use: count(.|$selected-nodes) = count($selected-nodes) Since $selected-nodes and $copied-nodes are known up front, I'll
create variables that indicate how many nodes are in each of them: <xsl:variable name="nselected-nodes" select="count($selected-nodes)" />
<xsl:variable name="ncopied-nodes" select="count($copied-nodes)"/>
So the template looks like:
<xsl:template match="*">
<xsl:choose>
<!-- this node is one of the selected nodes -->
<xsl:when test="count(.|$selected-nodes) = $nselected-nodes">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<!-- copy attributes that are selected nodes -->
<xsl:copy-of select="@*[count(.|$selected-nodes) =
$nselected-nodes]"/>
<!-- apply templates to nodes that are to be copied -->
<xsl:apply-templates select="node()[count(.|$copied-nodes) =
$ncopied-nodes]"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
And there you have it. That stylesheet will take the input you
specified and give the output you specified.
Now all you have to do is create a stylesheet that creates it. In
fact most of it is static, so you could bundle it out to a separate
stylesheet and include it rather than create it dynamically. The only
thing that isn't static is the creation of the $selected-nodes
variable:
<xsl:variable name="selected-nodes"
select="//product/@sku | //product/cost"/>
Assuming that you're using oxsl as the namespace prefix for your XSLT
namespace alias, then you need to create an oxsl:variable with a name
attribute equal to selected-nodes:
<oxsl:variable name="selected-nodes">
...
</oxsl:variable>
The select attribute is created dynamically by iterating over the
various expressions that you have (I'll assume their held in an $exprs
variable):
<oxsl:variable name="selected-nodes">
<xsl:attribute name="select">
<xsl:for-each select="$exprs">
<xsl:value-of select="." />
<xsl:if test="position() != last()"> | </xsl:if>
</xsl:for-each>
</xsl:attribute>
</oxsl:variable>
You should be able to create the rest of the stylesheet very
straight-forwardly. |
13. | Selecting only one node value out of the many identical values |
| Jeni Tennison
> this XML is genereted based on query from a user and comes from a
> database. I want to display to the user only the available "brands"
> of shirts Ie. output shall be only "Arrow" and "Lee" in my case. and
> the user can then further query on the subitems like "size" and
> "color". SO I want a Select "brand" from "clothes/category/sno"
> where "there is no repetiion"
Getting the 'distinct' values involves getting only those values that
haven't already occurred in the document. The basic method of doing
this is to find all the nodes where there isn't a preceding node that
has the same value in the document.
In your case you want all the sno elements:
clothes/category/sno
And then you want to filter in those where there aren't any preceding
(sibling) sno elements whose brand is the same as the brand of the
particular sno element:
clothes/category/sno[not(preceding-sibling::sno/brand = brand)]
If you have *lots* of sno elements, then another possibility is to
create a key that indexes the sno elements by brand:
<xsl:key name="sno-by-brand" match="sno" use="brand" />
You can then find all the sno elements with a particular brand (say
'Arrow') with the key() function:
key('sno-by-brand', 'Arrow')
and you can find all the sno elements that are first in the list of
sno elements of a particular brand, as returned by the key, with:
clothes/category/sno[generate-id() =
generate-id(key('sno-by-brand', brand)[1])]
or:
clothes/category/sno[count(.|key('sno-by-brand', brand)[1]) = 1]
|
14. | Selecting all but two elements by name |
| Jeni Tennison It depends how much you care about namespaces. *[not(name()='a' or name()='b')] Gives you all the elements aside from a and b elements that are in the
default namespace in their document. I'd tend to steer clear of this
because the default namespace could be anything at all. [not(self::a or self::b)] Gives you all the elements aside from a and b elements that are in no
namespace. Use this if the a and b elements that you want to ignore
don't have a namespace or if you're not using namespaces at all. *[not(local-name()='a' or local-name()='b')] Gives you all the elements aside from a and b elements in any
namespace. Use this if you want to ignore all a and b elements no
matter what namespace they're in. |
15. | Get the second para after the heading |
| Jeni Tennison
> I'm trying to find a way of saying 'output the third paragraph after
> the heading containing the text "foo"' -- to no avail.
It's probably easiest to do this by only selecting that paragraph
rather than (as you are doing currently, it seems) trying to match
only that paragraph.
You can get the h1 whose value is 'Best Section' with: and then get the second following sibling p element from that with: h1[. = 'Best Section']/following-sibling::p[2] If you only apply templates to that p element, then that's the only
output that you'll get. |
16. | Select all children except ... |
| Joerg Pietschmann
> I don't really know if "not(self::c)" is more efficient than "name()!='c'"
> but I prefer it for some reason, maybe because there's no function call?
I don't think there is a performance difference for most XSLT processors. However, using self:: is more robust when it comes to elements in a
namespace. If you write only elements with the literal name foo:bar fulfill this condition but not
baz:bar, even if the baz prefix is bound to the same namespace.
Like in <sample xmlns:foo="uri:sample:stuff" xmlns:baz="uri:sample:stuff">
<foo:bar/>
<baz:bar/>
</sample>
the inner elements have different a name(), but they are both matched
by self::foo:bar |
17. | Select an element based on childrens name |
| Wendell Piez
>> if i want to select all elements that have at least one, say,
>>"book" child element, it seems i can do it this way:
>> //*[name(child::*) = "book"] long way
>> //*[name(*) = "book"] shorter way
>>1) is this the easiest way to do it?
>
>//*[book]
>
>>2) why doesn't the following work as well?
>> //*[name(node()) = "book"]
>
>i'm not sure, but i think this will compare the name of the first child only.
Yup. The name() function takes a node set as its argument, and returns the
name of the first node in the node set. All three of the name tests will fall into this category. /*[book] is the way to do it, since the XPath expression "book" (short for
child::book) returns true if there are any book child elements (not just if
the first element child is a book)
//*[book] is short for
/descendant-or-self::node()/child::*[child::book]
(Traversing from the root, get all nodes at any depth, then get any element
child that has a book element child.)
name(node())='book' might be seeming to fail where name(*)='book' seems to
work due to whitespace in the input. If the first element child is a <book>
but it is preceded by a text node (even one that just contains a line
feed), the test name(node())='book' on its parent will test false whereas
name(*)='book' tests true.
I hope this clarifies! |
18. | Selecting elements in a given namespace |
| Jeni Tennison
> if i want to select all nodes in a given namespace ("auth"), it
> appears i can use:
>
> //namespace::auth
That will select all the *namespace*nodes* named "auth". Namespace
nodes are nodes that represent a prefix-namespace binding. Such a
namespace node will exist on every element within the scope of the
xmlns:auth="..." namespace declaration.
If you want to select all the elements in the namespace associated
with the prefix 'auth', use: //auth:*
All attributes in that namespace with:
//@auth:*
Note that the 'auth' namespace must be declared in the stylesheet
(or in whatever context you're selecting the nodes). A stylesheet will
not automatically pick up on the fact that the namespace is declared
in the XML document.
> so what is the XPath expression to match, say, the <last-name>
> elements within this namespace?
XPath expressions don't match elements, they select them. If you want
to select the last-name element in the 'auth' namespace, use: //auth:last-name
or, better: /auth:author/auth:last-name
To *match* the auth:last-name element with an XSLT pattern, you can
use:
auth:last-name
Note that in your example, the <last-name> element is not in the
namespace associated with the 'auth' prefix since it does not have a
prefix and there is no default namespace declaration. In your example,
only the <auth:author> element is in the 'auth' namespace. |
19. | Selective processing of first n elements |
| Passin, Tom
> I can't seem to get something
> which will only
> print/process the first 'x' (in my case x is 2) elements and
> then bail out
> of the for-each or just simply ignore the remaining ones found.
>
This is a good chance for you to start getting into XSLT-think mode.
Instead of limiting a loop, think of selecting just the elements you
want. The simplest example is to put this into a template -
<xsl:apply-templates select='element-to-work-with[3 > position()]'/>
Here you select just the first two nodes, and so whatever template
processes them only ever sees those two nodes to work on.
The most common and fundamental thing one usually does in xslt is to
select a set of nodes to work with. Therefore, think carefully about
how to select exactly the nodes you want.
[Note that the sense of the test is reversed to avoid having to write
<, which will work fine but is harder to read] |
20. | Pick first few elements as file sample |
| Dimitre Novatchev
> Need a simple transformation to reduce the size of a file... so like I
> just need to see the first 10 elements of an xml source which is 10
> megs! Those first 10 elements would be the first 10 child elements to
> the source including their child elements. Here's what ISN'T working:
>
>
> <xsl:template match="node | @*">
> <xsl:apply-templates select="node[position() <= 10] | @*" />
> </xsl:template>
Here's what is working:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/*[position() > 10]"/>
<xsl:template match="*[ancestor::*[3]]"/>
</xsl:stylesheet>
|
21. | Select one from a number of items |
| Michael Kay
> I have a gallery.xml file containing a number of images:
>
> <gallery>
> <image>
> <filename>1.jpg</filename>
> </image>
> <image>
> <filename>2.jpg</filename>
> </image>
> <!-- etc -->
> <image default="true">
> <!-- optional attribute applies to this element -->
> <filename>10.jpg</filename>
> </image>
> </gallery>
>
> and my xslt has to do the following thing -- look for an
> image marked with a "default" attribute, and if it's not
> found, use the first image instead. So I'm looking for the
> position number of the marked element, and if I can't find
> it, using 1:
Try <xsl:copy-of select="(image[1] | image[@default='true'])[last()]"/> |
22. | Namespace nodes. |
| Michael Kay
> Question regarding "<xsl:apply-templates
> select="*"/>".
> Is this going to be applied for each node and attribute > also?
> So for eg:
> if I have <ABC xmnls:ns2="http://"> would "<template
> match=*>" be called for ABC and then xmnls:ns2 also.
1. select="*" only selects child elements, it does does not select
attributes, namespaces, text nodes, comments, or processing instructions.
2. xmlns:ns2 in the XPath model is not an attribute. It turns into a
namespace node. You cannot apply-templates to namespace nodes (well, you
can, but no template rule will ever match them).
To get rid of namespace nodes that are being copied from the source
document, in XSLT 2.0 you can use <xsl:copy copy-namespaces="no">. In 1.0
you have to use <xsl:element name="{name()}" namespace="{namespace-uri()}">. |