Полный синтаксис выражений XPath описан в спецификации XPath, и я приведу его здесь для справки. Как и в случае образцов выбора, для формального определения выражений XPath W3C использует нотацию расширенных форм Бэкуса-Наура (РБНФ). (Описание этой грамматики вы можете найти по адресу www.w3.org/TR/REC-xml, раздел 6.) В следующем списке приведена нужная нам нотация РБНФ:
•
::=
означает «определяется как»;•
+
означает «один или больше»,•
*
означает «ноль или больше»;•
|
означает «или»;•
-
означает «не»;•
?
означает «не обязательно»;Также примите во внимание, что когда элемент заключен в одиночные кавычки, как
'ancestor'
или '::
', это значит, что элемент должен появиться в выражении буквально (как "ancestor::PLANET
"), — такие элементы называются литералами, literals
. Ниже приведено полное формальное определение выражения XPath (здесь оно называется Expr
):Expr ::= OrExpr
OrExpr ::= AndExpr | OrExpr 'or' AndExpr
AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
EqualityExpr ::= Relational Expr | EqualityExpr '=' Relational Expr
| EqualityExpr '!=' RelationalExpr
RelationalExpr ::= AdditiveExpr | RelationalExpr '<' AdditiveExpr
| RelationalExpr '>' AdditiveExpr | RelationalExpr '<=' AdditiveExpr
| RelationalExpr '>=' AdditiveExpr
AdditiveExpr ::= MultiplicativeExpr | AdditiveExpr '+' MultiplicativeExpr
| AdditiveExpr '-' MultiplicativeExpr
MultiplicativeExpr ::= UnaryExpr
| MultiplicativeExpr
MultiplyOperator ::= UnaryExpr
| MultiplicativeExpr 'div' UnaryExpr | MultiplicativeExpr 'mod' UnaryExpr
UnaryExpr ::= UnionExpr | '-' UnaryExpr
MultiplyOperator ::= '*'
UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
PathExpr ::= LocationPath | FilterExpr
| FilterExpr '/' RelativeLocationPath | FilterExpr '//' RelativeLocationPath
LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
AbsoluteLocationPath ::= '/' RelativeLocationPath? | AbbreviatedAbsoluteLocationPath
RelativeLocationPath ::= Step | RelativeLocationPath '/' Step
| AbbreviatedRelativeLocationPath
AbbreviatedAbsoluteLocationPath ::= '//' RelativeLocationPath
AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
AxisSpecifier ::= AxisName '::' | AbbreviatedAxisSpecifier
AxisName ::= 'ancestor' | 'ancestor-or-self' | 'attribute' | 'child' | 'descendant'
| 'descendant-or-self' | 'following' | 'following-sibling' | 'namespace'
| 'parent' | 'preceding' | 'preceding-sibling' | 'self'
AbbreviatedAxisSpecifier ::= '@'?
NodeTest ::= NameTest | NodeType '(' ')'
| 'processing-instruction' '(' Literal ')'
NameTest ::= '*' | NCName '*' | QName
NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
Predicate ::= '[' PredicateExpr ']'
PredicateExpr ::= Expr
FilterExpr ::= PrimaryExpr | FilterExpr Predicate
PrimaryExpr ::= VariableReference | '(' Expr ')'
| Literal | Number | FunctionCall
VariableReference ::= '$' QName
Number ::= Digits ('.' Digits?)? | Digits
Digits ::= [0-9]+
FunctionCall ::= FunctionName '(' ( Argument ( Argument )* )? ')'
FunctionName ::= QName - NodeType
Argument ::= Expr
AbbreviatedStep := '.' | '..'
Как видите, спецификация весьма объемна, она включает и обращения к функциям XPath (с которыми мы познакомимся в следующей главе). Лучший способ понять, как работают выражения XPath, — рассмотреть их по возвращаемым типам данных.
Типы данных XPath
В XPath существует четыре типа данных, а не только тип набора узлов, который должны возвращать образцы выбора:
• наборы узлов;
• логические значения;
• числа;
• строки.
ФРАГМЕНТЫ РЕЗУЛЬТИРУЮЩЕГО ДЕРЕВА
В XSLT 1.0 к типам данных XPath добавляются фрагменты результирующего дерева. Как говорилось в главе 4, фрагменты результирующего дерева представляют собой просто фрагменты дерева, которые можно присваивать переменным XSLT. Их поддержка была удалена из рабочего проекта XSLT 1.1, поэтому, скорее всего, они не будут включены в XSLT 2.0. Фрагменты результирующего дерева можно рассматривать как типы данных при помощи , что мы и увидим в главе 9.
В следующих разделах мы по очереди рассмотрим эти типы данных.
Наборы узлов XPath
Как следует из имени, набор узлов (node set) является просто совокупностью узлов. Набор узлов может включать несколько узлов, единственный узел или быть пустым. Поскольку главная задача XPath — определять место разделов документов, постольку возвращающие наборы узлов выражения XPath являются наиболее популярными типами выражений. Например, выражение XPath
child::PLANET
возвращает набор узлов из всех элементов
, дочерних для контекстного узла. Выражение child::PLANET/child::NAME
возвращает набор узлов из всех элементов
, дочерних для элементов
контекстного узла. Выражения XPath такого рода называются путями расположения, location path (W3C называет их «самой важной конструкцией» в XPath), и существенная часть этой главы будет посвящена разъяснению путей расположения.Чтобы выбрать узел или узлы из набора узлов или обработать их, вы можете воспользоваться следующими функциями XPath для работы с наборами узлов, которые впервые встретились нам в главе 4 (и которые мы более подробно рассмотрим в следующей главе):
•
count(node-set)
. Эта функция возвращает количество узлов в наборе. Если опустить параметр «набор узлов», функция будет применена к контекстному узлу;•
id(string ID)
. Эта функция возвращает набор узлов из элемента, чей ID удовлетворяет строке, переданной функции в качестве параметра, или пустой набор узлов, если ни у какого элемента нет указанного ID. Можно указать несколько идентификаторов, разделенных символами-разделителями, — в таком случае функция вернет набор узлов из элементов с этими идентификаторами;•
last()
. Возвращает номер последнего узла в наборе;•
local-name(node-set)
. Возвращает локальное имя первого узла в наборе. Если опустить параметр «набор узлов», функция будет применена к контекстному узлу;•
name(node-set)
. Возвращает полностью определенное имя первого узла в наборе. Если опустить параметр «набор узлов», функция будет применена к контекстному узлу;•
namespace-uri(node-set)
. Возвращает URI пространства имен первого узла в наборе. Если опустить параметр «набор узлов», функция будет применена к контекстному узлу;•
position()
. Возвращает позицию контекстного узла в контекстном наборе узлов (начиная с 1).В следующем примере (из главы 6) для подсчета количества узлов в наборе применяется функция
count
. В этом случае набор узлов состоит из всех элементов
в planets.xml
, и я получил его при помощи пути расположения «\\PLANET
» (который как путь расположения также является выражением XPath):
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
Ниже показан результат; заметьте, что у каждого элемента
есть оба атрибута, number
и total
, и атрибут total
содержит общее число элементов
в документе:
Mercury
.0553
58.65
1516
.983
43.4
Venus
.815
116.75
3716
.943
66.8
Earth
1
1
2107
1
128.4
Среди функций для работы с наборами узлов в особенности обратите внимание на функции
name
и local-name
. С их помощью можно определить имя текущего элемента: например, если текущим элементом является
, local-name
вернет DAY
. Следующая таблица стилей демонстрирует, для чего это может понадобиться; в ней я использую такие теги, как
,
и
, в качестве элементов буквального результата:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Однако в таком случае разметка трактуется как простой текст. Вместо этого можно создать новые элементы при помощи
, определяя имена контекстных узлов через local-name
:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Ряд пишущих об XSLT авторов рассматривает выражения XSLT только как выражения, возвращающие наборы узлов. Но выражения XPath возвращают также логические значения, числа и строки, которые используются в элементах
, ,
,
,
, шаблонах значений атрибутов и предикатах путей расположения. В предыдущем примере для вставки в документ числа я присвоил атрибуту select
элемента
выражение XPath count(//PLANET)
, которое возвращает не набор узлов, а число. Сейчас мы как раз перейдем к обработке чисел при помощи выражений XPath.Числа XPath
В XPath числа хранятся в формате чисел с плавающей точкой двойной точности. В соответствии с формальным определением, числа XPath должны храниться в формате 64-разрядных чисел с плавающей точкой двойной точности IEEE 754, и все числа хранятся как числа с плавающей точкой двойной точности.
В XPath можно выполнять следующие операции над числами, как мы уже видели в главе 4 при обсуждении предикатов XPath:
•
+
сложение;•
-
вычитание;•*
умножение;
•
div
деление (символ /, соответствующий делению в других языках, в XML и XPath уже занят);•
mod
возвращает значение деления по модулю двух чисел (остаток после деления первого числа на второе).Например, элемент
вставит в выходной документ строку «90
». В следующем примере выбираются все планеты, чей день (измеренный в днях Земли), умноженный на расстояние планеты от Солнца (измеренное в миллионах миль), больше, чем 60 000:
XPath также поддерживает следующие функции работы с числами:
•
ceiling()
. Возвращает наименьшее целое, большее, чем переданное функции число;•
floor()
. Возвращает наибольшее целое, меньшее, чем переданное функции число;•
round()
. Округляет переданное число до ближайшего целого;•
sum()
. Возвращает сумму переданных функции чисел.Например, среднее расстояние от Солнца (в миллионах миль) планет в
planets.xml
можно найти таким способом:
xmlns.xsl="http://www.w3.org/1999/XSL/Transform">
The average planetary distance from the Sun is:
Строки XPath
В XPath строки по умолчанию состоят из символов Unicode. Как мы уже видели в главе 4 при обсуждении выражений XPath в предикатах выбора, существует ряд функций, специально предназначенных для работы со строками (более подробно они будут изучаться в следующей главе):
•
concat(string string1, string string2,...)
. Возвращает конкатенацию (объединение) всех строк;•
contains(string string1, string string2)
. Возвращает true
(истину), если первая строка содержит (contains) вторую строку;•
format-number(number number1, string string2, string string3)
. Возвращает строку, содержащую число number1
в виде форматированной строки, используя string2
в качестве форматирующей строки (форматирующие строки создаются так же, как для метода Java java.text.DecimalFormat
) и string3
как возможную строку локализации;•
normalize-space(string string1)
. Возвращает строку string1
после отбрасывания лидирующих и завершающих символов-разделителей и замены нескольких последовательных разделителей на один пробел;•
starts-with(string string1, string string2)
. Возвращает истину, если первая строка начинается (starts with) со второй строки;•
string-length(string string1)
. Возвращает количество символов в строке string1
;•
substring(string string1, number offset number length)
. Возвращает length
символов из строки, начиная со смещения offset
;•
substring-after(string string1, string string2)
. Возвращает часть строки string1
после первого вхождения string2
;•
substring-before(string string1, string string2)
. Возвращает часть строки string1
до первого вхождения строки string2
;•
translate(string string1, string string2, string string3)
. Возвращает строку string1
, в которой все вхождения символов в строке stri
ng2 заменены на соответствующие символы в строке string3
.В листинге 7.1 я ищу слово «miles» во всех атрибутах, и если оно встречается, добавляю в результирующий документ текст «You should switch to kilometers.» (Нужно перевести в километры.).
Листинг 7.1. Поиск текста в атрибутах
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
Distance
You should switch to kilometers.
Вот результирующий документ:
The Planets Table
The Planets Table
Name
Mass
Radius
Day
Distance
Mercury
.0553 (Earth = 1)
1516 You should switch to kilometers.
58.65 days
43.4 You should switch to kilometers.
Venus
.815 (Earth = 1)
3716 You should switch to kilometers.
116.75 days
66.8 You should switch to kilometers.
Earth
1 (Earth = 1)
2107 You should switch to kilometers.
1 days
128.4 You should switch to kilometers.
Помимо работы с наборами узлов, числами и строками, можно работать и с логическими значениями (true/false).
Логические значения XPath
Логические (Boolean) выражения XPath вычисляются либо в истину (true), либо в ложь (false), и обычно они используются только в предикатах. Для чисел ноль принимается за ложь, другие значения — за истину. Пустая строка, "", также считается ложью, все остальные строки — истиной.
Для генерации логических результатов true/false в XPath можно применять ряд логических операций, как мы видели в обзоре в главе 4:
•
!=
означает «не равно»;•
<
означает «меньше, чем» (в документах XML используйте <
);•
<=
означает «меньше или равно» (в документах XML используйте <=
);•
=
означает «равно» (программисты на С, С++, Java и JavaScript, обратите внимание: эта операция пишется как один знак =, а не два);•
>
означает «больше, чем»;•
>=
означает «больше или равно».Для связи логических выражений логическими операциями And и Or используются ключевые слова
and
и or
, слово not
инвертирует логический смысл выражения, как в следующем примере, где я выбираю все элементы
, кроме первого и последнего:
Следующий пример уже встречался нам в главе 5, он использует логическую операцию
not
и операции =
и !=
:
Each planet must have a name!
,
and
.
Кроме того, имеется функция
true
, всегда возвращающая истину, и функция false
, всегда возвращающая ложь. Есть также функция lang
, при помощи которой вы можете проверить язык, установленный в атрибуте документа xml:lang
: эта функция возвращает истину, если язык, который вы передали в эту функцию, такой же, как и установленный в документе язык.Как вы видели, существуют все виды выражений XPath, в том числе возвращающие узлы, числа, строки и логические значения. Наиболее важным типом выражений XPath является путь расположения; для создания путей расположена XPath первоначально и задумывался, поэтому оставшаяся часть главы будет посвящена работе с ними.
Создание путей расположения XPath