2 Пути адресации
Хотя пути адресации (location path) и не являются самой главной грамматической конструкцией языка (LocationPath - это частный случай Expr), они имеют самое большое значение, а потому будут описаны в первую очередь.
Каждый путь адресации может быть описан с помощью простого, но довольно громоздкого синтаксиса. Существует также ряд синтаксических аббревиатур для краткого обозначения основных случаев. Сперва в этой главе с помощью развернутого синтаксиса будет дано разъяснение семантики путей адресации. Затем будет показано, каким образом сокращенный синтаксис приводится к развернутому (см. [2.5 Сокращенный синтаксис]).
Ниже приводятся некоторые примеры путей адресации, использующих развернутый синтаксис:
child::para
находит элемент para
, являющийся непосредственным потомком узла контекста
child::*
собирает все элементы, являющиеся непосредственными потомками узла контекста
child::text()
собирает все текстовые узлы, являющиеся непосредственными потомками узла контекста
child::node()
собирает все непосредственные потомки текущего узла контекста независимо от типа этих узлов
attribute::name
в текущем узле контекста находит атрибут name
attribute::*
собирает все атрибуты в текущем узле контекста
descendant::para
среди потомков узла контекста находит элементы para
ancestor::div
собирает все предки div
текущего узла контекста
ancestor-or-self::div
собирает предки div
текущего узла контекста и также, если сам узел контекста тоже является элементом div
, включает в набор и его
descendant-or-self::para
среди потомков узла контекста выбирает элементы para
а также, если сам узел контекста является элементом para
, то включает в набор и его
self::para
выбирает текущий узел контекста, если это элемент para
, либо в противном случае не выбирает ничего
child::chapter/descendant::para
выбирает элементы para
среди потомков элемента chapter
, являющегося непосредственным потомком текущего узла контекста
child::*/child::para
собирает все para
, являющиеся потомками текущего узла контекста во втором поколении
/
находит корень документа (который всегда является родителем элемента документа)
/descendant::para
в документе, которому принадлежит узел контекста, находит все элементы para
/descendant::olist/child::item
находит все элементы item
, которые имеют родителем olist
и находятся в пределах документа, в котором располагается узел контекста
child::para[position()=1]
находит первый непосредственный потомок para
текущего узла контекста
child::para[position()=last()]
находит последний непосредственный потомок para
текущего узла контекста
child::para[position()=last()-1]
находит предпоследний непосредственный потомок para
текущего узла контекста
child::para[position()>1]
среди непосредственных потомков текущего узла контекста собирает все para
, за исключением первого
following-sibling::chapter[position()=1]
находит следующий chapter
, имеющий с узлом контекста общего родителя
preceding-sibling::chapter[position()=1]
находит предыдущий chapter
, имеющий с узлом контекста общего родителя
/descendant::figure[position()=42]
находит в документе сорок второй элемент figure
/child::doc/child::chapter[position()=5]/child::section[position()=2]
находит второй section
в пятом chapter
в элементе документа doc
child::para[attribute::type="warning"]
находит все непосредственные потомки para
текущего узла контекста, имеющие атрибут type
со значением warning
child::para[attribute::type='warning'][position()=5]
среди непосредственных потомков текущего узла контекста с названием para
и имеющих атрибут type
со значением warning
находит пятый элемент
child::para[position()=5][attribute::type="warning"]
среди непосредственных потомков para
узла контекста выбирает пятый элемент, при условии что он имеет атрибут type
со значением warning
child::chapter[child::title='Introduction']
среди непосредственных потомков chapter
текущего узла контекста выбирает тот, у которого в свою очередь имеется один или несколько непосредственных потомков title
со строковым значением Introduction
child::chapter[child::title]
среди непосредственных потомков текущего узла контекста chapter
находит тот, у которого имеется один или несколько непосредственных потомков title
child::*[self::chapter or self::appendix]
среди непосредственных потомков текущего узла контекста находит chapter
и appendix
child::*[self::chapter or self::appendix][position()=last()]
из множества непосредственных потомков текущего узла контекста chapter
и appendix
выбирает последний
Пути адресации бывают двух типов: относительные и абсолютные.
Относительный путь адресации состоит из последовательности одного или нескольких шагов адресации, отделенных друг от друга символом /
. Шаги в относительном пути адресации считаются слева направо. На каждом шаге осуществляется отбор узлов, отталкиваясь от некоторого узла контекста. Основная последовательность шагов образуется последовательным перечислением шагов в порядке их выполнения. Сперва, отталкиваясь от узла контекста, последовательность шагов набирает некий набор узлов. Затем каждый узел в этом наборе поочередно используется как узел контекста для следующего шага. Все наборы узлов, полученных после выполнения такого шага, опять собираются вместе. В итоге в полученном объединении будет собран набор узлов, идентифицируемых данной последовательностью шагов. Например, формула child::div/child::para
собирает все элементы para
, являющиеся непосредственными потомками элемента div
, который сам является непосредственным потомком узла контекста, или, иными словами, находит все элементы - потомки во втором поколении para
, родителями которых являются div
.
Абсолютный путь адресации состоит из символа /
, за которым может следовать относительный путь адресации. Сам символ /
находит корневой узел документа, в котором располагался текущий узел контекста. Если за этим символом последовал относительный путь адресации, то получившийся путь адресации будет собирать набор узлов так, как если бы в качестве узла контекста был выбран корневой узел того документа, которому принадлежал действительный текущий узел контекста.
Пути адресации
2.1 Шаги адресации
Шаги адресации (location step) состоят из трех частей:
оси (axis), указывающей дерево взаимоотношений между текущим узлом контекста и узлами, отбираемыми на данном шаге адресации,
правила проверки узлов, указывающего тип и расширенное название узлов, отбираемых на данном шаге адресации,
нуля или более предикатов, использующих произвольные выражения для дальнейшего отсева в наборе узлов, собранных на данном шаге адресации.
Синтаксис шага адресации образуется из названия оси и правила проверки узлов, отделенных друг от друга двумя символами двоеточия. За ними следует нуль или более выражений, каждое из которых заключено в квадратные скобки. Например, в выражении child::para[position()=1]
фрагмент child
- это название оси, para
- правило проверки узла, а [position()=1]
- предикат.
Набор узлов, собранных на данном шаге адресации, - это множество узлов, полученных в результате обработки ранее собранного набора узлов с учетом оси, правила проверки узлов и последующего отсева полученного набора узлов каждым из представленных предикатов.
Исходный набор узлов образуется из узлов, имеющих с текущим узлом контекста взаимосвязь, определяемую указанной осью, имеющих тип узла и расширенное имя, отвечающих представленному правилу проверки узлов. Например, шаг адресации descendant::para
находит элементы para
, являющиеся потомками текущего узла контекста: descendant
указывает, что каждый узел в первоначальном наборе должен быть потомком текущего узла контекста, а para
указывает, что каждый узел в исходном наборе должен быть элементом с названием para
. Можно использовать оси, описаные в главе [2.2 Оси]. Возможные правила проверки описаны в главе [2.3 Проверка узлов], причем смысл некоторых правил проверки меняется в зависимости от используемой оси.
Полученный исходный набор узлов фильтруется в соответствии с первым предикатом для получения нового набора узлов, затем этот новый набор фильтруется в соответствии со вторым предикатом и так далее. Окончательный набор узлов и будет тем самым набором, который получен в результате выполнения данного шага адресации. Выбранная ось оказывает влияние на обработку выражения для каждого предиката, а потому семантика предиката строится отталкиваясь от оси. См. [2.4 Предикаты].
Шаги адресации
2.2 Оси
Можно использовать следующие оси:
ось child
включает непосредственного потомка текущего узла контекста
ось descendant
состоит из потомков текущего узла контекста. Потомок - это непосредственный потомок, непосредственный потомок непосредственного потомка и так далее. Таким образом, ось потомков не содержит узлы атрибутов и узлы пространств имен.
ось parent
включает непосредственного родителя текущего узла контекста, если таковой имеется
ось ancestor
состоит из предков текущего узла контекста. Предки текущего узла контекста - это его родитель, родитель родителя и так далее. Таким образом, ось ancestor всегда будет содержать корневой узел, за исключением единственного случая, когда корневой узел является узлом контекста.
ось following-sibling
состоит из всех последующих узлов, которые с узлом контекста имеют общего родителя. Если узлом контекста является узел атрибута или узел пространства имен, ось following-sibling
будет пустой.
ось preceding-sibling
состоит из всех предшествующих узлов, которые с узлом контекста имеют общего родителя. Если узлом контекста является узел атрибута или узел пространства имен, ось preceding-sibling
будет пустой
ось following
. В документе, где располагается текущий узел контекста, находит все узлы, которые записанные после узла контекста. В число отобранных не попадают потомки текущего узла контекста, а также узлы атрибутов и пространств имен.
ось preceding
. В документе, где располагается текущий узел контекста, находит все узлы, которые предшествуют узлу контекста. В число отобранных не попадают предки текущего узла контекста, а также узлы атрибутов и пространств имен.
ось attribute
состоит из атрибутов текущего узла контекста. Если текущий узел контекста не является элементом, ось будет пустой.
ось namespace
состоит из узлов пространства имен, относящихся к текущему узлу контекста. Если текущий узел контекста не является элементом, ось будет пустой.
ось self
содержит только сам текущий узел контекста
ось descendant-or-self
образуется текущим узлом контекста и его потомками
ось ancestor-or-self
образуется текущим узлом контекста и его предками. Как результат, ось ancestor (примечание редактора: здесь, вероятно, ошибка — речь об оси ancestor-or-self — но в английском оригинале написано именно так) будет включать корневой узел.
Замечание: Оси ancestor
, descendant
, following
, preceding
и self
осуществляют разбиение документа (если игнорировать узлы атрибутов и пространств имен). При этом указанные оси не пересекаются, а все вместе задействуют все узлы документа.
Оси
[6] |
AxisName |
::= |
'ancestor' |
|
|
|
|
| 'ancestor-or-self' |
|
|
|
|
| 'attribute' |
|
|
|
|
| 'child' |
|
|
|
|
| 'descendant' |
|
|
|
|
| 'descendant-or-self' |
|
|
|
|
| 'following' |
|
|
|
|
| 'following-sibling' |
|
|
|
|
| 'namespace' |
|
|
|
|
| 'parent' |
|
|
|
|
| 'preceding' |
|
|
|
|
| 'preceding-sibling' |
|
|
|
|
| 'self' |
|
2.3 Проверка узлов
Каждая ось имеет основной тип узлов (principal node type). Если ось может содержать элементы, то для такой оси основным типом узлов будут элементы. В противном случае в качестве основного берется тип тех узлов, которые эта ось может содержать. Таким образом,
- для оси attribute основным типом узлов является атрибут.
- для оси namespace основным типом узлов является пространство имен.
- для остальных осей основным типом узлов является элемент.
Правило проверки узлов, соответствующее сценарию QName, имеет результатом true тогда и только тогда, когда тип узла (см. [5 Модель данных]) совпадает с основным типом узлов, а его расширенное имя совпадает с расширенным именем, указанным этим QName. Например, child::para
собирает элементы para
, являющиеся непосредственными потомками текущего узла контекста. Если текущий узел контекста не имеет непосредственного потомка para
, то будет получен пустой набор узлов. attribute::href
в текущем узле контекста выбирает атрибут href
. Если текущий узел контекста не имеет атрибута href
, будет получен пустой набор узлов.
QName в правиле для проверки узла, преобразуется в расширенное имя с помощью деклараций пространств имен в контексте этого выражения. Точно так же преобразуются названия типов элементов в начальных и конечных тэгах, за исключением того, что не используется пространство имен по умолчанию, декларированное с помощью xmlns
: если QName не имеет префикса, URI пространства имен будет нулевым (таким же способом обрабатываются названия атрибутов). Если QName имеет префикс, для которого в контексте выражения нет соответствующей декларации пространства имен, фиксируется ошибка.
Правило проверки узлов *
имеет результатом true для любого узла, если его тип соответствует основному. Например, child::*
найдет все элементы, являющиеся непосредственными потомками текущего узла контекста, а attribute::*
соберет все атрибуты текущего узла контекста.
Правило проверки узлов может иметь вид NCName:*
. В этом случае префикс, так же как и в случае с QName, преобразуется с помощью деклараций пространства имен в контексте. Если для этого префикса в контексте выражения не найдено соответствующей декларации пространства имен, фиксируется ошибка. Указанное правило проверки узла будет выдавать true для любого узла основного типа, чье расширенное имя имеет именно то URI пространства имен, к которому привязан указанный префикс, независимо от локальной части в названии узла.
Правило проверки узлов text()
будет давать результат true для любого текстового узла. Например, child::text()
будет собирать текстовые узлы, являющиеся непосредственными потомками текущего узла контекста. Точно так же, правило проверки узлов comment()
будет выдавать true для любого узла комментария, а правило проверки узлов processing-instruction()
- для любой инструкции обработки. Правило проверки processing-instruction()
может иметь аргумент типа Literal. В этом случае проверка будет давать true для любой инструкции проверки, чье название соответствует значению этого аргумента.
Правило проверки узлов node()
будет выдавать true для любого узла, к какому бы типу он не относится.
2.4 Предикаты
Оси делятся на прямые и обратные. Ось, содержащая лишь текущий узел контекста или те узлы, которые в документе следуют за ним, называется прямой осью (forward axis). Ось, содержащая текущий узел контекста или те узлы, которые в документе предшествуют ему, называется обратной осью (reverse axis). Таким образом, оси ancestor, ancestor-or-self, preceding и preceding-sibling являются обратными осями, а все остальные - прямыми. Поскольку ось self всегда содержит не более одного узла, то нет разницы, является ли она прямой или обратной. Положение близости (proximity position) по отношению к оси для какого-либо члена в наборе узлов определяется как положение узла в наборе, когда последний выстроен в соответствии с порядком следования узлов в документе, если ось является прямой, или в обратном порядке, если ось является обратной. Первая позиция имеет номер 1.
Для получения нового набора предикат фильтрует имеющийся набор узлов, отталкиваясь от оси. Каждый узел в исходном наборе, подлежащем фильтрации, поочередно становится узлом контекста и для него проверяется PredicateExpr. При этом в качестве размера контекста используется количество узлов в исходном наборе, а в качестве положения в контексте берется положение близости к оси. Если для данного узла PredicateExpr оценивается как true, то этот узел попадает во вновь создаваемый набор узлов, в противном случае узел туда не попадает.
Проверка PredicateExpr сводится к обработке Expr и приведению результата к булевому значению. Если результатом обработки является число, оно будет преобразовано в true, если соответствует положению узла в контексте. В противном случае оно преобразуется в false. Если же результат обработки не является числом, то он будет приведен к булевому значению как при вызове функции boolean. Таким образом, путь адресации para[3]
равнозначен para[position()=3]
.
Предикаты
2.5 Сокращенный синтаксис
Некоторые примеры путей адресации, использующих сокращенный синтаксис:
para
находит элемент para
, являющийся непосредственным потомком текущего узла контекста
*
находит все элементы, являющиеся непосредственными потомками текущего узла контекста
text()
находит все текстовые узлы, являющиеся непосредственными потомками текущего узла контекста
@name
выделяет атрибут name
в текущем узле контекста
@*
находит все атрибуты текущего узла контекста
para[1]
находит первый непосредственный потомок para
текущего узла контекста
para[last()]
находит последний непосредственный потомок para
текущего узла контекста
*/para
находит все потомки во втором поколении para
текущего узла контекста
/doc/chapter[5]/section[2]
в doc
в пятом chapter
находит второй section
chapter//para
собирает элементы para
, являющиеся потомками элемента chapter
, который является непосредственным потомком текущего узла контекста
//para
собирает все para
, являющиеся потомками корневого узла документа, то есть находит все элементы para
в том документе, где располагается текущий узел контекста
//olist/item
в документе, где располагается текущий узел контекста, находит все элементы item
, имеющие родителем olist
.
выделяет текущий узел контекста
.//para
собирает элементы para
, являющиеся потомками текущего узла контекста
..
выделяет родителя текущего узла контекста
../@lang
выделяет атрибут lang
, принадлежащий родителю текущего узла контекста
para[@type="warning"]
находит все непосредственные потомки para
текущего узла контекста, имеющие атрибут type
со значением warning
para[@type="warning"][5]
находит пятый по счету из непосредственных потомков para
текущего узла контекста, имеющих атрибут type
со значением warning
para[5][@type="warning"]
извлекает пятый непосредственный потомок para
текущего узла контекста, если этот потомок имеет атрибут type
со значением warning
chapter[title="Introduction"]
получает непосредственный потомок текущего узла контекста chapter
, который в свою очередь имеет один или несколько непосредственных потомков title
со строковым значением, равным Introduction
chapter[title]
находит непосредственный потомок chapter
текущего узла контекста, который имеет один или несколько непосредственных потомков title
employee[@secretary and @assistant]
находит все непосредственные потомки employee
данного узла контекста, которые имеют оба атрибута secretary
и assistant
Самой важной является аббревиатура child::
, которую при записи шага адресации всегда можно опустить. Фактически, child
используется как ось по умолчанию. Например, путь адресации div/para
становится сокращением для child::div/child::para
.
Аналогичные аббревиатуры имеются и для атрибутов: attribute::
может быть сокращен до @
. Например, путь адресации para[@type="warning"]
является сокращением для child::para[attribute::type="warning"]
, а следовательно, находит непосредственные потомки para
, имеющие атрибут type
, значение которого равно warning
.
//
является сокращением для /descendant-or-self::node()/
. Например, //para
- это сокращение для /descendant-or-self::node()/child::para
, а потому будет находить в документе все элементы para
(путь //para
найдет элемент para
, даже если последний является элементом документа, поскольку узел элемента документа является непосредственным потомком корневого узла). div//para
- это сокращение для div/descendant-or-self::node()/child::para
, а потому находит все потомки para
для непосредственного потомка div
.
Замечание: Путь адресации //para[1]
имеет иное значение, чем путь адресации /descendant::para[1]
. Последний отыскивает первый элемент-потомок para
, а предыдущий находит все элементы-потомки para
, являющиеся для своего родителя первым непосредственным потомком para
.
Шаг адресации .
является сокращением для self::node()
. Особенно эта запись полезна в сочетании с //
. Например, путь адресации .//para
является сокращением для
self::node()/descendant-or-self::node()/child::para
а потому будет находить все элементы para
, являющиеся потомками текущего узла контекста.
Точно так же, шаг адресации ..
является сокращением для parent::node()
. Например, ../title
- это сокращенная запись для parent::node()/child::title
, а потому для родителя текущего узла контекста будет находить непосредственные потомки title
.
Аббревиатуры
Назад |
Содержание |
Вперед