13

I'm trying to use parentheses to override default operator precedence in an xpath expression within an xslt with no luck. For example:

<?xml version="1.0" encoding="UTF-8" ?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common"
                extension-element-prefixes="exsl"
                version="1.0">

   <xsl:output encoding="utf-8" standalone="yes"/>

   <xsl:template match="/">
      <xsl:apply-templates select="*"/>
   </xsl:template>

   <xsl:template match="@* | node()">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
   </xsl:template>

   <!--these should work but don't-->
   <xsl:template match="//(X|Y|Z)/AABBCC"/>
   <xsl:template match="(book/author)[last()]"/>

</xsl:stylesheet>

Visual Studio 2010 won't compile this returning:

Unexpected token '(' in the expression. // -->(<-- X|Y|Z)/AABBCC

Unexpected token '(' in the expression. -->(<-- book/author)[last()]

Yet the second example is from MSDN:

http://msdn.microsoft.com/en-us/library/ms256086.aspx

and numerous references say you can use parentheses in this way:

http://saxon.sourceforge.net/saxon6.5.3/expressions.html

http://www.stylusstudio.com/xsllist/200207/post90450.html

http://www.mulberrytech.com/quickref/XSLT_1quickref-v2.pdf

Is this an xpath 1.0 vs 2.0 thing...or is there something else i'm missing? If it's an xpath 2.0 thing, is there a nice xpath 1.0 way to do the same thing?

0

2 Answers 2

13

See @Martin's answer for the key point: that valid patterns are only a subset of valid XPath expressions. In other words, there are many XPath expressions that cannot be used as patterns. (This is something about XSLT that it took me a long time to realize.)

As for valid alternatives:

//(X|Y|Z)/AABBCC

is a valid expression in XPath 2.0, but not in 1.0, because the parentheses cannot begin immediately after the // axis. But in 1.0,

(//X|//Y|//Z)/AABBCC

is a valid alternative expression (but still not a valid pattern). A valid but somewhat awkward pattern would be

*[contains('X Y Z', local-name())]/AABBCC

or

*[self::X | self::Y | self::Z]/AABBCC

As for

(book/author)[last()]

a valid pattern would be

(book/author)[not(following::author[parent::book])]

(But of course

(book/author)[not(following::book/author)]

would not be equivalent, because it would match all <author> children of the last <book> that had any.)

Sign up to request clarification or add additional context in comments.

Comments

10

You have to understand that a match attribute of an xsl:template does not allow any XPath expression but rather only so called patterns: https://www.w3.org/TR/1999/REC-xslt-19991116#patterns, a subset of XPath expressions.

So while (book/author)[last()] is a syntactically correct XPath 1.0 expression I don't think it is a syntactically correct XSLT 1.0 pattern, the parentheses are not allowed.

I don't think //(X|Y|Z)/AABBCC is an allowed XPath 1.0 expression (nor a pattern of course) but match="X/AABBCC | Y/AABBCC | Z/AABBCC" should do.

1 Comment

Thanks to Martin and Lars...I understand now

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.