Re: [xsl] Specifying element associated with attribute

Subject: Re: [xsl] Specifying element associated with attribute
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Wed, 3 Jan 2001 09:55:10 +0000
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:


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:


(the element that is the parent of this node) or:


(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:

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:


(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

  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=""; />

In this, the 'FOO' element is in the '' namespace.
The name() of that element is:


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=""; />

The 'FOO' element here is in the same namespace (
but has a different prefix.  Its name is:


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 '' URI


then the XPath:


will match both the 'foo:FOO' and the 'bar:FOO' elements - it looks
for the equivalence in the namespace *URI* rather than the namespace

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

I hope that helps,


Jeni Tennison

 XSL-List info and archive:

Current Thread