I want to check if there is an inline stylesheet within the document, but I am not sure how to pick descendant attributes of an element as "style" attribute could be attached to any element within the body element. This is the current xpath I write:
descendant::@*[self::@style]
But the parser throw开发者_如何学Gos error saying: "Unexpected token "@" after axis name". Can anyone tell me how do I fix it or there is another way of doing this? Thanks!
So, you are looking for any element anywhere within the document that has an @style
attribute I think.
If you want the element that contains the attribute you want to the following:
descendant::*[@style]
That will return all descendant elements of the current node that have an @style
attribute. If you wanted the attribute itself you would be better off using something like:
descendant::*[@style]/@style
That will find you all the style attributes themselves.
Use this XPath: //@style
, it will select all attributes style
@Kirill gave the correct answer regarding how to fix
descendant::@*[self::@style]
by using
//@style
But for those who want to know why the initial XPath doesn't work, and whether there's a variant using self::
that would work...
Remember that @
is an abbreviation for the attribute::
axis. So self::@foo
is shorthand for self::attribute::foo
. But syntactically, there can only be one axis in a location step. That's why the parser rejects self::@style
: it has two axes.
There's something else interesting going on here. You might think you could fix the expression as follows:
//@*[self::style]
(Ignore for the moment the fact that this is needlessly more complex that //@style
. You start trying expressions like this when you want all attributes except style
, e.g. //@*[not(self::style)]
.)
This expression parses and runs without errors. The first part, //@*
, matches all attribute nodes in the document. And you might think (as I did) that the predicate [self::style]
will evaluate to a truthy value whenever its context node is a style
attribute.
But we would be wrong. If we try it, we'll get an empty nodeset. Why? If the context node is an attribute node, and the self::
axis contains only the context node, and the attribute's name matches the name that comes after self::
, shouldn't the expression in the predicate yield that attribute node as its result?
On p. 1228 of XSLT 2.0 and XPath 2.0 (4th ed.), the glossary definition of Self Axis explains:
The principal node kind of the self axis is elements, which means that when the context node is an attribute, an axis step of the form
self::*
orself::xyz
will not select that attribute [bold emphasis mine].
However, in XPath 2.0, you can use self::attribute(style)
. I.e. you can use a KindTest instead of a NameTest.
Michael Kay goes into quite a bit of detail on the rules for what kinds of nodes can be matched by a NameTest on p. 695.
精彩评论