Операции с наборами

Язык XPath поддерживает операцию | с наборами.

Union (|), оператор

Оператор |, или union, возвращает объединение двух своих операндов, которые должны быть наборами узлов. Например, //author | //publisher возвращает набор узлов, в котором объединены все узлы //author и все узлы //publisher. Для объединения нескольких наборов узлов можно связать несколько операторов union по цепочке друг с другом. Например, //author | //publisher | //editor | //book-seller возвращает набор узлов, содержащий все узлы //author, //publisher, //editor и //book-seller elements. Оператор union сохраняет порядок расположения документов и не возвращает повторяющиеся документы.

Примеры

Выражение Ссылается на

first-name | last-name

Набор узлов, содержащий элементы <first-name> и <last-name> в текущем контексте.

(bookstore/book | bookstore/magazine)

Набор узлов, содержащий элементы <book> или <magazine> внутри элемента <bookstore>.

book | book/author

Набор узлов, содержащий все элементы <book> и все элементы <author> внутри элементов <book>.

(book | magazine)/price

Набор узлов, содержащий все элементы <price> элементов <book> или <magazine>.

Пример

В следующем примере иллюстрируется действие оператора union.

XML-файл (test.xml)

<?xml version="1.0"?>
<test>
    <x a="1">
      <x a="2" b="B">
        <x>
          <y>y31</y>
          <y>y32</y>
        </x>
      </x>
    </x>
</test>

XSLT-файл (test.xsl)

Приведенная ниже таблица стилей XSLT выбирает все элементы <x>, атрибут a которых равен 2, а также элементы <x> без атрибутов.

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>

   <!-- Suppress text nodes not covered in subsequent template rule. -->
   <xsl:template match="text()"/>

  <!-- Handles a generic element node. -->
   <xsl:template match="*">
      <xsl:element name="{name()}">
         <xsl:apply-templates select="*|@*" />
         <xsl:if test="text()">
            <xsl:value-of select="."/>
         </xsl:if>
      </xsl:element>
   </xsl:template>

   <!-- Handles a generic attribute node. -->
   <xsl:template match="@*">
      <xsl:attribute name="{name()}">
         <xsl:value-of select="."/>
      </xsl:attribute>
   </xsl:template>

   <xsl:template match="/test">
      <xsl:apply-templates select="//x[@a=2] | //x[not(@*)]"/>
   </xsl:template>

</xsl:stylesheet>

Результат выполнения данного преобразования:

<x a="2" b="B">
   <x>
      <y>31</y>
      <y>y32</y>
   </x>
</x>
<x>
   <y>y31</y>
   <y>y32</y>
</x>

Очередность

В следующей таблице показан порядок приоритета (от наибольшего к наименьшему) между логическими операторами и операторами сравнения.

Очередность Операторы Описание

1

( )

Группирование

2

[ ]

Фильтры

3

/

//

Операции с путями

4

&lt;

&lt;=

&gt;

&gt;=

Сравнения

5

=

!=

Сравнения

6

|

Объединение

7

not()

Логическое НЕ

8

and

Логическое И

9

or

Логическое ИЛИ

Пример

В следующем примере иллюстрируется действие приведенного выше приоритета операторов.

XML-файл (test.xml)

<?xml version="1.0"?>
<test>

    <x a="1">
      <x a="2" b="B">
        <x>
          <y>y31</y>
          <y>y32</y>
        </x>
      </x>
    </x>

    <x a="1">
      <x a="2">
        <y>y21</y>
        <y>y22</y>
      </x>
    </x>

    <x a="1">
      <y>y11</y>
      <y>y12</y>
    </x>

    <x>
      <y>y03</y>
      <y>y04</y>
    </x>

</test>

Базовый XSLT-файл (test.xsl)

Этот базовый XSLT-файл будет использоваться в следующих примерах в качестве отправной точки.

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>

   <!-- Suppress text nodes not covered in subsequent template rule. -->
   <xsl:template match="text()"/>

  <!-- Handles a generic element node. -->
   <xsl:template match="*">
      <xsl:element name="{name()}">
         <xsl:apply-templates select="*|@*" />
         <xsl:if test="text()">
            <xsl:value-of select="."/>
         </xsl:if>
      </xsl:element>
   </xsl:template>

   <!-- Handles a generic attribute node. -->
   <xsl:template match="@*">
      <xsl:attribute name="{name()}">
         <xsl:value-of select="."/>
      </xsl:attribute>
   </xsl:template>

</xsl:stylesheet>

Вариант 0. Пробный запуск

В таблицу стилей XSLT можно добавить следующее правило шаблона.

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

В результате будет сформирован XML-документ, идентичный исходному, но без инструкции по обработке <?xml version="1.0"?>.

В следующих вариантах показаны различные способы написания этого правила шаблона. Смысл в том, чтобы показать порядок, в котором операторы XPath связываются с элементом.

Вариант 1. () связывается плотнее, чем []

Следующее правило шаблона выбирает первый элемент <y> в порядке документа из всех элементов <y> в исходном документе.

<xsl:template match="/test">
      <xsl:apply-templates select="(//y)[1]"/>
   </xsl:template>

Далее приведен результат.

<y>y31</y>

Вариант 2. [] связывает плотнее, чем / или //

Следующее правило шаблона выбирает все элементы <y>, которые являются первыми среди своих одноуровневых элементов.

<xsl:template match="/test">
   <xsl:apply-templates select="//y[1]"/>
</xsl:template>

Далее приведен результат.

<y>y31</y>

<y>y21</y>

<y>y11</y>

<y>y03</y>

Вариант 3. and, not

Следующее правило шаблона выбирает все элементы <x>, у которых нет дочерних элементов <x>, есть родительский элемент <x> и нет ни одного атрибута.

<xsl:template match="/test">
   <xsl:apply-templates select=
    "//x[./ancestor::*[name()='x'] and *[name()!='x'] and not(@*)]"/>
</xsl:template>

В результате получается один элемент <x>, приведенный ниже вместе с дочерними элементами:

<x>
   <y>y31</y>
   <y>y32</y>
</x>

Вариант 4. or, and, not

Следующее правило шаблона выбирает каждый элемент <x>, который является дочерним элементом элемента <x>, или не является родительским элементом элемента <x> и не имеет атрибутов.

<xsl:template match="/test">
   <xsl:apply-templates select=
    "//x[./ancestor::*[name()='x'] or *[name()!='x'] and not(@*)]"/>
</xsl:template>

В результате создается набор узлов, содержащих следующие элементы <x>, перечисленные далее вместе с их дочерними элементами.

<x a="2" b="B">
  <x>
     <y>y31</y>
     <y>y32</y>
  </x>
</x>
<x>
  <y>y31</y>
  <y>y32</y>
</x>
<x a="2">
  <y>y21</y>
  <y>y22</y>
</x>
<x>
  <y>y03</y>
  <y>y04</y>
</x>

Вариант 5. and, or, not

Следующее правило шаблона выбирает каждый элемент <x>, который является дочерним элементом элемента <x>, но не является родительским элементом элемента <x> или который не имеет атрибутов.

<xsl:template match="/test">
   <xsl:apply-templates select=
    "//x[./ancestor::*[name()='x'] and *[name()!='x'] or not(@*)]"/>
</xsl:template>

В результате создается набор узлов, содержащих следующие элементы <x>, перечисленные далее вместе с их дочерними элементами.

<x>
   <y>y31</y>
   <y>y32</y>
</x>
<x a="2">
  <y>y21</y>
  <y>y22</y>
</x>
<x>
  <y>y03</y>
  <y>y04</y>
</x>