2 Пути адресации

Хотя пути адресации (location path) и не являются самой главной грамматической конструкцией языка (LocationPath - это частный случай Expr), они имеют самое большое значение, а потому будут описаны в первую очередь.

Каждый путь адресации может быть описан с помощью простого, но довольно громоздкого синтаксиса. Существует также ряд синтаксических аббревиатур для краткого обозначения основных случаев. Сперва в этой главе с помощью развернутого синтаксиса будет дано разъяснение семантики путей адресации. Затем будет показано, каким образом сокращенный синтаксис приводится к развернутому (см. [2.5 Сокращенный синтаксис]).

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

Пути адресации бывают двух типов: относительные и абсолютные.

Относительный путь адресации состоит из последовательности одного или нескольких шагов адресации, отделенных друг от друга символом /. Шаги в относительном пути адресации считаются слева направо. На каждом шаге осуществляется отбор узлов, отталкиваясь от некоторого узла контекста. Основная последовательность шагов образуется последовательным перечислением шагов в порядке их выполнения. Сперва, отталкиваясь от узла контекста, последовательность шагов набирает некий набор узлов. Затем каждый узел в этом наборе поочередно используется как узел контекста для следующего шага. Все наборы узлов, полученных после выполнения такого шага, опять собираются вместе. В итоге в полученном объединении будет собран набор узлов, идентифицируемых данной последовательностью шагов. Например, формула child::div/child::para собирает все элементы para, являющиеся непосредственными потомками элемента div, который сам является непосредственным потомком узла контекста, или, иными словами, находит все элементы - потомки во втором поколении para, родителями которых являются div.

Абсолютный путь адресации состоит из символа /, за которым может следовать относительный путь адресации. Сам символ / находит корневой узел документа, в котором располагался текущий узел контекста. Если за этим символом последовал относительный путь адресации, то получившийся путь адресации будет собирать набор узлов так, как если бы в качестве узла контекста был выбран корневой узел того документа, которому принадлежал действительный текущий узел контекста.

Пути адресации
[1]    LocationPath    ::=    RelativeLocationPath
| AbsoluteLocationPath
[2]    AbsoluteLocationPath    ::=    '/' RelativeLocationPath?
| AbbreviatedAbsoluteLocationPath
[3]    RelativeLocationPath    ::=    Step
| RelativeLocationPath '/' Step
| AbbreviatedRelativeLocationPath

2.1 Шаги адресации

Шаги адресации (location step) состоят из трех частей:

Синтаксис шага адресации образуется из названия оси и правила проверки узлов, отделенных друг от друга двумя символами двоеточия. За ними следует нуль или более выражений, каждое из которых заключено в квадратные скобки. Например, в выражении child::para[position()=1] фрагмент child - это название оси, para - правило проверки узла, а [position()=1] - предикат.

Набор узлов, собранных на данном шаге адресации, - это множество узлов, полученных в результате обработки ранее собранного набора узлов с учетом оси, правила проверки узлов и последующего отсева полученного набора узлов каждым из представленных предикатов.

Исходный набор узлов образуется из узлов, имеющих с текущим узлом контекста взаимосвязь, определяемую указанной осью, имеющих тип узла и расширенное имя, отвечающих представленному правилу проверки узлов. Например, шаг адресации descendant::para находит элементы para, являющиеся потомками текущего узла контекста: descendant указывает, что каждый узел в первоначальном наборе должен быть потомком текущего узла контекста, а para указывает, что каждый узел в исходном наборе должен быть элементом с названием para. Можно использовать оси, описаные в главе [2.2 Оси]. Возможные правила проверки описаны в главе [2.3 Проверка узлов], причем смысл некоторых правил проверки меняется в зависимости от используемой оси.

Полученный исходный набор узлов фильтруется в соответствии с первым предикатом для получения нового набора узлов, затем этот новый набор фильтруется в соответствии со вторым предикатом и так далее. Окончательный набор узлов и будет тем самым набором, который получен в результате выполнения данного шага адресации. Выбранная ось оказывает влияние на обработку выражения для каждого предиката, а потому семантика предиката строится отталкиваясь от оси. См. [2.4 Предикаты].

Шаги адресации
[4]    Step    ::=    AxisSpecifier NodeTest Predicate*
| AbbreviatedStep
[5]    AxisSpecifier    ::=    AxisName '::'
| AbbreviatedAxisSpecifier

2.2 Оси

Можно использовать следующие оси:

Замечание: Оси 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). Если ось может содержать элементы, то для такой оси основным типом узлов будут элементы. В противном случае в качестве основного берется тип тех узлов, которые эта ось может содержать. Таким образом,

Правило проверки узлов, соответствующее сценарию 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 для любого узла, к какому бы типу он не относится.
[7]    NodeTest    ::=    NameTest
| NodeType '(' ')'
| 'processing-instruction' '(' Literal ')'

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].

Предикаты
[8]    Predicate    ::=    '[' PredicateExpr ']'
[9]    PredicateExpr    ::=    Expr

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

Некоторые примеры путей адресации, использующих сокращенный синтаксис:

Самой важной является аббревиатура 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.

Аббревиатуры
[10]    AbbreviatedAbsoluteLocationPath    ::=    '//' RelativeLocationPath
[11]    AbbreviatedRelativeLocationPath    ::=    RelativeLocationPath '//' Step
[12]    AbbreviatedStep    ::=    '.'
| '..'
[13]    AbbreviatedAxisSpecifier    ::=    '@'?

Назад | Содержание | Вперед