Алексей Валиков - Технология XSLT
□ "html" — шаг выборки элементов html;
□ "/" — разделитель шагов выборки;
□ "head" — шаг выборки элементов head;
□ "/" — разделитель шагов выборки;
□ "title" — шаг выборки элементов title.
Поскольку каждый из шагов отсчитывается от результатов предыдущего, шаг "html" будет выбирать элементы html, являющиеся дочерними элементами корневого узла и так далее. Пошаговое вычисление этого пути можно описать следующим образом:
□ "/" — путь, который выбирает корневой узел;
□ "/html" — путь, который выбирает дочерние элементы html корневого узла;
□ "/html/head" — путь, который выбирает дочерние элементы head элементов html, находящихся в корне документа;
□ "/html/head/title" — путь, выбирающий дочерние элементы title субэлементов head элементов html, которые находятся в корне документа.
Можно заметить очевидную аналогию с файловыми системами: пути выборки очень похожи на пути в структуре каталогов. Между тем, пути выборки гораздо мощнее:
□ для каждого из шагов выборки можно указать направление, в котором он будет выбирать узлы в документе — например, дочерние узлы, узлы- потомки или, наоборот, узлы-предки или братские узлы;
□ выбор узлов может проводиться не только по имени, но также и по типу или принадлежности определенному пространству имен;
□ выбранное на каждом шаге множество может фильтроваться одним или более предикатом (в отфильтрованном множестве останутся только те из выбранных узлов, которые поочередно удовлетворяют каждому из логических условий-предикатов).
Пути выборки являются средством получения информации, содержащейся в обрабатываемых документах. Неважно, что они возвращают множества узлов, неявное преобразование типов позволяет спокойно записывать выражения вида:
data/a + data/b
Несмотря на то, что data/a и data/b являются множествами узлов, в арифметическом выражении они будут неявно преобразованы к численному типу. То же самое касается строкового и булевого типа.
Фильтрующие выражения
Фильтрующие выражения выполняют две основные задачи:
□ выбор из вычисленного множества узлов некоторого подмножества в соответствии с заданными логическими критериями-предикатами;
□ вычисление путей выборки относительно узлов фильтрованного множества.
ПримерыПредположим, что переменной nodeset присвоено некоторое множество узлов. Задачи типа "выбрать каждый второй узел этого множества" или "выбрать первый узел этого множества" или вообще, любой выбор узлов этого множества в соответствии с некоторыми заданными логическими критериями являются задачами фильтрации. Выражение $nodeset[1] выберет первый в порядке просмотра документа узел множества $nodeset; выражение $nodeset[position() mod 2 = 0] выберет четные узлы множества $nodeset. Здесь "[1]" и "[position() mod 2 = 0]" являются предикатами — логическими выражениями, которые фильтруют множество.
Фильтрующие выражения также позволяют вычислять пути выборки относительно узлов фильтруемых множеств.
Пример Листинг 3.22. Входящий документ<data>
<string>
<value>a</value>
<value>b</value>
<value>c</value>
</string>
<number>
<value>1</value>
<value>2</value>
<value>3</value>
</number>
</data>
Следующее преобразование демонстрирует использование относительных путей выборки в фильтрующих выражениях:
Листинг 3.23. Преобразование<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Тransform">
<xsl:template match="data">
<values>
<xsl:copy-of select="(string | number)/value"/>
</values>
</xsl:template>
</xsl:stylesheet>
Листинг 3.24. Входящий документ<values>
<value>a</value>
<value>b</value>
<value>c</value>
<value>1</value>
<value>2</value>
<value>3</value>
</values>
Элемент values выходящего документа содержит множество, являющееся результатом вычисления выражения (string | number)/value. Это будет множество элементов value, принадлежащих элементам string или number.
Объединение множеств
Единственная операция над множествами, которая определена в XSLT, — это операция объединения. Если $nodeset1 и $nodeset2 — два множества узлов, то результатом вычисления
$nodeset1 | $nodeset2
будет множество узлов, которые принадлежат хотя бы одному из этих множеств.
Следует сказать, что, поскольку никакой тип данных не может быть преобразован во множество узлов, операнды объединения сами всегда должны быть множествами. То есть, выражение вида:
'а' | body/a
не добавит текстовый узел "а" к множеству элементов а, принадлежащих элементу body — оно просто будет некорректным.
Арифметические операции
Четыре основные бинарные операции — "+", "-", "div", "mod" и пятая, унарная операция отрицания "-" обеспечивают в XSLT основные арифметические действия. Поскольку любой из типов данных может быть преобразован в численный тип, в качестве операндов арифметических операций можно использовать что угодно — например, вычитать из строки булевое выражение:
'0.5' - true() → -0.5
Следует осторожно обращаться со знаком "-". Имена элементов и атрибутов могут включать этот знак и поэтому выражение first-last будет воспринято не как разность значений элементов first и last, а как путь выборки элементов с именами "first-last". Для того чтобы избежать таких казусов, операторы всегда следует выделять пробелами:
first - last
Операции сравнения
В XSLT имеются следующие шесть операторов сравнения:
□ "=" — равно;
□ "!=" — не равно;
□ "<" меньше;
□ ">" больше;
□ "<=" меньше или равно (не больше);
□ ">=" больше или равно (не меньше).
Результат этих сравнений всегда имеет булевый тип, то есть сравнение может быть либо истинным, либо ложным. Несмотря на внешнюю очевидность функций этих операторов, наличие такого типа данных, как множество узлов, делает четкое определение сравнений довольно сложным. Мы приведем его так, как оно приведено в спецификации, снабдив подробными комментариями и примерами.
Операции сравнения определяются в спецификации в три этапа:
□ сначала сравнение, в котором участвуют множества узлов, определяется в терминах сравнения более простых типов данных;
□ затем для простых типов данных определяются равенство ("=") и неравенство ("!=");
□ наконец, для простых типов данных определяются сравнения "<", "<=", ">", ">=".
Сравнение, хотя бы один из операндов которого является множеством узлов, определяется следующим образом:
□ если один из операндов является множеством узлов, а второй имеет булевый тип, сравнение будет истинным тогда и только тогда, когда истинным будет результат сравнения множества узлов, преобразованного к булевому типу и самого булевого операнда;
□ если один из операндов является множеством узлов, а второй имеет численный тип, сравнение будет истинным тогда и только тогда, когда во множестве узлов найдется такой узел, что сравнение текстового значения этого узла, преобразованного к числу, и самого численного операнда будет истинным;
□ если один из операндов является множеством узлов, а второй имеет строковый тип, сравнение будет истинным тогда и только тогда, когда во множестве узлов найдется такой узел, что сравнение его текстового значения и самого строкового операнда будет истинным;
□ если оба операнда являются множествами узлов, их сравнение будет истинным тогда и только тогда, когда найдется узел в первом множестве и узел во втором множестве, такие, что их сравнение будет истинным.
Примеры выражений, которые мы будем приводить, будут использовать следующий входящий документ (листинг 3.25).
Листинг 3.25. Входящий документ<values>
<string>0.5</string>
<string>50%</string>