This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Specifying element associated with attribute
- To: Paul Caton <paul at mama dot stg dot brown dot edu>
- Subject: Re: [xsl] Specifying element associated with attribute
- From: Jeni Tennison <mail at jenitennison dot com>
- Date: Wed, 3 Jan 2001 09:55:10 +0000
- CC: xsl-list at lists dot mulberrytech dot com
- Organization: Jeni Tennison Consulting Ltd
- References: <Pine.GSO.4.10.10101021612330.14075-100000@mama.stg.brown.edu>
- Reply-To: xsl-list at lists dot mulberrytech dot com
Hi Paul,
> When you have a template that matches element nodes, it's easy to
> specify choices based on particular attributes: but how do you do it
> the other way around? That is, you have a template for an attribute
> and you want to specify a choice based on the name of the element in
> which the attribute occurs (ie. test="IF THE NAME OF YOUR ASSOCIATED
> ELEMENT IS 'FOO'"). I've tried numerous permutations involving
> name() and node(), but nothing has worked so far. Please, what's the
> magic expression?
The short answer is, use:
parent::FOO
The long answer follows:
To go from an attribute to its element involves using the parent::
axis. So, if the context node is an attribute (as it is in a template
that matches attribute nodes) then you can identify the element that
attribute is on with the expression:
parent::*
(the element that is the parent of this node) or:
parent::node()
(the *node* [which actually must be an element in this context] that
is the parent of this node) or the abbreviation of the above:
..
To get the name of the parent, you can use the name() function, taking
one of the above expressions as an argument:
name(..)
So, to test whether the name of the parent element is 'FOO' then you
could use:
name(..) = 'FOO'
This answer will work perfectly well in most cases, but a better
solution becomes apparent if you turn around the phrasing of what
you're after. You want to know if this attribute has a 'FOO' element
as a parent: is there are parent of this attribute that is a 'FOO'
element? The expression to get to such a parent is:
parent::FOO
(the 'FOO' element that is the parent of this node). If the parent
element is a 'FOO' element, then that node will be returned. If the
parent element is *not* a 'FOO' element, then no node will be returned
as there is no parent FOO element. Within a test expression, if a
node is returned the test returns true, if no node is returned the
test returns false. So (in most situations) the following are
equivalent:
parent::FOO is equivalent to name(..) = 'FOO'
The situation where they are not equivalent is where namespaces are
involved. The name() of a node gives the exact name for the node
within the XML source. Look at the following XML:
<foo:FOO xmlns:foo="http://www.foo.com" />
In this, the 'FOO' element is in the 'http://www.foo.com' namespace.
The name() of that element is:
foo:FOO
So, if you are using name() to test the identity of the element, then
you need to use:
name(..) = 'foo:FOO'
However, it might be that in another document (or even the same
document!) you have an element like:
<bar:FOO xmlns:bar="http://www.foo.com" />
The 'FOO' element here is in the same namespace (http://www.foo.com)
but has a different prefix. Its name is:
bar:FOO
and it would have to be tested with:
name(..) = 'bar:FOO'
despite the fact that actually the two FOO elements in the two
documents are meant to be precisely the same.
Fortunately, when you use 'parent::FOO' instead, it takes into account
the fact that the prefix of a namespace isn't important - it's the
*URI* that you have to look at. If within your XSLT you have declared
the 'foo' prefix to be associated with the 'http://www.foo.com' URI
using:
xmlns:baz="http://www.foo.com"
then the XPath:
parent::baz:FOO
will match both the 'foo:FOO' and the 'bar:FOO' elements - it looks
for the equivalence in the namespace *URI* rather than the namespace
*prefix*.
For this reason, it is worth getting into the habit of testing for
nodes called a particular name by testing for whether the node called
that name exists rather than testing whether the node is called that
name.
I hope that helps,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list