user533832
user533832

Reputation:

How do I match an element that has a certain sibling element in xslt/xpath

I'm trying to match all a/c elements that have a b sibling. I've tried:

<xsl:template match="a/b/../c">

but I get "Cannot convert the expression {..} to a pattern" from Saxon.

My XSLT/XPath skills are basic at best...

Upvotes: 4

Views: 518

Answers (2)

LarsH
LarsH

Reputation: 28014

<xsl:template match="a[b]/c">

Explanation: match any c element that is a child of an a element that has a b child.

You should also be able to use .. in a predicate:

<xsl:template match="a/c[../b]">

which is similar to what you were trying.

The reason you can't use .. directly in a match pattern (i.e. outside of a predicate) is that patterns are not XPath expressions, even though they look and behave very similarly. In particular, only "downward" axes (child::, descendant::, and attribute::) are allowed directly in patterns. (The only explicit axes allowed by the spec are child:: and attribute::. descendant:: is implicitly allowed via the // between pattern steps. Saxon seems to bend the rules a bit here, allowing an explicit descendant:: axis, and even descendant-or-self::!)

The reason given for the restriction on axes is that (a) other axes are rarely needed in patterns, and (b) this allows XSLT processors to be much more efficient in testing for matches.

But predicates in patterns are defined with the same syntax rules as in XPath expressions (with some restrictions in XSLT 1.0, like not allowing variable references or current()). So you can use other axes, like parent::, or the abbreviation ...

Upvotes: 5

Lev Levitsky
Lev Levitsky

Reputation: 65871

This XPath expression seems to do the job (may be not optimal):

//a|//c[following-sibling::b or preceding-sibling::b]

Edit:

In case LarsH is right, it should be //a/c instead of //a|//c.

Upvotes: 1

Related Questions