Используя круглые скобки в xpath/xslt

Я пытаюсь использовать круглые скобки, чтобы переопределить приоритет оператора по умолчанию в выражении xpath в xslt без везения. Например:

<?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 не будет компилировать это возвращение:

Неожиданный токен '(' в выражении. // → (< -X | Y | Z)/AABBCC

Неожиданный токен '(' в выражении. → (< - book/author) [last()]

Однако второй пример - из MSDN:

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

и многочисленные ссылки говорят, что вы можете использовать круглые скобки следующим образом:

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

Является ли это версией xpath 1.0 vs 2.0... или есть что-то еще, что мне не хватает? Если это вещь xpath 2.0, есть ли хороший способ xpath 1.0 сделать то же самое?

Ответ 1

Вы должны понимать, что атрибут match для xsl:template не допускает выражения XPath, а скорее только так называемые шаблоны: http://www.w3.org/TR/xslt#patterns, подмножество выражений XPath.

Итак, хотя (book/author)[last()] является синтаксически корректным выражением XPath 1.0, я не думаю, что это синтаксически правильный шаблон XSLT 1.0, скобки не разрешены.

Я не думаю, что //(X|Y|Z)/AABBCC является допустимым выражением XPath 1.0 (а не шаблоном, конечно), но match="X/AABBCC | Y/AABBCC | Z/AABBCC" должен делать.

Ответ 2

См. ответ @Martin для ключевого момента: допустимые шаблоны являются только подмножеством действительных выражений XPath. (Это что-то о XSLT, что мне понадобилось много времени.)

Что касается действительных альтернатив:

//(X|Y|Z)/AABBCC

является допустимым выражением в XPath 2.0, но не в 1.0, поскольку скобки не могут начинаться сразу после оси //. Но в 1.0,

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

является допустимым альтернативным выражением (но все еще недействительным шаблоном). Правильный, но несколько неудобный шаблон будет

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

или

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

Что касается

(book/author)[last()]

действительный шаблон будет

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

(Но, конечно,

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

не будет эквивалентным, потому что он будет соответствовать всем <author> дочерним элементам последнего <book>, в которых есть какие-либо.)