XSLT

Холзнер Стивен

Глава 4

Создание образцов выбора

 

 

До сих пор материал книги был достаточно очевиден, за исключением одного: несколько загадочных образцов выбора (match pattern). Мы работали с различными образцами выбора, такими как «/PLANETS» в элементах , не предлагая систематического объяснения того, как в действительности работают эти образцы, — как в этом случае:

 

  

    </p> <p class="paragraph">     The Planets Table </p> <p class="paragraph">    

  

  

   .

   .

   .

 

 

В этой главе мы рассмотрим все необходимое, что нужно знать для создания образцов выбора в XSLT. Образцы выбора применяются в элементах , и ; с элементом мы работали с самого начала книги, элемент мы увидим в главе 9 и элемент — в главе 5. В частности, для выбора по образцу у элементов и используется атрибут match, а у элемента — атрибуты count и from.

Образцы выбора можно также применять в атрибуте select таких элементов, как , , и . Здесь важно отметить один момент: атрибут select этих элементов обладает большими возможностями, чем атрибуты match, count и from элементов , и , потому что в select можно использовать полные выражения XPath, а не только образцы выбора.

Образцы выбора являются подмножеством выражений XPath, то есть все образцы выбора являются допустимыми выражениями XPath, но не все выражения XPath являются образцами выбора. Единственные выражения XPath, которые могут быть образцами, — это выражения, возвращающие набор узлов (даже набор, состоящий из одного узла) и использующие пути, которые задают только дочерние узлы или узлы атрибутов.

Образцы выбора определены в самой рекомендации XSLT, в то время как выражения XPath определены в рекомендации XPath (www.w3.org/TR/xpath); тем не менее, эти рекомендации совместимы, потому что все образцы выбора являются одновременно выражениями XPath.

СОЗДАНИЕ ПОЛНЫХ ВЫРАЖЕНИЙ XPATH

В главе 7 «Работа и изучение XPath» показано, как создавать полные выражения XPath. Полные выражения XPath можно применять в XSLT в следующих местах: в атрибуте select элементов <xsl:apply-templates>, <xsl:value-of>, <xsl:for-each>, <xsl:param>, <xsl:variable>, <xsl:with-param>, <xsl:copy-of> и <xsl:sort>; в значениях шаблонов атрибутов; в атрибуте test элементов <xsl:if> и <xsl:when>; в значении атрибута элемента <xsl:number> и в предикатах образцов выбора.

Чтобы еще больше все усложнить, следует сказать, что выражения XPath можно использовать в специальной, необязательной части (и только в этой части) образцов выбора: в предикатах. Как мы увидим в этой главе, предикаты — это выражения XPath, которые вычисляются либо в значения «истина/ложь», либо в числа, заключаемые в квадратные скобки, [ и ]. Например, образец PLANET[NAME="Venus"] выбирает дочерние узлы контекстного узла, у которых есть дочерние узлы с текстом «Venus». Выражения внутри [ и ] представляют собой настоящие выражения XPath с известными ограничениями, которые будут рассмотрены в этой главе.

Безусловно, для создания образцов выбора необходим опыт, поэтому в данной главе приводится много примеров.

MICROSOFT И НЕСТАНДАРТНЫЕ ОБРАЗЦЫ ВЫБОРА

Microsoft поддерживает образцы выбора в своем процессоре XML MSXML3, но есть еще кое-что, о чем вам следует знать: с образцами выбора Microsoft использует также весьма много нестандартного, не используемого W3C синтаксиса. В этой главе я собираюсь придерживаться официальной, W3C, версии, и если вам доведется читать документацию Microsoft об образцах выбора, имейте в виду, что многое из этой документации относится только к реализации Microsoft.

 

Выбор корневого узла

Как вы уже видели, выбрать корневой узел можно при помощи образца выбора «/», как, например:

 

 

 

 

Выбор элементов

Можно выбирать элементы, просто задавая их имена, как мы уже видели. Следующий шаблон выбирает элементы :

 

 

 

 

Выбор дочерних элементов

При доступе к дочернему узлу определенного узла для разделения имен элементов можно использовать операцию шага /. Пусть, например, требуется создать правило, которое должно применяться только к тем элементам , которые являются дочерними для элементов . Для этого можно задать выражение "PLANET/NAME". Вот правило, окружающее текст таких элементов в элемент HTML <Н3>:

 

 

 

Можно также использовать символ * в качестве символа-подстановки, что соответствует любому элементу. (* может выбирать только элементы, однако образец @* выбирает любой атрибут.) Например, следующее правило применяется ко всем элементам , которые являются внуками элементов :

 

 

 

 

Выбор потомков элемента

В предыдущем разделе при помощи выражения "PLANET/NAME" я выбирал все элементы , являющиеся прямыми потомками элементов , а при помощи выражения "PLANET/*/NAME" — все элементы , являющиеся внуками элементов . Есть, однако, более простой способ выполнить оба выбора — применить выражение "PLANET//NAME", выбирающее все элементы , находящиеся внутри элементов , независимо от глубины вложенности (соответствующие элементы называются потомками элемента ). Иными словами, "PLANET//NAME" выбирает "PLANET/NAME", "PLANET/*/NAME", "PLANET/*/*/NAME" и т.д.:

 

 

 

 

Выбор атрибутов

Как было показано в главе 3, «Создание и применение шаблонов», можно выбирать атрибуты, если предварять их имена префиксом @. Вы уже работали с атрибутом UNITS, который поддерживают большинство детей элементов :

 Earth

 1

 1

 2107

 1

 128.4

Чтобы извлечь единицы измерения и отобразить их вместе со значениями массы и т.п., можно выбрать атрибут UNITS при помощи @UNITS (листинг 4.1).

Листинг 4.1. Выбор атрибутов

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

  

   

    .

    .

    .

  

   

    .

    .

    .

   

  

 

 

  

  

   

   

 

 

 

 

 

 

 

 

  

  

  

 

 

  

  

  

 

Теперь результирующая HTML-таблица включает не только значения, но и их единицы измерения:

 

   </p> <p class="paragraph">    The Planets Table </p> <p class="paragraph">   

 

 

  

   The Planets Table

  

 

   

    .

    .

    .

  

   

    

    

  

  

   

    

    

  

   .

   .

   .

 

Mercury .0553 (Earth = 1) 1516 miles
Venus .815 (Earth = 1) 3716 miles

 

Для выбора всех атрибутов элемента можно также использовать подстановку. Например, "PLANET/@*" выбирает все атрибуты элементов .

 

Формальное определение образцов выбора

Определение образцов выбора приводится также в рекомендации XSLT W3C. Образцы выбора определяются в терминах выражений XPath следующим образом: «Синтаксис для образцов является подмножеством для выражений [XPath]. В частности, пути расположения, удовлетворяющие определенным ограничениям, могут использоваться как образцы. Выражение, в то же время являющееся образцом, всегда вычисляется в объект типа набора узлов. Узел удовлетворяет образцу, если узел является членом результата вычисления образца как выражения по отношению к возможному контексту; возможный контекст — это контекст, контекстный узел которого был выбран, или один из его предков».

Самое важное предложение в предыдущем абзаце — последнее. Суть в том, что узел X удовлетворяет образцу тогда и только тогда, когда существует узел X или предок X, такой, что при применении к этому узлу образца как выражения XPath, результирующий набор узлов будет включать X.

Что в действительности это означает? Это значит, что когда нужно проверить, удовлетворяет ли узел образцу, сначала следует применить образец как выражение XPath к самому узлу, затем применить его последовательно ко всем его предкам, вплоть до корневого узла. Если какой-либо полученный при этом набор узлов будет содержать сам узел, узел удовлетворяет образцу. Такой порядок действий имеет смысл потому, что образцы выбора пишутся для применения к текущему узлу или его дочерним узлам.

СЛЕДСТВИЯ ФОРМАЛЬНОГО ОПРЕДЕЛЕНИЯ ОБРАЗЦОВ ВЫБОРА

Приведенное определение образцов в терминах выражений XPath довольно очевидно, но существуют следствия, которые сразу не видны. Например, хотя функция node() определена как функция, выбирающая любой узел, при использовании ее в качестве образца, "node()", в действительности она представляется как "child::node()", как вы увидите позже в этой главе. Помимо прочего, это означает, что образец "node()" может выбирать только дочерние узлы — он никогда не выберет корневой узел. Отметьте также, что нет образцов, которые бы могли выбрать узлы объявлений пространств имен.

W3C дает формальное определение образцов выбора в нотации расширенных форм Бэкуса-Наура (РБНФ), при помощи которой написана и спецификация XML. Объяснение этой грамматики можно найти по адресу www.w3.org/TR/REC-xml (раздел 6). Здесь я привожу формальное определение образцов только для справки. (Разъяснению этого формального определения посвящена целая глава.) В следующем списке приведены используемые здесь лексемы нотации РБНФ:

• ::= означает «определяется как»;

• + означает «один или больше»;

• * означает «ноль или больше»;

• | означает «или»;

• - означает «не»;

• ? означает «необязательно».

Далее приведено настоящее, формальное определение образцов выбора W3C; когда элемент заключен в одиночные кавычки, как 'child' или '::', это значит, что элемент должен появиться в образце буквально (как "child::NAME"), — такие элементы называются литералами, Literal:

Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern

LocationPathPattern ::= '/' RelativePathPattern?

 | IdKeyPattern ('/' | '//') RelativePathPattern?

 | '//'? RelativePathPattern

IdKeyPattern ::= 'id' '(' Literal ')' | 'key' '(' Literal '.' Literal ')'

RelativePathPattern ::= StepPattern | RelativePathPattern '/' StepPattern

 | RelativePathPattern '//' StepPattern

StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*

ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier

 | ('child' | 'attribute') '::'

Определения NodeText (текстового узла) и Predicate (предиката) приводятся в спецификации XPath (Expr соответствует выражению XPath, a NCName и QName были определены в начале главы 2, «Создание и применение таблиц стилей»):

NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'

Predicate ::= '[' PredicateExpr ']'

PredicateExpr ::= Expr

AbbreviatedAxisSpecifier ::= '@'?

NameTest :: = '*' | NCName ':' '*' | QName

NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'

Как вы можете видеть, все это больше походит на какой-то код. Давайте начнем его расшифровывать. Во-первых, образец (pattern) состоит из одного (или более) образца пути расположения (location path pattern). Образец пути расположения, в свою очередь, состоит из одного или нескольких образцов шага (step pattern), разделенных / или //, или одним (несколькими) образцом шага в объединении с функциями id и key (выбирающими элементы с определенными идентификаторами или ключами).

Образцы шага являются строительными блоками шаблонов: в одном пути можно использовать несколько шагов, разделяя их символами / или //, как в образце "PLANET/*/ NAME", в котором три шага: "PLANET", "*" и "NAME". Если вы начнете сам образец с символа /, он будет называться абсолютным, так как вы указали образец от корневого узла (как в "/PLANETS/PLANET" или "//PLANET"); иначе образец называется относительным и применяется начиная с контекстного узла (как в "PLANET").

Затем образец шага состоит из оси, условия узла и предикатов (которых может и не быть). Например, в выражении child::PLANET[position()=5], child — это имя оси, PLANET — условие узла, a [position()=5] — это предикат. (Предикаты всегда заключены в квадратные скобки.) Образцы можно создавать при помощи одного или более образцов шага, как, например, образец /child::PLANET/child::NAME, который выбирает элементы , дочерние по отношению к родителю .

Таким образом, чтобы понять работу образцов, вам необходимо понять работу образцов шага, поскольку образцы состоят из одного или более образцов шага, в таких выражениях, как "step-pattern1/step-pattern2/step-pattern3…". А чтобы понять работу образца шага, необходимо понять работу деятельности трех составных частей — осей, условий узлов и предикатов, которыми мы и займемся в следующих разделах.

 

Образцы шага, часть 1: оси образца

 

Оси — первая часть образцов шага. Например, в образце шага child::NAME, ссылающемся на элемент , дочерний по отношению к контекстному узлу, child называется осью. У образцов две оси:

• ось attribute содержит атрибуты контекстного узла;

• ось child содержит детей контекстного узла. Если ось явно не задана, ось child будет осью по умолчанию.

При помощи осей можно задать шаг расположения (location path) или путь, как в следующем примере, в котором ось child используется для задания выбора дочерних узлов контекстного узла, элемента :

 

 

  

 

  

  

  

  

  

 

 

Рассмотрим ряд примеров применения осей:

• child::PLANET. Возвращает дочерние элементы контекстного узла;

• child::*. Возвращает все дочерние элементы контекстного узла (* выбирает только элементы);

• attribute::UNITS. Возвращает атрибут UNITS контекстного узла;

• child::*/child::PLANET. Возвращает всех внуков контекстного узла.

Хотя, судя по этим примерам, кажется, что можно применять только оси детей и атрибутов, на практике это не совсем так. Когда требуется указать детей, возможности оси child несколько ограничены, потому что необходимо указывать каждый уровень, который необходимо выбрать — например "child::PLANETS/child::PLANET/child::MASS" выбирает элемент , дочерний по отношению к элементу , который, в свою очередь, дочерний по отношению к . Если вам требуется выбрать все элементы , появляющиеся в любом месте элемента , детей, внуков, правнуков и т.д., кажется, что нет способа сделать это в одном образце. В XPath это можно сделать при помощи выражения наподобие "child::PLANETS/descendant::MASS", но в образцах нельзя использовать ось потомков (descendant). Помните, однако, что в этих же целях можно применить операцию //. Например, образец "child::PLANETS//child::MASS" выбирает все элементы в любом месте внутри элемента .

Следующий пример (листинг 4.2) демонстрирует работу этого образца, заменяя текст во всех элементах независимо от того, где они находятся внутри элемента , на текст "Very heavy!". Для того чтобы скопировать в результирующий XML-документ все остальные узлы planets.xml, я также установил правило, выбирающее любой узел при помощи условия узла (node test) node, с которым мы познакомимся позже. Заметьте, что, хотя образец, выбирающий любой узел, также выбирает все элементы , образец "child::PLANETS//child::MASS" гораздо более специален — поэтому, как объяснялось в главе 3, процессор XSLT задаст ему более высокий приоритет для элементов .

Листинг 4.2. Выбор элементов <MASS>

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

  

  

 

 

  

   Very heavy!

  

 

А вот результирующий XML-документ:

 

  Mercury

  

   Very heavy!

  

  58.65

  1516

  43.4

 

 

  Earth

  

   Very heavy!

  

  1

  2107

  1

  128.4

 

При задании осей в образцах можно воспользоваться рядом сокращений, применяемых практически повсеместно.

 

Сокращенный синтаксис

Для образцов существует два правила сокращения осей:

• child::childname может быть сокращено как childname;

• attribute::childname может быть сокращено как @childname.

В следующем списке перечислен ряд примеров образцов с сокращенным синтаксисом; в конце главы вы увидите много других.

• PLANET. Выбирает дочерние элементы контекстного узла;

• *. Выбирает все дочерние элементы контекстного узла;

• @UNITS. Выбирает атрибут UNITS узла;

• @*. Выбирает все атрибуты контекстного узла;

• */PLANET. Выбирает всех внуков контекстного узла;

• //PLANET. Выбирает всех потомков корня документа;

• PLANETS//PLANET. Выбирает все элементы , являющиеся потомками дочерних элементов контекстного узла;

• //PLANET/NAME. Выбирает все элементы , дочерние по отношению к ;

• PLANET[NAME]. Выбирает детей контекстного узла, у которых есть дочерние элементы .

В таком образце, как "child::PLANET", "child" является осью, a "PLANET" — условием узла, что представляет собой вторую часть образцов шага.

 

Образцы шага, часть 2: условия узла

 

Условия узла (node test) составляют вторую часть образцов шага. В качестве условий узла можно использовать названия узлов или символ подстановки * для выбора и узлов, и их типов. Например, выражение child::*/child::NAME выбирает все элементы , являющиеся правнуками контекстного узла.

Помимо названий узлов и символа подстановки, можно применять также следующие условия узлов:

• comment() выбирает узлы комментария;

• node() выбирает узел любого типа;

• processing-instruction() выбирает узел инструкции обработки. В скобках можно указать название выбираемой инструкции обработки;

• text() выбирает текстовый узел.

В следующих разделах мы изучим эти условия узлов и рассмотрим примеры их применения.

 

Выбор комментариев

Текст комментариев можно выбрать при помощи образца comment(). Разумеется, не следует хранить данные, которые попадут в выходной документ, в комментариях входного документа. Тем не менее, вам может потребоваться преобразовать комментарии из формы в какую-то другую форму, используемую другим языком разметки, — например, элемент .

В следующем примере я извлеку комментарии из planet.xml и включу их в полученные выходные данные.

 Venus

 "(Earth = 1)">.815

 116.75

 3716

 .943

 66.8

Чтобы извлечь комментарии и поместить их в элементы , я включил правило только для комментариев (листинг 4.3).

Листинг 4.3. Выбор комментариев

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

  

   

  

 

 

  

  

  

 

Вот результат для Венеры, в котором комментарий преобразован в элемент :

Venus

.815

116.75

3716

.943

66.8B перигелии

Обратите внимание: здесь текст для других элементов в элементе также включается в выходной документ, потому что так установлено в соответствии с правилом по умолчанию для каждого элемента. Поскольку для элементов я не предоставил какого-либо правила, их текст просто включается в выходной документ.

 

Выбор узлов при помощи node()

В образце условие узла node выбирает любой узел, за исключением корневого узла — помните, что в действительности это child::node(). Предположим, мы хотим создать таблицу стилей, копирующую произвольный документ XML, используя . (В главе 3 для этого применялся элемент .) Можно начать так, как показано в следующем примере. В этом случае в применяемом шаблоне для выбора любого элемента или любого атрибута используется операция OR, с которой мы познакомимся позже в этой главе (этот шаблон фактически выбирает себя — для того чтобы продолжать копирование на много уровней вглубь):

 xmlns:xsl=http://www.w3.org/1999/XSL/Transform">

 

 

  

  

  

 

 

Однако посмотрите на результат — обратите внимание на то, что в этой версии, выбирающей только элементы и атрибуты (@*|*), не копируются узлы-разделители и текстовые узлы:

Это, конечно, неполно. Если я, с другой стороны, буду выбирать по образцу "@*|node()" вместо "@*|*", новое правило шаблона выберет все узлы за исключением корневого узла (который создается в результирующем дереве автоматически), поэтому символы-разделители будут скопированы, так же как и текст (листинг 4.4).

Листинг 4.4. Копирующая таблица стилей

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

  

  

 

Новый результат:

 

  Mercury

  .0553

  58.65

  1516

  .983

  43.4

 

 

  Venus

  .815

  116.75

  3716

  .943

  66.8

 

Выбор текстовых узлов при помощи text()

Выбрать текст узла можно при помощи образца "text()". Как правило, нет особых причин применять условие узла text. В XSLT существует правило по умолчанию, в соответствии с которым текст текстового узла включается в выходной документ, если этот узел не выбирается какими-либо другими правилами. Если нужно сделать это правило по умолчанию явным, можно поступить, например, так:

 

Можно перекрыть это правило, не отправляя текст из текстовых узлов в выходной документ, — в том числе так:

Потребность в применении условия текстового узла возникает, например, когда нужно выбрать узлы с определенным текстом. Предикат "NAME[text()='Venus']" выбирает элементы , в которых содержится имя "Venus". (Будьте внимательны с вложением кавычек, чтобы процессор XSLT не ошибся, — например, такой предикат не работает: "NAME[text()="Venus"]".) Еще одна причина для использования условия текстового узла появляется, когда требуется применить к текстовым узлам некоторое условие при помощи строковых функций XPath (которые будут рассмотрены позже в этой главе). Например, текстовый узел "Earth" в Earth выбирается образцом "text()[starts-with(.,'Е')]".

КАК УБРАТЬ КОММЕНТАРИИ

Ранее мы видели, что образец "@*|node()" (в котором используется операция OR, обсуждаемая позже) выбирает из файла planets.xml все, включая комментарии. Если вы хотите убрать комментарии, воспользуйтесь образцом "@*|*|text()", который сохраняет только элементы, атрибуты и текстовые узлы.

 

Выбор инструкций обработки

Для выбора инструкций обработки используйте образец processing-instruction():

 

  Found a processing instruction.

 

Можно также указать, какую именно инструкцию обработки вы хотите выбрать, задав имя инструкции (исключая ), — как в следующем примере, в котором выбирается инструкция обработки :

 

  Found an xml-include processing instruction.

 

РАЗЛИЧИЕ МЕЖДУ КОРНЕВЫМИ УЗЛАМИ И КОРНЕВЫМИ ЭЛЕМЕНТАМИ

Одна из основных причин различия корневого узла в самом начале документа и корневого элемента заключается в том, что при этом у вас есть доступ к инструкциям обработки и другим узлам в прологе документа.

На этом мы заканчиваем обсуждение возможных условий узлов в образцах шага. Третья и последняя часть образцов шага — предикаты

 

Образцы шага, часть 3: предикаты

Предикаты, третья часть образцов шага, содержат выражения XPath. Предикат можно заключить в операцию [] и проверить, верно ли заданное условие.

Например, можно проверить:

• значение атрибута в заданной строке;

• значение элемента;

• содержит ли элемент определенного ребенка, атрибут или другой элемент;

• позицию узла в дереве узлов.

Подробнее выражения XPath обсуждаются в главе 7, но здесь будет представлено введение в тему, так как эти выражения можно применять в предикатах образцов.

Выражения XPath более сложны, чем образцы выбора. Если при их создании у вас возникнут затруднения, вам может помочь удобная программа-пример ApplyXPath.java из пакета Xalan, при помощи которой можно применить к документу выражение XPath и посмотреть на результаты. Например, если применить выражение XPath "PLANET/NAME" к planets.xml, будут отображены значения всех элементов , дочерних по отношению к элементам (открывающий и закрывающий теги добавляются программой ApplyXPath):

C:\>java ApplyXPath planets.xml PLANET/NAME

Mercury

Venus

Earth

Если предикат имеет числовое значение, последнее представляет условие позиции (position test). Например, NAME[1]См. выпущенные издательством книги «XML и Java 2, библиотека программиста» и «XML, справочник». — Примеч. ред.
выбирает первого ребенка контекстного узла. Условия позиции W3C, а также условия позиции в Xalan, Oracle, XT, Saxon и MSXML3 (XML процессор от Microsoft, подразумевающий использование JavaScript, с которым вы встречались в главе 1 и еще встретитесь в главе 10, «Работа с API процессоров XSLT») основаны на 1, поэтому первый ребенок — это ребенок 1. Условия позиции в XML-документах, которые используют таблицы стилей XSL и загружаются в текущую версию Internet Explorer (версию 5.5, на смену которой приходит 6.0), основаны на 0 (и в предикатах можно использовать только очень сокращенную форму выражений XPath) — и, следовательно, так же считается в большей части документации по XSL на web-узле Microsoft. В другом случае значением предиката должна быть ложь или истина, что называется логическим условием (Boolean test). Например, предикат [@UNITS="million miles"] выбирает элементы, у которых имеются атрибуты UNITS со значением "million miles".

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

• когда образец используется в атрибуте match, предикат не должен содержать никаких ссылок на переменные XSL (которые обсуждаются в главе 9). Это ограничение не применяется к предикатам, используемым в элементах ;

• образцы не могут использовать в предикатах функцию XPath current, возвращающую текущий узел. Ее применение ограничено, поэтому обработка зависит от реализации и не зависит от текущего состояния обработки.

В следующем примере образец выбирает элементы с дочерними элементами :

 .

 .

 .

Этот образец выбирает любой элемент с дочерним элементом :

 .

 .

 .

Теперь я задал элементам в planets.xml новый атрибут, COLOR, устанавливающий цвет планеты:

 

  Mercury

  .0553

  58.65

  1516

  .983

  43.4

 

 

  Venus

  .815

  116.75

  3716

  .943

  66.8

 

 

  Earth

    1

  2107

  1

  128.4

 

Следующее выражение выбирает элементы с атрибутом COLOR:

 .

 .

 .

А что, если нам требуется выбрать планеты, у которых атрибут COLOR имеет значение "BLUE" (голубой)? Это можно сделать при помощи операции =, как показано в листинге 4.5.

Листинг 4.5. Применение операции =

<"xml version="1.0"?>

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

  

  

  

 

 

  The is blue.

 

 

 

Таблица стилей из листинга 4.5 отбирает планеты с голубым цветом и убирает остальные, выключая правило по умолчанию для текстовых узлов. Результат следующий:

 The Earth is blue.

 

Создание предикатов

 

Предикаты — настоящие выражения XPath, и XPath гораздо ближе к настоящему языку, чем образцы: к примеру, выражения XPath могут возвращать не только списки узлов, но также логические, строковые и числовые значения. Выражения XPath могут работать не только с текущим узлом или дочерними узлами: можно работать с родительскими узлами, узлами-предками и другими узлами.

Глава 7 полностью посвящена XPath, но имеет смысл предоставить введение в предмет здесь, при обсуждении образцов, потому что часть предиката образца обладает наибольшими возможностями. В предикатах могут быть все виды выражений; в следующем списке перечислен ряд возможных типов, которые будут изучены в следующих разделах:

• наборы узлов;

• логические выражения;

• числа;

• строки.

 

Предикаты: наборы узлов

Набор узлов (node set), как понятно из названия, представляет собой просто совокупность узлов (и может содержать только один узел). Выражение child::PLANET возвращает набор узлов, состоящий из всех элементов . Выражение child::PLANET/child::NAME возвращает список узлов, состоящий из всех элементов , дочерних по отношению к элементам . Для выбора узла или узлов из набора узлов воспользуйтесь следующими функциями для работы с наборами узлов в предикатах:

• last(). Возвращает количество узлов в наборе узлов;

• position(). Возвращает позицию контекстного узла в контекстном наборе узлов (начиная с 1);

• count(node-set). Возвращает количество узлов в наборе. Если опустить node-set, функция будет применена к контекстному узлу;

• id(string ID). Возвращает набор узлов, содержащий элемент с ID, удовлетворяющим переданной функции строке, или пустой набор узлов, если такой элемент отсутствует. Можно перечислить несколько идентификаторов, разделенных символами-разделителями, — тогда функция вернет набор узлов, состоящий из элементов с этими идентификаторами;

• local-name(node-set). Возвращает локальное имя первого узла в наборе узлов. Если опустить node-set, функция будет применена к контекстному узлу;

• namespace-uri(node-set). Возвращает URI пространства имен первого узла в наборе узлов. Если опустить node-set, функция будет применена к контекстному узлу;

• name(node-set). Возвращает полностью определенное имя первого узла в наборе узлов. Если опустить node-set, функция будет применена к контекстному узлу.

В листинге 4.6 я перенумеровал элементы в выходном документе при помощи функции position().

Листинг 4.6. Применение функции position

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform>

 

  

   

     </p> <p class="paragraph">      The Planets </p> <p class="paragraph">     

   

  

   

  

 

 

 

  

  

  

     

 

Вот результат. Как видите, планеты перенумерованы:

 

   </p> <p class="paragraph">    The Planets </p> <p class="paragraph">  

 

 

  

   1. Mercury

 

  

   2. Venus

 

  

   3. Earth

 

 

Можно также применять функции для работы с наборами узлов в предикатах, как, например, PLANET[position()=last()], выбирающая последнего ребенка контекстного узла

 

Предикаты: логические значения

В выражениях XPath можно также использовать логические (Boolean) значения. Для чисел ноль принимается за ложь (false), другие значения — за истину (true). Пустая строка, "", также считается ложью, все остальные строки — истиной.

Для вычисления логических результатов true/false можно применять следующие логические операции XPath:

• != означает «не равно»;

• < означает «меньше, чем» (в документах XML или XSL используйте <);

• <= означает «меньше или равно» (в документах XML или XSL используйте <=);

• = означает «равно» (программисты на С, С++, Java и JavaScript, обратите внимание: эта операция пишется как один знак =, а не два);

• > означает «больше, чем»;

• >= означает «больше или равно».

ИСПОЛЬЗОВАНИЕ СИМВОЛА <

Особенно обратите внимание на то, что непосредственно в документах XML или XSL нельзя использовать символ <, необходимо использовать ссылку на сущность &lt;.

Для связи логических выражений логическими операциями And и Or используются ключевые слова and и or; слово not инвертирует логический смысл выражения — с истины на ложь или со лжи на истину.

В листинге 4.7 я определяю элемент Земли и помещаю в таблицу строки "Earth", "needs", "no" и "introduction" вместо числовых данных Земли. Я определяю, которая из планет есть Земля, при помощи предиката "[NAME='Earth']", проверяющего значение элемента , которое, в свою очередь, представляет собой заключенный в элементе текст. Я также предоставил шаблон для других планет, удовлетворяющих предикату "[NAME!='Earth']''.

Листинг 4.7. Определение планеты Земля

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

  

   

     </p> <p class="paragraph">      The Planets Table </p> <p class="paragraph">     

   

   

    

     The Planets Table

    

   

     

     

     

     

      

     

    

    

Name Mass Radius Day

   

  

 

 

 

   Earth

   needs

   no

   introduction.

  

 

 

  

  

   

   

   

  

 

 

  

 

  

 

 

  

  

  

 

 

  

  

  

 

Вот результат:

 

   </p> <p class="paragraph">    The Planets Table </p> <p class="paragraph">   

 

 

  <Н1>

   The Planets Table

 

 

   

   

    

    

    

   

   .

   .

   .

  

   

    

    

    

   

  

Name Mass Radius Day
Earth needs no introduction.

 

Результат можно увидеть на рис. 4.1.

Рис. 4.1. Применение предикатов XPath

В следующем примере используется логическая операция >. Это правило применяется ко всем элементам после позиции 5:

 

Имеется также функция true, всегда возвращающая значение true, и функция false, всегда возвращающая значение false. Функция not инвертирует логический смысл выражения, как в следующем случае, где я выбираю все элементы , кроме последнего:

 

Наконец, функция lang возвращает истину или ложь в зависимости от того, является ли язык контекстного узла (определяемый атрибутами xml:lang) таким же, как язык, который передан в эту функцию.

 

Предикаты: числа

В XPath числа хранятся в формате числа с плавающей точкой двойной точности. (Технически все числа XPath хранятся в 64-разрядном формате IEEE числа с плавающей точкой двойной точности, floating-point double.) Все числа хранятся как числа с двойной точностью — даже целые числа, как 5 в рассматриваемом примере:

 

Над числами можно производить ряд операций:

• + сложение;

• - вычитание;

• * умножение;

• div деление (символ /, соответствующий делению в других языках, в XML, XSL и XPath уже занят);

• mod возвращает значение деления по модулю двух чисел (остаток после деления первого числа на второе).

Например, элемент вставит в выходной документ строку "600". В следующем примере выбираются все планеты, у которых отношение дня (измеренного в днях Земли) к массе (где масса Земли принята за 1) больше 100:

 

  

  

  

 

XPath также поддерживает следующие функции работы с числами:

• ceiling(). Возвращает наименьшее целое, большее, чем переданное функции число;

• floor(). Возвращает наибольшее целое, меньшее, чем переданное функции число;

• round(). Округляет переданное число до ближайшего целого;

• sum(). Возвращает сумму переданных функции чисел.

Например, среднюю массу планет в planets.xml можно найти так, как в листинге 4.8:

Листинг 4.8. Вычисление средней массы планет

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

   

    The average planetary mass is:

    

  

 

 

 

Строки

В XPath строки формируются из символов Unicode, как можно было предположить. Ряд функций специально предназначен для работы со строками:

• string(object object1). Преобразует объект в строку;

• starts-with(string string1, string string2). Возвращает истину, если первая строка начинается (starts with) со второй строки;

• contains(string string1, string string2). Возвращает истину, если первая строка содержит (contains) вторую строку;

• substring(string string1, number offset number length). Возвращает length символов из строки, начиная со смещения offset;

• substring-before(string string1, string string2). Возвращает часть строки string1 до первого вхождения строки string2;

• substring-after(string string1, string string2). Возвращает часть строки string1 после первого вхождения string2;

• string-length(string string1). Возвращает количество символов в строке string1;

• normalize-space(string string1). Возвращает строку string1 после отбрасывания лидирующих и завершающих символов-разделителей и замены нескольких последовательных разделителей на один пробел;

• translate(string string1, string string2, string string3). Возвращает строку string1, в которой все вхождения символов в строке string2 заменены на соответствующие символы в строке string3;

• concat(string string1, string string2, ...). Возвращает конкатенацию (объединение) всех строк.

Есть еще одна строковая функция, о которой вам следует знать, входящая не в XPath, а в XSLT:

• format-number(number number1, string string2, string string3). Возвращает строку, содержащую число number1 в виде форматированной строки, используя string2 в качестве форматирующей строки (форматирующие строки создаются так же, как для метода Java java.text.DecimalFormat) и string3 как возможную строку локализации.

В листинге 4.9 я выбираю текстовые узлы, в которых текст начинается с 'Е', чтобы выбрать Earth (Земля), и добавляю текст '(the World)' (мир), получая 'Earth (the World)'. Для этого я применяю предикат "text()[starts-with(., 'Е')]".

Листинг 4.9. Применение функции starts-with

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

   

    .

    .

    .

   

  

 

 

  

  

  

  

   

  

 

 

  (the World)

 

 

  

  

  

  

 

 .

 .

 .

 

  

  

  

 

А вот результат — заметьте, что заголовок для Земли стал "Earth (the World)":

 

   </p> <p class="paragraph">    The Planets Table </p> <p class="paragraph">   

 

 

  

   The Planets Table

  

 

   

   

    

    

    

   

  

   

    

    

    

   

 

Name Mass Radius Day
Earth (the World) 1 (Earth = 1) 2107 miles 1 days

 

Этот документ показан на рис. 4.2.

Рис. 4.2. Применение текстовых предикатов 

 

Предикаты: фрагменты результирующего дерева

XSLT 1.0 добавляет к поддерживаемым XPath типам данных фрагменты результирующего дерева. Это фрагменты дерева, которые можно присваивать переменным XSLT, они не очень широко распространены. Практически все, что можно с ними сделать, — это вычислить их строковое значение. В рабочем проекте XSLT 1.1 их поддержка была удалена, поэтому, видимо, в XSLT 2.0 их уже не будет.

 

Сокращенный синтаксис предикатов

Выражения предикатов можно сокращать, опуская "position()=". Например, [position()=3] становится [3], [position()=last()] становится [last()] и т.д. С использованием сокращенного синтаксиса применять выражения XPath в предикатах становится существенно проще. Вот ряд примеров:

• PLANET[2]. Возвращает второго ребенка контекстного узла;

• PLANET[last()]. Возвращает последнего ребенка контекстного узла;

• /PLANETS/PLANET[2]/NAME[1]См. выпущенные издательством книги «XML и Java 2, библиотека программиста» и «XML, справочник». — Примеч. ред.
. Возвращает первый элемент второго элемента элемента ;

• PLANET[5][@UNITS="million miles"]. Возвращает пятого ребенка контекстного узла, только если у него имеется атрибут UNITS со значением "million miles". Это выражение можно также написать как PLANET[@UNITS="million miles"][5].

На этом мы заканчиваем рассмотрение трех частей образцов шага: осей, условий узлов и предикатов. Это строительные блоки образцов выбора. Лучше всего изучить создание образцов на примере, и многие примеры мы вскоре рассмотрим. Сначала, однако, важно рассмотреть две небольшие темы. Как вы помните из формального определения образцов выбора, можно помимо образцов шага, создавать образцы, выбирающие элементы по идентификатору (ID) или ключу.

 

Выбор по ID

В дополнение к созданию образцов из образцов шага, задающих ось, условие узла и предикат, можно применять и образец id() для выбора элементов с определенным значением ID. Для работы с этим образцом необходимо задать элементам атрибут ID, который должен быть объявлен с типом ID, что можно сделать в DTD или схеме документа. В следующем примере правило добавляет текст всех элементов, имеющих ID "favorite":

 

Вот как может выглядеть объявление DTD для planets.xml, в котором объявляется ID и его значение устанавливается в "favorite":

 id ID #REQUIRED>

]>

 

 Mercury

 .0553

 58.65

 1516

 .983

 43.4

.

.

.

Ряд процессоров XSLT не может осуществлять выбор по ID, потому что они не читают DDS или схему XML. (Возможность доступа к информации ID должна быть включена в XSLT 2.0.) Но есть альтернатива: можно осуществлять выбор по ключу.

ВОЗМОЖНАЯ ПОДДЕРЖКА IDREF

Помимо упрощения работы с ID, в XSLT 2.0 W3C даже рассматривает возможность включения поддержки IDREF. В частности, по заданному ID процессор XSLT может предоставить список всех элементов с атрибутом IDREF или IDREFS, ссылающихся на этот ID. (Заметьте, что сейчас это тоже можно сделать при помощи элемента <xsl:key> и образца "key()".)

 

Выбор по ключу

Ключи дают простой способ идентифицировать элементы; конкретные ключи можно выбрать при помощи образца "key()". Работа с ключами подробно обсуждается в главе 9, но здесь я также приведу небольшой пример.

Для создания ключа служит элемент . Это элемент верхнего уровня, поэтому он используется вне шаблонов и как дочерний элемент . В следующем примере я при помощи ключа выбираю планеты, чей атрибут COLOR (цвет) установлен в "BLUE" (голубой), что означает Землю:

 .

 .

 .

 

  Earth

  1

  1

  2107

  1

  128.4

 

Теперь я могу создать ключ с именем COLOR, который выбирает элементы , проверяя их атрибут COLOR:

 xmlns:xsl="http.//www.w3.org/1999/XSL/Transform">

 

 .

 .

 .

Теперь при помощи образца "key()" можно выбрать элементы с атрибутом COLOR со значением "BLUE":

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

   

     </p> <p class="paragraph">      The Planets Table </p> <p class="paragraph">     

   

   

   

     The Planets Table

    

   

     

     

      

      

     

     

    

   

Name Mass Radius Day

   

  

 

 .

 .

 .

А вот результат — как видите, единственной планетой, удовлетворявшей используемому образцу, была Земля (Earth).

 

   </p> <p class="paragraph">    The Planets Table </p> <p class="paragraph">   

 

 

  

   The Planets Table

  

 

   

   

    

    

    

   

  

   

    

    

    

  

  

Name Mass Radius Day
Earth 1 (Earth = 1) 2107 miles 1 days

 

 

Применение операции Or

При помощи операции Or (или), |, можно осуществлять выбор по нескольким возможным образцам, что очень удобно с ростом сложности документов. В следующем примере я хочу отобразить элементы и полужирным, что задается тегом HTML <В>. Для выбора либо элементов , либо в новом правиле я использую операцию Or:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

  

   

    .

    .

    .

  

  

 

 

  

  

   

   

   

  

 

 

  

  

 

 

 

  

  

  

 

 

  

  

  

 

Вот результаты; заметьте, что значения имени и массы заключены в элементы <В>:

 

   </p> <p class="paragraph">    The Planets Table </p> <p class="paragraph">   

 

 

  .

  .

  .

  

    Mercury

    .0553

    1516 miles

    58.65 days

   

  

    Venus

    .815

    3716 miles

    116.75 days

   

   

    Earth

    1

    2107 miles

    1 days

   

  

 

Операцию | можно применять к любым допустимым образцам — например, в таких выражениях, как "PLANET|PLANET//NAME"; можно использовать несколько операций | — например, "NAME|MASS|DAY" и т.п.

 

Примеры образцов

Изучать образцы лучше всего на примерах. Предположим, что нам требуется преобразовать planets.xml в planets.html, но сохранить только первую планету, Меркурий. Это можно сделать при помощи предиката [position()<2], так как позиция первой планеты равна 1, следующей — 2, и т.д. Заметьте, однако, что <; является управляющим символом для процессоров XSLT, начинающим разметку, поэтому вместо < необходимо использовать <. И отметьте, что для того чтобы убрать из planets.xml другие элементы, для них нужно предоставить пустой шаблон, что можно сделать при помощи предиката [position()>=2] (листинг 4.10).

Листинг 4.10. Выбор только Меркурия

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

  

   

     </p> <p class="paragraph">      The Planets Table </p> <p class="paragraph">     

   

   

    

     The Planets Table

    

   

     

     

      

     

      

     

    

    

Name Mass Radius Day

   

 

 

 

  

  

   

   

   

  

 

 

 

 

 

  

  

 

 

  

  

  

 

 

  

  

  

 

Вот результирующий документ — отметьте, что сохранилась только первая планета, Меркурий:

 

   </p> <p class="paragraph">    The Planets Table </p> <p class="paragraph">   

 

 

  

   The Planets Table

  

 

   

   

    

    

    

   

  

   

    

    

    

   

  

Name Mass Radius Day
Mercury .0553 (Earth = 1) 1516 miles 58.65 days

 

В следующем примере в элемент Земли были добавлены атрибуты COLOR (цвет) и POPULATED (населена):

 Earth

 1

 1

 2107

 1

 1284

Как выбрать только элементы, имеющие оба атрибута, COLOR и POPULATED? Можно применить предикат "[@COLOR and @POPULATED]". Чтобы убрать другие элементы — так, чтобы правило по умолчанию не поместило их текст в результирующий документ, — можно применить предикат "[not(@COLOR) or not(@POPULATED)]", как показано в листинге 4.11.

Листинг 4.11. Выбор только элементов с двумя атрибутами COLOR и POPULATED

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

  

   

     </p> <p class="paragraph">      Colorful, Populated Planets </p> <p class="paragraph">     

   

   

    

     Colorful, Populated Planets

    

   

     

     

      

      

      

     

    

    

Name Mass Radius Day

   

  

 

 

 

  

   

   

   

  

 

 

 

 

  

  

  

 

 

  

  

  

 

 

  

  

  

 

А вот результат:

 

   </p> <p class="paragraph">    Colorful, Populated Planets </p> <p class="paragraph">   

 

 

  

   Colorful, Populated Planets

  

 

   

   

    

    

    

   

  

   

    

    

    

  

  

Name Mass Radius Day
Earth 1 (Earth = 1) 2107 miles 1 days

 

Этот документ показан на рис. 4.3.

Рис. 4.3. Применение предикатов XPath для проверки атрибутов

В следующем примере я копирую planets.xml в новый XML-документ и изменяю текст в элементе Венеры на "The Planet of Love" (планета любви). Для этого я сначала копирую в результирующий документ все узлы и атрибуты:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

  

 

 

 .

 .

 .

Теперь я добавлю новое правило, выбирающее элементы с текстом "Venus" (Венера) по образцу "NAME[text()='Venus']". Хотя элементы удовлетворяют обоим правилам этой таблицы стилей, правило с образцом "NAME[text()='Venus']" осуществляет более узкий выбор, поэтому для элемента Венеры процессор XSLT применит его:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

  

 

 

 

  

   The Planet of Love

  

 

И вот результат:

 

  Mercury

  .0553

  58.65

  1516

  .983

  43.4

 

 

  

   The Planet of Love

  

  .815

  116.75

  3716

  .943

  66.8

 

 

  Earth

  1

  1

  2107

  1

  128.4

 

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

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

  

  

 

 

  

   The Planet of Love

  

 

Имеет смысл привести как можно больше примеров — примеров XPath или образцов выбора никогда не бывает слишком много. Ниже приведен содержательный ряд примеров образцов выбора:

• PLANET выбирает дочерние элементы контекстного узла;

• /PLANETS выбирает корневой элемент документа;

• * выбирает все дочерние элементы контекстного узла;

• PLANET[3] выбирает третьего ребенка контекстного узла;

• PLANET[last()] выбирает последнего ребенка контекстного узла;

• PLANET[NAME] выбирает детей контекстного узла, имеющих детей ;

• PLANET[DISTANCE]/NAME выбирает все элементы элементов , содержащих по крайней мере один элемент ;

• PLANET[DISTANCE]/PLANET[DAY] выбирает все элементы элементов , в которых элемент содержит по крайней мере один элемент , и элемент содержит по крайней мере один элемент ;

• РLANETS[РLАNET/DAY] выбирает все элементы , содержащие элементы как минимум с одним элементом ;

• PLANET[DISTANCE][NAME] выбирает все элементы , имеющие элементы и ;

• PLANETS/PLANET[last()] выбирает последний элемент в каждом элементе ;

• */PLANET выбирает всех внуков контекстного узла;

• /PLANETS/PLANET[3]/NAME[2] выбирает второй элемент третьего элемента элемента ;

• //PLANET выбирает всех потомков корня документа;

• PLANETS//PLANЕТ выбирает потомков элемента детей элемента контекстного узла;

• //PLANET/NAME выбирает все элементы , дочерние по отношению к родителю ;

• РLАNETS//PLАNET/DISTАNСЕ//РЕRIНЕLION выбирает элементы везде внутри элемента элемента , везде внутри элемента ;

• @UNITS выбирает атрибут UNITS контекстного узла;

• @* выбирает все атрибуты контекстного узла;

• *[@UNITS] выбирает все элементы с атрибутом UNITS;

• DENSITY/@UNITS выбирает атрибут UNITS в элементах ;

• PLANET[not(@COLOR) or not(@SIZE)] выбирает элементы , не имеющие обоих атрибутов COLOR и SIZE;

• PLANETS[@STAR="Sun"]//DENSITY выбирает любой элемент с элементом-предком , имеющим атрибут STAR со значением "Sun";

• PLANET[NAME="Venus"] выбирает детей контекстного узла, имеющих детей с текстом "Venus";

• PLANET[NAME[1]См. выпущенные издательством книги «XML и Java 2, библиотека программиста» и «XML, справочник». — Примеч. ред.
="Venus"] выбирает все элементы , у которых в первом элементе содержится текст в "Venus";

• DAY[@UNITS!="million miles"] выбирает все элементы , атрибут UNITS которых не равен "million miles";

• PLANET[@UNITS="days"] выбирает всех детей контекстного узла, имеющих атрибут UNITS со значением "days";

• PLANET[6][@UNITS="days"] выбирает шестого ребенка контекстного узла, только если у этого ребенка есть атрибут UNITS со значением "days", — что также можно записать как PLANET[@UNITS="days"][6];

• PLANET[@COLOR and @UNITS] выбирает всех детей контекстного узла, имеющих оба атрибута COLOR и UNITS;

• *[1]См. выпущенные издательством книги «XML и Java 2, библиотека программиста» и «XML, справочник». — Примеч. ред.
[NAME] выбирает любой элемент , являющийся первым ребенком своего родителя;

• *[position() < 5] выбирает первые пять детей контекстного узла;

• *[position() < 5][@UNIT] выбирает первые пять детей контекстного узла с атрибутом UNITS;

• text() выбирает все дочерние текстовые узлы контекстного узла;

• text()[starts-with(., "In the course of human events")] выбирает все дочерние текстовые узлы контекстного узла, начинающиеся с "In the course of human events";

• /PLANETS[@UNITS="million miles"] выбирает все элементы PLANETS, у которых значение атрибута UNITS равно "million miles";

• PLANET[/PLANETS/@UNITS=@REFERENCE] выбирает все элементы , у которых значение атрибута REFERENCE такое же, как значение атрибута UNITS элемента PLANETS в корне документа;

• PLANET/* выбирает все дочерние элементы элементов PLANET;

• PLANET/*/DAY выбирает все элементы DAY — правнуки элементов PLANET, являющиеся детьми контекстного узла;

• */* выбирает элементы-внуки текущего элемента;

• astrophysics:PLANET выбирает элемент PLANET в пространстве имен «astrophysics»;

• astrophysics:* выбирает любые элементы в пространстве имен «astrophysics»;

• PLANET[DAY and DENSITY] выбирает все элементы , у которых есть по крайней мере один элемент и один элемент ;

• PLANET[(DAY or DENSITY) and MASS] выбирает все элементы , у которых есть по крайней мере один элемент или один элемент , а также по крайней мере один элемент ;

• PLANET[DAY and not(DISTANCE)] выбирает все элементы , у которых есть по крайней мере один элемент и нет элементов ;

• PLANET[MASS=/STANDARD/REFERENCE/MASS] выбирает все элементы , у которых значение элемента равно значению элемента ///.

На этом мы завершаем в данный момент рассмотрение образцов выбора; связанный материал приводится в главе 7 при рассмотрении выражений XPath. Глава 5 начинается с изучения способов работы с данными в XML-документах путем сортировки и принятия решения на основе значений данных.