□ */@* — выберет все атрибуты всех дочерних элементов контекстного узла;
□ //* [local-name(.) = 'body'] — выберет все элементы body текущего документа вне зависимости от их пространств имен.
Паттерны
В языке XSLT определяется подмножество выражений языка XPath, которые называются
Чаще всего паттерны применяются в элементе xsl:template в атрибуте match. Шаблоны такого типа будут выполняться только для тех узлов, которые удовлетворяют заданному образцу. Например, следующий шаблон будет выполняться только для элементов body, принадлежащих элементу html:
<xsl:template match='html/body'>
...
</xsl:template>
Кроме этого, паттерны применяются при нумерации и при определениях ключей.
Паттерны являются сильно упрощенными путями выборки. Единственные оси, которые могут использоваться в паттернах, — это child, attribute и descendant-or- self, причем ось навигации descendant-or-self может быть указана только в сокращенном виде оператором '//'. То, что в паттернах используются только оси атрибутов и узлов-потомков, позволяет XSLT-процессорам значительно оптимизировать процесс сопоставления узла заданному образцу — ведь теперь даже в самом худшем сценарии не нужно метаться по всему документу, выбирая узлы, содержащиеся в тех или иных осях навигации. Правда, оператор '//' остается не менее опасным — при его проверке может понадобиться перебрать всех предков текущего узла, что может быть весьма и весьма затруднительно (хотя и проще, чем перебор всех потомков).
Хоть паттерны и выглядят как пути выборки, на самом деле механизм их работы несколько иной. Они не выбирают множество узлов, как таковое, они проверяют узлы на соответствие образцу, который они определяют. Это в принципе эквивалентно выбору множества и проверке узла на вхождение в него, но, как правило, так не делается, поскольку такая проверка потребовала бы слишком больших затрат времени. Гораздо дешевле в этом смысле воспользоваться тем фактом, что синтаксис паттернов упрощен, и осей не так много для того, чтобы создать более эффективный алгоритм проверки соответствия узлов. Например, для того чтобы проверить соответствие некоторого узла, назовем его X, паттерну body/a, совершенно необязательно вычислять путь выборки body/a и затем проверять, входит ли узел X в полученное множество. Достаточно проверить, является ли именем узла 'a', а именем его родителя (если он, конечно, есть) — 'body'.
Образцы для сравнения могут состоять из одного или нескольких паттернов, которые перечисляются через знак '|'. Для того чтобы соответствовать такому перечислению в целом, узел должен соответствовать хотя бы одному из паттернов, входящих в него. Здесь тоже есть определенная аналогия с множествами, оператор '|' означает как бы объединение: узел входит в объединение множеств, если он входит хотя бы в одно из объединяемых множеств. Но, конечно же, и здесь упрощенный синтаксис играет свою роль для оптимизации — оперировать множествами, выбираемыми каждым из паттернов, было бы очень неэкономно.
Паттерны и их продукции описываются в спецификации самого языка XSLT, но мы приводим их в той же главе, что и выражения языка XPath, поскольку они очень похожи и имеют к тому же практические одинаковые семантические принципы. Паттерны используют также некоторые продукции языка XPath (такие, как NodeTest, Predicate и другие).
При нумерации EBNF-продукций паттернов мы будем нумеровать их с префиксом PT ([PT1], [PT2] и т.д.), чтобы не путать с продукциями других языков, рассматриваемых в этой книге.
Самая общая продукция паттерна называется Pattern и показывает, что образец соответствия может быть как одиночным паттерном, так и перечислением нескольких паттернов с разделяющими символами '|'. Продукция LocationPathPattern соответствует одиночному паттерну, показывая своим названием (англ. location path pattern — образец пути выборки) конструкционную близость к самим путям выборки.
[PT1] Pattern ::= LocationPathPattern
| Pattern '|' LocationPathPattern
Одиночный паттерн определяется следующим образом:
[PT2] LocationPathPattern
::= '/' RelativePathPattern?
| IdKeyPattern (('/' | '//') RelativePathPattern)?
| '//'? RelativePathPattern
Упростив эту продукцию, мы получим следующее правило:
LocationPathPattern ::= '/'
| RelativePathPattern
| '/' RelativePathPattern
| '//' RelativePathPattern
| IdKeyPattern
| IdKeyPattern '/' RelativePathPattern
| IdKeyPattern '//' RelativePathPattern
Если учесть, что нетерминал RelativePathPattern соответствует образцу относительного пути, можно легко заметить, как похожи первые четыре возможности в этом правиле на то, что мы разбирали при описании самих абсолютных и относительных путей.
□ Паттерну '/' соответствует только корневой узел.
□ Паттерн RelativePathPattern задает образец относительного пути. Например, паттерну a/b соответствуют элементы b, находящиеся в элементах a.
□ Паттерну '/' RelativePathPattern соответствуют узлы, которые соответствуют образцу относительного пути при отсчете от корневого узла. Например, паттерну /a/b соответствуют элементы b, находящиеся в элементах a, находящихся в корне документа.
□ Паттерну '//' RelativePathPattern соответствуют узлы, которые соответствуют относительному пути при отсчете от любого узла документа. Например, паттерну //a/b соответствуют любые элементы b, имеющие родителем элемент с именем а. Фактически, этот паттерн не отличается от паттерна a/b (единственное различие в том, что они могут иметь разные приоритеты).
Последние три случая в правиле LocationPathPattern относятся к таким механизмам XSLT, как адресация по уникальным идентификаторам и ключам.
В первой главе книги, когда мы описывали синтаксис и семантику языка разметки документов XML, мы коротко остановились на уникальных атрибутах — атрибутах, которые определяются типом ID и значения которых должны быть уникальны внутри документа. Как мы узнали, это позволяет более эффективно обращаться к элементам в документе.
