WEB. Справочная информация
XML и XSL
XPath - Что это такое
XPath (XML Path Language) - это язык запросов, используемый для навигации и поиска информации в XML-документах. Он позволяет точно указать путь к элементам, атрибутам и текстовым данным, которые нужно найти в структуре XML файлов и получить данные при необходимости.

XPath предлагает набор выражений, операторов и функций для указания конкретных путей обхода XML-деревьев и фильтрации данных с помощью различных критериев. Эти выражения состоят из элементов и операторов, которые можно комбинировать, чтобы получить нужные результаты.
Для чего нужен XPath
XPath используется для навигации и выбора элементов XML-документов. Он позволяет находить пути к элементам и их атрибутам, а также выполнять операции с ними: поиск, фильтрация, выборка.
Вот некоторые основные случаи использования XPath:
1) Поиск элементов: XPath позволяет найти определенные элементы в XML-документе с помощью путей и фильтров. Например, можно найти все элементы определенного типа или имеющие определенное значение атрибута.
2) Извлечение данных: XPath позволяет извлекать конкретные значения из XML-документа. Например, можно получить содержимое элемента или значение его атрибута.
3) Проверка условий: XPath позволяет задавать условия и проверять их в XML-документе. Например, можно проверить, что значение атрибута соответствует определенному критерию или что в XML-документе есть определенный элемент.
4) Навигация по структуре: XPath позволяет перемещаться по структуре XML-документа, находить конкретные узлы и выполнять с ними операции. Например, можно перейти к родительскому или дочернему элементу, выбрать первый или последний элемент, перейти на следующий или предыдущий элемент, а также совершать другие действия для исследования структуры XML-документа.
Использование XPath позволяет эффективно и удобно работать с XML-данными, особенно при обработке и анализе больших объемов информации.
Кому и зачем нужен Xpath
Если коротко — XPath нужен всем, кто работает с XML.
XPath широко используется в различных областях: программирование, веб-скрапинг, автоматизацию тестирования и анализ данных. Язык запросов позволяет легко и эффективно обращаться к нужным элементам в структурированных документах XML к нужным элементам, совершать какие то операции или получить необходимые данные.
Это лишь часть сценариев, в когда язык XPath может помочь — на самом деле, сценариев может быть намного больше.
Синтаксис XPath

Для выбора узлов в XML документе с помощью XPath используются выражения путей. Выборка узла производится следуя по заданному пути или по, так называемым, шагам.
Синтаксис XPath описывает правила для создания выражений, которые позволяют точно указать, какие элементы и атрибуты должны быть выбраны из XML-структуры. Точно указать, какой элемент выбрать нужно с помощью XPath можно при помощи:
1) Выбора узлов
2) Пути выбора элементов
3) Оси направления выбора
4) Функций
5) Предикатов
Выбор узлов

Чтобы выбрать нужный узел в XML документе, нужно обратиться к нему при помощи языка запросов XPath, указав путь к нужному элементу. Узел выбирается следуя по заданному пути.
Базовый синтаксис XPath для парсинга элементов:
1) * — Выбрать любой элемент.
2) [] — Найти конкретный элемент. Пример: //li[1]
имя_узла — Выбирает все узлы с указанным именем узла. Пример: div, p и т.д.
3) / — Ищет от корневого узла html
4) // — Ищет узлы в документе от текущего узла, который соответствует выбору, независимо от того, где они находятся
5) . — Ищет текущий узел
6) .. — Ищет родителя текущего узла
7) @ — Ищет нужный атрибут. Пример: //p[@value="2008"]
Абсолютные и относительные пути обращения к элементам

К конкретному элементу можно обратиться двумя способами:
1) Абсолютным. Абсолютный xpath начинается со слеша ( / ) и указывает на полный путь от корневого узла до целевого узла.
Пример выражения в XPath: /html/body/div[1]/h1
Конструкция означает: "выбрать первый элемент div, который находится по пути html > body > div и затем выбрать его дочерний элемент h1".
2) Относительным. Относительный путь начинается с двух слешей (//) и указывает на путь от любого узла, который соответствует определенным критериям, до целевого узла. Пример: //div[@id='main']
Конструкция означает: "выбрать любой элемент div, который имеет атрибут id со значением 'main'".
Общие функции XPath
Язык XPath имеет набор встроенных функций, которые позволяют осуществлять различные операции с XML-документами. Вот некоторые из основных функций XPath:
1) text() - возвращает текстовое содержимое элемента.
2) count() - возвращает количество элементов, соответствующих указанному выражению.
3) normalize-space() - удаляет лишние пробелы из строки и заменяет последовательности пробелов на одиночные пробелы.
4) starts-with(x,y) - проверяет, начинается ли строка с x-y.
5) contains(x,y) - проверяет, содержит ли строка x-y.
6) last() - возвращает последнюю позицию элемента в выборке.
7) position() - возвращает позицию текущего элемента в выборке.
8) name() - возвращает имя текущего элемента.
9) sum() - суммирует значения элементов выборки.
10) string() - преобразует узел в строку.
11) lower-case() - преобразует текст в нижний регистр.
12) @attribute - выбирает значение указанного атрибута.
13) concat() - объединяет две или более строки.
14) string-length() - возвращает длину строки.
15) substring() - возвращает подстроку из строки, начиная с указанной позиции.
Кроме этих основных функций, XPath также предоставляет более сложные функции, такие как функции математических операций (например, floor(), round(), sum()), функции работы с датами и временем и другие.
Оси XPath
Ось в XPath - это специальная концепция, которая используется для указания направления движения при поиске элементов в документе. Оси позволяют выбирать элементы, которые относятся к определенным отношениям с другими элементами в дереве XML или HTML.
В XPath есть несколько осей, которые можно использовать при создании выражений:
1) child::note — Выбирает все узлы note, которые являются прямыми потомками текущего узла
2) attribute::date — Выбирает атрибут date текущего узла
3) child::* — Выбирает всех прямых потомков текущего узла
4) attribute::* — Выбирает все атрибуты текущего узла
5) child::text() — Выбирает все текстовые узлы текущего узла
6) child::node() — Выбирает всех прямых потомков текущего узла
7) descendant::note — Выбирает всех потомков note текущего узла
8) ancestor::note — Выбирает всех предков note текущего узла
9) ancestor-or-self::note — Выбирает всех предков note текущего узла, а также сам текущий узел, если это узел note
10) child::*/child::heading — Выбирает всех прямых потомков прямых потомков (“внуков") heading текущего узла
11) last() — Выделяет последний элемент в дереве.
Предикаты (Коллекции)
Предикаты — конструкции, которые используются для фильтрации элементов и выбора конкретных элементов с помощью определенных условий.
Вот несколько примеров использования предикатов в XPath для :
1) //a — Выберите все элементы в документе
2) //a[@class='active'] — Выберите все элементы, у которых атрибут class равен "active"
3) //input[@type='checkbox'] — Выберите все элементы input, у которых атрибут type равен "checkbox"
4) //input[@type='text'] — Выберите все элементы input с атрибутом type равным "text"
5) //p[contains(text(), 'Lorem')] — Выберите все элементы, у которых текст содержит слово "Lorem"
6) //div[count(p) > 3] — Выберите все элементы, у которых количество дочерних элементов больше 3
7) //a[starts-with(@href, 'https://')] — Выберите все элементы, у которых атрибут href начинается с "https://"
8) //input[matches(@value, '^\d+$')] — Выберите все элементы input, у которых атрибут value содержит только цифры
9) //p[@value="01/2008"] — Выбирает все элементы p, у которых есть атрибут value со значением "01/2008"
10) //p[@value] — Выбирает все элементы p, у которых есть атрибут value
11) //p/text() — Выделит все текстовые узлы внутри всех элементов p
12) //div[not(p)] — Выберите все элементы, у которых не существует дочернего элемента
13) /div/p[position()<3] — Выбирает первые два элемента p, которые являются прямыми потомками элемента div
14) //tag[position()=1] — Выбирает первый элемент с тегом "tag"
15) /div/ul/li[1] — Выбирает первый элемент li, который является прямым потомком элемента ul в div
16) //li[a] — Выделяет элементы li, в которых есть элемент a
17) //li[last()] — Выделяет последний элемент li в документе
18) //a | //h2 - Выделить все элементы a и h2 с помощью оператора объединения |
19) //tag[@value > 9] — Получить узлы tag, value которых больше 9-ти.
20) //div[note[@value > 9]]/а — Получить только имена узлов, value которых больше 9-ти
21) //div[4]/h2[text() = "Текст"] — Выделит четвертый элемент div, h2 которого содержит слово: Текст
22) /div/note[last()] — Выбирает последний элемент note, который является прямым потомком элемента div
23) /div/note[last()-1] — Выбирает предпоследний элемент note, который является прямым потомком элемента div
24) //*[@id] — Выберите все элементы с атрибутом id
25) //div[contains(@class, 'content')]/p — Выберите все элементы, которые являются дочерними элементами с классом "content"
26) //img[contains(@src, 'logo')] — Выберите все элементы , у которых атрибут src содержит слово "logo"
27) //*[@href[contains(text(), '.pdf')]] — Выберите все элементы со значением атрибута href, оканчивающимся на .pdf
28) //*[@data-toggle='modal'] — Выберите все элементы с атрибутом data-toggle и значением "modal"
29) //tag[@attribute>5] — Выбирает все элементы с тегом "tag" и атрибутом "attribute", значение которого больше 5
30) //tag[@attribute="value"] — Выбирает все элементы с тегом "tag" и атрибутом "attribute" со значением "value"
Это лишь некоторые примеры запросов для получения данных. Существует много других комбинаций формирования запросов XPath.
Какие данные можно извлечь с сайта при помощи XPath и парсера

XPath и парсеры могут извлекать различные данные с веб-сайтов. Вот несколько типов данных, которые можно получить при помощи этих инструментов:
Количество товаров в категориях;
Описание, характеристики и цену товара;
Изображения;
Наличие и количество отзывов;
Количество просмотров статей;
Количество лайков у статей;
Почтовые ящики;
Хлебные крошки;
Страницы с видео;
Какие страницы, имеют сколько отзывов;
На каких страницах размещен определенный текстовый блок или нет;
Даты публикаций статей или товаров;
Рейтинги товаров или статей.
Это лишь некоторые примеры того, что можно извлечь с помощью XPath. Фактически, вы можете извлекать любые данные или атрибуты, доступные на веб-странице в зависимости от ее структуры и организации информации.
Формулы по извлечению HTML атрибутов которые будут полезны СЕОшникам
1) //@href — Извлечь все ссылки
2) //a[starts-with(@href,'mailto')]/@href — Получить ссылки, которые содержат “mailto” (email адрес)
3) //a[contains(@href,'tel:')]/@href — Получить все телефоны
4) //img/@src — Получить все URL адреса картинок
5) //img[contains(@class,'name-class')]/@src — Получить все URL адреса источников изображений с именем класса
6) //div[@class='class'] — Получить элементы в тегах с определенным классом, указанным в кавычках
7) count(//h2) — Посчитать количество элементов на странице
8) //*[@itemtype]/@itemtype — Извелчь какие типы микроразметок есть на странице
9) //*[@itemprop='price']/@content — Узнать значение поля свойства разметки
10) //iframe[contains(@src,'https://www.youtube.com/')]/@src — Найти ссылки на все видео с ютуба
11) //table[@class='product-table']//td/text() — Извлечь текст всех ячеек таблицы с классом "product-table"
12) //td[contains(text(),'Weight')]/following-sibling::td — Извлечение данных из ячеек таблиц
13) contains(//meta[@name='description']/@content, 'таргетированное-ключевое-слово') — Проверяет наличие ключевого слова в мета теге
14) //link[@rel=’amphtml’]/@href — Получить URL-адрес AMP
15) //form[*]/input[@type='text']/@name — Имена всех текстовых полей внутри форм
Это далеко не весь список, чего можно достать с сайта конкурента. Более того, в конкретном случае, синтаксис будет разный. Составить формулу можно при помощи расширения XPath Helper или нажав правой кнопкой на html элементе и выбрать скопировать XPath
Как извлечь данные при помощи XPath со страницы
Для извлечения данных со страниц, я использую расширение "XPath Helper".
1) Установите XPath Helper для браузера Google Chrome https://chrome.google.com/webstore/detail/xpath-helper/hgimnogjllphhhkhlmebbmlgjoejdpjl
2) После установки, обновите страницу или откройте новую вкладку и перейдите на любую веб-страницу.
3) Нажмите Ctrl-Shift-X (или Command-Shift-X в OS X) или нажмите кнопку XPath Helper на панели инструментов, чтобы открыть консоль XPath Helper.
3) Удерживая нажатой клавишу Shift, наведите указатель мыши на элементы на странице. Поле запроса будет постоянно обновляться, чтобы отображать запрос XPath для элемента под указателем мыши, а в окне результатов будут отображаться результаты для текущего запроса.
4) При желании отредактируйте XPath-запрос прямо в консоли. В окне результатов немедленно отразятся ваши изменения.
5) Повторите шаг (3), чтобы закрыть консоль.
Если консоль вам мешает, удерживайте нажатой клавишу Shift, а затем наведите на нее указатель мыши; он переместится на противоположную сторону страницы.
XPath. Основы построения запросов
Что же представляет из себя xpath-запрос?
XPath (XML Path Language) — язык запросов к элементам XML или XHTML документа. XML имеет древовидную структуру. В документе всегда имеется корневой элемент. У элемента дерева всегда существуют предки (исключение — корневой элемент, у которого предков нет) и могут существовать потомки. Каждый элемент дерева находится на определенном уровне вложенности. У элементов на одном уровне бывают предыдущие и следующие за ним элементы. Строка XPath — это фактически путь к элементу в дереве, где каждый уровень разделяется косой чертой «/». В результате обработки выражения XPath получается объект, который может быть:
набор узлов (node-set) — неупорядоченный набор узлов без дубликатов
булево значение (boolean) — true или false
число (number) — число с плавающей точкой
строка (string) — последовательность UCS символов
Небольшой примерчик для старта:
Результатом выполнения следующего XPath запроса будет узел <span>:
/html/body/*/span
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
Следующий запрос вернет несколько элементов (div#first и div#second):
/html/body/div
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div> <div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
* — обозначает любое имя или набор символов
/ — определяет уровень дерева
Если в запросе первым символом стоит «/» , то путь адресации считается абсолютным (то есть от корня документа). Корень документа всегда является контекстом по умолчанию. Контекст — это текущий полученный узел или набор узлов, относительно которых рассчитывается следующий шаг.
Оси
Оси это основа запросов XPath и их обязательная часть.
ancestor:: — возвращает множество предков.
ancestor-or-self:: — возвращает множество предков и текущий элемент.
attribute:: — возвращает множество атрибутов текущего элемента.
child:: — возвращает множество потомков на один уровень ниже.
descendant:: — возвращает полное множество потомков.
descendant-or-self:: — возвращает полное множество потомков и текущий элемент.
following:: — возвращает необработанное множество, ниже текущего элемента.
following-sibling:: — возвращает множество элементов на том же уровне, следующих за текущим.
namespace:: — возвращает множество имеющее пространство имён (то есть присутствует атрибут xmlns).
parent:: — возвращает предка на один уровень назад.
preceding:: — возвращает множество обработанных элементов исключая множество предков.
preceding-sibling:: — возвращает множество элементов на том же уровне, предшествующих текущему.
self:: — возвращает текущий элемент.
Для наиболее часто используемых осей существуют сокращения:
attribute:: — можно заменить на «@»
child:: — часто просто опускают
descendant:: — можно заменить на «.//»
parent:: — можно заменить на «..»
self:: — можно заменить на «.»
Для приведенного выше примера
/html/body/*/span
полный синтаксис будет иметь вид
/child::html/child::body/child::*/child::span
Чаще xpath-запрос начинают с «.//» или «//», это делает путь к элементу относительным. Символы ".//" в начале запроса возвращают полное множество потомков, которые являются дочерними для корня документа, т.е. все элементы на текущей странице. В данном случае точку в начале запроса можно опустить, потому что корневой элемент уже является контекстом.
Первый пример можно переписать так:
.//div/span
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
В то время как следующий xpath-запрос вернет оба элемента span:
.//span
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
Важную роль в построение запросов играют предикаты — это необязательная часть, заключаемая в квадратные скобки, в которой могут содержаться оси, условия проверки, функции и операторы. В ходе обработки предиката из полученного на шаге набора узлов исключаются узлы, не прошедшие условие проверки. Например, найдем элемент span, находящийся внутри любого элемента с id = «first»
.//*[@id="first"]/span
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
Примеры использования осей при построении запросов:
1. following-sibling::
.//*[@id="first"]/following-sibling::span
или
.//*[@id="second"]/following-sibling::*[1]
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
2. parent::
.//span[1]/..
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>Математика и XSLT
<xsl:template match="numbers">
A. 4 + 3.2 = <xsl:value-of select="x + y"/>
B. 3.2 - 4 = <xsl:value-of select="y - x"/>
C. 4 * 3.2 = <xsl:value-of select="x * y"/>
D. 11/3.2 = <xsl:value-of select="z div y"/>
E. 4 + 3.2 * 11 = <xsl:value-of select="x+y*z"/>
F. (4 + 3.2) * 11 = <xsl:value-of select="(x+y)*z"/>
G. 11 mod 4 = <xsl:value-of select="z mod x"/>
H. 4 + 3.2 + 11 = <xsl:value-of select="sum(*)"/>
I. floor(3.2) = <xsl:value-of select="floor(y)"/>
J. ceiling(3.2) = <xsl:value-of select="ceiling(y)"/>
K. round(3.2) = <xsl:value-of select="round(y)"/>
L. 11 + count(*) = <xsl:value-of select="11+count(*)"/>
M. 3.2 + string-length("3.2") =
<xsl:value-of select="y + string-length(y)"/>
N. 11 + "hello" = <xsl:value-of select="z + 'hello'"/>
</xsl:template>СТРОКИ
string(object object1)
starts-with(string string1, string string2)
contains(string string1, string string2)
substring(string string1, number offset number length)
length
offset
substring-before(string string1, string string2)
string1
string2
substring-after(string string1, string string2)
string1
string2
string-length(string string1)
string1
normalize-space(string string1)
string1
translate(string string1, string string2, string string3)
string1
string2
string3
concat(string string1, string string2, ...)
format-number(number number1, string string2, string string3)
number1
string2
string3
text()[starts-with(., 'Е')]
Удаление заданных символов из строки
Задача
Требуется убрать из строки некоторые символы (например, пробельные).
Решение
XSLT 1.0
Воспользуйтесь функцией translate() с пустой строкой замены. Например, следующий код удаляет из строки все пробельные символы:
translate($input, " 	

", "")
Применение translate оправдано и в XSLT 2.0, так как обычно эта функция работает быстрее всего. Но некоторые задачи такого рода более естественно решаются с помощью регулярных выражений и новой функции replace():
(: \s соответствует любому пробельному символу
replace($input, "\s", "")
Обсуждение
translate() – довольно гибкая функция, которая часто применяется для компенсации отсутствующих в XSLT 1.0 средств работы со строками. Здесь мы воспользовались тем фактом, что translate() не копирует те символы входной строки, которые есть в строке from, но отсутствуют в строке to.
Функцию translate() можно использовать также для удаления из строки всех символов, кроме заданных. Например, следующий код удаляет из исходной строки все символы, кроме цифр:
translate($string, translate($string, '0123456789', ''), '')
Внутренний вызов translate() удаляет все интересующие нас символы (в данном случае цифры), чтобы получить параметр from для внешнего вызова, который удалит из исходной строки все символы, кроме цифр.
Иногда нужно удалять не все пробелы, а только находящиеся в начале и в конце строки, а также оставлять из нескольких подряд идущих пробелов в середине только один. В XPath для этой цели есть встроенная функция normalize-space(). А если нужно решить ту же задачу для символа, отличного от пробела, то можно воспользоваться таким кодом (в данном случае мы нормализуем вхождения символа C):
translate(normalize-space(translate($input,"C "," C")),"C "," C")
Однако это преобразование будет работать неправильно, если входная строка содержит другие символы пропуска, то есть знаки табуляции (#x9), конца строки (#xA) и перевода каретки (#xD). Причина в том, что это выражение переставляет местами пробел и нормализуемый символ, затем нормализует пробелы и выполняет обратную перестановку. Если после первого преобразования остается символ пропуска, отличный от пробела, то он также нормализуется, хотя вы, возможно, этого и не хотели. Впрочем, нормализация чего-либо, кроме пробелов, встречается редко. Ниже показано, как можно удалить лишние символы -:
<xsl:template match="/">
<xsl:variable name="input" select=" ‘-this -is- the way we normalize
non-whitespace-‘ "/>
<xsl:value-of select="translate(normalize-space(
translate($input,’- "," -‘)),’- "," -‘)"/>
Более универсальный способ удаления ненужных символов дает встроенная в XSLT 2.0 функция replace(), основанная на аппарате регулярных выражений. Ниже мы с помощью replace() нормализуем отличный от пробела символ без особых случаев, возникающих в решении для XSLT 1.0:
<xsl:template match="/">
<xsl:variable name="input" select=" ‘-this -is- the way we normalize non-whitespace-‘ "/> <xsl:value-of selec"="replace(replace($input,’ —+’,’-‘),’Л-+|-+$’,”)"/>
</xsl:template>
Здесь функция replace() вызывается дважды. Внутренний вызов заменяет все соседние вхождения символа одним, а внешний удаляет начальные и конечные символы.
[x] Удаляем из строки все символы, кроме цифр:
<xsl:for-each select="modifications/shop_item">
<xsl:sort order="ascending" select="."/>
<li><xsl:value-of select="translate(name, translate(name, '0123456789', ''), '')" /></li>
</xsl:for-each>Функции XPath для работы со строками
Функция round()
Синтаксис
-
Если дробная часть числа равна 0.5, то функция вернет ближайшее большее целое.
-
Если аргумент является не-числом (NaN), то результат также будет NaN.
-
Если аргумент является положительной или отрицательной бесконечностью, то результатом будет тоже положительная или отрицательная бесконечность, то есть аргумент не изменится.
-
Если аргумент является положительным или отрицательным нулем, результатом будет также положительный или отрицательный нуль, то есть аргумент не изменится.
-
Если аргумент меньше нуля, но больше или равен — 0.5, результатом будет отрицательный нуль.
Элемент <xsl:number> - нумерация
Синтаксис
XSLT 1.0
<xsl:number
level = "single | multiple | any"
count = "паттерн"
from = "паттерн"
value = "выражение"
format = "строка"
lang = "токен"
letter-value = "alphabetic | traditional"
grouping-separator = "символ"
grouping-size = "число" />
Атрибуты
-
level — необязательный атрибут, указывает, на каких уровнях дерева следует искать нумеруемые узлы.
-
count — необязательный атрибут, указывает, какие именно узлы следует считать при вычислении номера.
-
from — необязательный атрибут, указывает, в какой части документа будет производиться нумерация.
-
value — необязательный атрибут, задает выражения, которые следует использовать для вычисления значения номера.
-
format — необязательный атрибут, определяет, как номер будет форматироваться в строку.
-
lang — необязательный атрибут, задает языковой контекст нумерации.
-
letter-value — необязательный атрибут, определяет параметры буквенных методов нумерации.
-
grouping-separator — необязательный атрибут, задает символ, разделяющий группы цифр в номере.
-
grouping-size — необязательный атрибут, определяет количество цифр в одной группе.
XSLT 2.0
<xsl:number
value = "expression"
select = "expression"
level = "single | multiple | any"
count = "pattern"
from = "pattern"
format = "string"
lang = "nmtoken"
letter-value = "alphabetic | traditional"
ordinal = "string"
grouping-separator = "char"
grouping-size = "number" />
Атрибуты
-
count — необязательный атрибут, содержит шаблон XPath, определяющий, что именно должно подсчитываться. Если атрибут count не указан, подсчитываются узлы с таким же именем, как у текущего узла.
-
level — необязательный атрибут, определяет, какие уровни исходного дерева должны учитываться при нумерации элементов. Для него определены три допустимых значения: single, multiple и any. single — нумерация ведется только на одном уровне. Процессор XSLT переходит к первому узлу оси ancestor-or-self, соответствующему атрибуту count, а затем нумерует этот узел вместе со всеми предшествующими одноуровневыми узлами, соответствующими также атрибуту count. Значение используется по умолчанию. multiple — нумерация на нескольких уровнях. Процессор XSLT перебирает всех предков текущего узла вместе с самим текущим узлом и выбирает все узлы, соответствующие атрибуту count. any — включает всех предков текущего узла (по аналогии с level="multiple"), а также все элементы оси preceding. Во всех этих случаях при использовании атрибута from анализируются только те предки, которые являются потомками ближайшего предка, соответствующего атрибуту from. Иначе говоря, с атрибутом from="h1" для нумерации анализируются только те узлы, которые находятся под ближайшим элементом <h1>.
-
from — необязательный атрибут, содержит шаблон XPath, определяющий начальную точку нумерации. Например, from="h1" означает, что нумерация должна начаться с предыдущего элемента <h1>.
-
value — необязательный атрибут, выражение, преобразуемое в число. С помощью этого атрибута можно быстро отформатировать число; элемент <xsl:number value="7" format="i:"/> возвращает строку "vii:". При заданном атрибуте value атрибуты count, level, from и select использоваться не могут.
-
format — необязательный атрибут, определяет формат генерируемой нумерации:
-
format="1" Нумерация вида 1 2 3 4 5 6 7 8 9 10 11 ….
-
format="01" Нумерация вида 01 02 03 04 … 09 10 11 … 99 100 101 ….
-
format="a" Нумерация вида a b c d e f … x y z aa ab ac ….
-
format="A" Нумерация вида A B C D E F … X Y Z AA AB AC ….
-
format="i" Нумерация вида i ii iii iv v vi vii viii ix x ….
-
format="I" Нумерация вида I II III IV V VI VII VIII IX X ….
-
format="w" Нумерация в виде словарной последовательности. С атрибутами ordinal="yes" и lang="en"нумерация форматируется в виде first second third fourth .... Если атрибут ordinal="yes" не задан, создается последовательность вида one two three four .... Если заданная комбинация format, ordinal и lang не поддерживается, процессор XSLT обязан прибегнуть к последнему средству – отформатировать числа в виде 1 2 3 4 5 ....
-
format="Ww" Нумерация в виде словарной последовательности. С атрибутами ordinal="yes" и lang="en"нумерация форматируется в виде First Second Third Fourth .... Если атрибут ordinal="yes" не задан, создается последовательность вида One Two Three Four .... Если заданная комбинация format, ordinal и lang не поддерживается, процессор XSLT обязан прибегнуть к последнему средству – отформатировать числа в виде 1 2 3 4 5 ....
-
format="остальные обозначения" Зависит от используемого процессора XSLT. В спецификации XSLT перечислено несколько других схем нумерации (например, format="�E51;" для тайского языка); за информацией о поддерживаемых форматах обращайтесь к документации процессора XSLT. Если процессор XSLT не поддерживает запрашиваемую схему нумерации, спецификация XSLT требует, чтобы по умолчанию использовался атрибут format="1".
-
lang — необязательный атрибут, определяет язык, алфавит которого должен использоваться при нумерации. Разные процессоры XSLT поддерживают разные языки; за дополнительной информацией обращайтесь к документации своего процессора XSLT.
-
letter-value — необязательный атрибут, имеет допустимые значения alphabetic и traditional. Во многих языках поддерживаются две словарные схемы нумерации; в одной числовые значения представляются в алфавитной последовательности, а в другой используется традиция, специфическая для данного языка. (Одним из примеров нумерации, не использующей алфавитный порядок, служит римская нумерация.) По умолчанию используется значение alphabetic.
-
grouping-separator — необязательный атрибут, определяет символ, используемый для разделения групп разрядов в сгенерированном числе. По умолчанию используется запятая (,).
-
grouping-size — необязательный атрибут, определяет количество цифр в группах; по умолчанию используется значение 3.
-
ordinal — необязательный атрибут, управляет использованием порядковых числительных; допустимые значения: yes и no. Атрибуты ordinal, format и lang работают совместно. Например, комбинация ordinal="yes", format="1" и lang="en" создает последовательность 1st 2nd 3rd 4th. С атрибутом format="w"нумерация принимает вид first second third fourth, а с атрибутом format="Ww" – First Second Third Fourth. Если комбинация ordinal, format и lang не поддерживается, процессор XSLT обязан сгенерировать обычную числовую нумерацию (1 2 3 4). За информацией о комбинациях языков и форматов, поддерживаемых с атрибутом ordinal, обращайтесь к документации своего процессора XSLT.
-
select — необязательный атрибут, выбирает нумеруемый узел. Атрибут позволяет выбрать узел, отличный от контекстного узла.
XSLT 3.0
<xsl:number
value? = expression
select? = expression
level? = "single" | "multiple" | "any"
count? = pattern
from? = pattern
format? = { string }
lang? = { language }
letter-value? = { "alphabetic" | "traditional" }
ordinal? = { string }
start-at? = { integer }
grouping-separator? = { char }
grouping-size? = { integer } />
Описание и примеры
-
Для того чтобы получить порядковый номер текущего узла в обрабатываемом множестве, можно использовать функцию position. Обратим внимание, что это будет позиция узла в обрабатываемом в данный момент множестве, а не в дереве исходящего документа.
-
Функция count(preceding-sibling::*)+1 возвращает порядковый номер текущего элемента среди других элементов его родителя, иначе говоря, среди его братьев. Путь выборки preceding-sibling::* выбирает множество братских элементов, предшествующих текущему узлу, а функция count вычисляет их количество. Таким образом, значение count(preceding-sibling::*)+1 будет равно 1 для первого элемента (поскольку ему другие элементы не предшествуют), 2 — для второго (ему предшествует один элемент) и так далее.
-
Для того чтобы учитывать при подсчете только определенные элементы, можно переписать предыдущее выражение в чуть более строгом виде. Например, выражение, считающее только элементы chapter, будет задаваться следующим образом: (preceding-sibling::chapter) +1.
-
Глубина текущего узла от корня дерева может быть вычислена выражением count(ancestor-or-self::node()). Это выражение будет возвращать 1 для корневого узла, 2 для элемента документа и так далее.
<xsl:value-of select="count(preceding-sibling::chapter)+1" />
Вычисление номеров
<doc>
<chapter title="First chapter">
<section title="First section">
<para>paragraph 1</para>
<para>paragraph 2</para>
<para>paragraph 3</para>
</section>
<section title="Second section">
<para>paragraph 4</para>
<para>paragraph 5</para>
</section>
</chapter>
<chapter title="Second chapter">
<section title="Third section">
<para>paragraph 6</para>
<para>paragraph 7</para>
<para>paragraph 8</para>
<para>paragraph 9</para>
</section>
<section title="Forth section">
<para>paragraph 10</para>
<para>paragraph 11</para>
<para>paragraph 12</para>
</section>
<section title="Fifth section">
<para>paragraph 13</para>
<para>paragraph 14</para>
<para>paragraph 15</para>
<para>paragraph 16</para>
</section>
</chapter>
<chapter title="Third chapter">
<section title="Sixth section">
<para>paragraph 17</para>
<para>paragraph 18</para>
</section>
</chapter></doc>
<xsl:template match="chapter">
<xsl:value-of select="position()"/>
<xsl:text>. </xsl:text>
<xsl:value-of select="@title"/>
<xsl:text> </xsl:text></xsl:template>
<xsl:template match="chapter">
<xsl:number value="position()" format="1. "/>
<xsl:value-of select="@title"/>
<xsl:text> </xsl:text></xsl:template>
Метод single
-
На первом шаге находится узел уровня дерева. Узлом уровня будет узел, удовлетворяющий следующим условиям:
-
он является первым (то есть ближайшим к текущему) узлом, принадлежащим оси ancestor-or-self текущего узла;
-
он удовлетворяет паттерну count;
-
он принадлежит области подсчета;
-
если такого узла нет, список номеров будет пустым.
-
На втором шаге вычисляется номер узла уровня. Этот номер будет равен 1 плюс количество узлов, принадлежащих оси навигации preceding-sibling и удовлетворяющих паттерну count.
<xsl:template match="para">
<xsl:number format=" 1." count="section"/>
<xsl:number format="1." count="para"/>
<xsl:value-of select="."/>
<xsl:text> </xsl:text></xsl:template>
<xsl:number format=" 1." count="section"/>
<xsl:number format="1." count="para"/>
Метод multiple
-
На первом этапе выбирается множество нумеруемых узлов, удовлетворяющее следующим условиям:
-
его узлы принадлежат оси навигации ancestor-or-self текущего узла;
-
его узлы соответствуют паттерну count;
-
его узлы принадлежат области подсчета.
-
На втором этапе для каждого узла нумеруемого множества вычисляется позиция среди собратьев. Позиция нумеруемого узла будет равна 1 плюс количество узлов, принадлежащих его оси навигации preceding-sibling и соответствующих паттерну count.
<xsl:number format=" 1.1." level="multiple" count="doc|chapter|para" from="doc"/>
Метод any
<xsl:number format=" 1." level="any" count="*" from="chapter[2]"/>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="doc">
<xsl:text>Resulting document </xsl:text>
<xsl:text>================== </xsl:text>
<xsl:apply-templates select="chapter"/>
</xsl:template>
<xsl:template match="chapter">
<xsl:number format="1. "/>
<xsl:value-of select="@title"/>
<xsl:text> </xsl:text>
<xsl:apply-templates select="section"/>
</xsl:template>
<xsl:template match="section">
<xsl:number format=" 1.1 " level="multiple" count="chapter|section"/>
<xsl:value-of select="@title"/>
<xsl:text> </xsl:text>
<xsl:apply-templates select="para"/>
</xsl:template>
<xsl:template match="para">
<xsl:number format=" a) " level="any" count="para"/>
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:template></xsl:stylesheet>
-
Элементы chapter будут нумероваться в соответствии со своей позицией среди других элементов chapter того же уровня.
-
Элементы section будут нумероваться при помощи многоуровневой нумерации — номер будет состоять из номера элемента chapter и номера самого элемента section.
-
Элементы para будут нумероваться исходя из своей позиции среди всех остальных элементов para вне зависимости от того, на каких уровнях в документе они находятся.
Форматирование номеров
-
Список номеров будет пустым, если в области нумерации не оказалось нумеруемых узлов.
-
Список номеров будет состоять не более чем из одного числа при использовании методов single и any.
-
Список номеров будет состоять из нуля или более чисел (по одному на каждый уровень нумерации) при использовании метода multiple.
<xsl:number format=" 1.1." level="multiple" count="doc|chapter|para" from="doc"/>
-
разделяющей последовательности "_____", которая будет скопирована, как есть;
-
числа 2, которое получается в результате форматирования номера 2 форматирующим токеном “1”;
-
разделяющего символа “.”;
-
числа 2, которое получается в результате форматирования номера 2 вторым форматирующим токеном “1”;
-
разделяющего символа “.”.
Таблица 8.3. Форматирующие токены
|
ТОКЕН
|
ОПИСАНИЕ
|
ПРИМЕРЫ
|
|
|
ТОКЕН
|
ПРЕОБРАЗОВАНИЕ
|
||
|
1
|
Форматирует номер в виде строкового представления десятичного числа
|
1
|
1 ? ‘1’
|
|
1
|
2 ? ‘2’
|
||
|
1
|
10 ? ‘10’
|
||
|
1
|
999 ? ‘999’
|
||
|
1
|
1000 ? ‘1000’
|
||
|
0…01
|
Форматирует номер в виде строкового представления десятичного числа; если получившая строка короче токена, она дополняется предшествующими нулями
|
0001
|
1 ? ‘0001’
|
|
001
|
2 ? ‘002’
|
||
|
001
|
10 ? ‘010’
|
||
|
01
|
999 ? ‘999’
|
||
|
00001
|
1000 ? ‘01000’
|
||
|
A
|
Форматирует номер в виде последовательности заглавных букв латинского алфавита
|
A
|
1 ? ‘A’
|
|
A
|
2 ? ‘B’
|
||
|
A
|
10 ? ‘J’
|
||
|
A
|
27 ? ‘AA’
|
||
|
A
|
999 ? ‘ALK’
|
||
|
A
|
1000 ? ‘ALL’
|
||
|
a
|
Форматирует номер в виде последовательности строчных букв латинского алфавита
|
a
|
1 ? ‘a’
|
|
a
|
2 ? ‘b’
|
||
|
a
|
10 ? ‘j’
|
||
|
a
|
27 ? ‘aa’
|
||
|
a
|
999 ? ‘alk’
|
||
|
a
|
1000 ? ‘all’
|
||
|
I
|
Форматирует номер заглавными римскими цифрами
|
I
|
1 ? ‘I’
|
|
I
|
2 ? ‘II’
|
||
|
I
|
10 ? ‘X’
|
||
|
I
|
27 ? ‘XXVII’
|
||
|
I
|
999 ? ‘IM’
|
||
|
I
|
1000 ? ‘M’
|
||
|
i
|
Форматирует номер строчными римскими цифрами
|
i
|
1 ? ‘i’
|
|
i
|
2 ? ‘ii’
|
||
|
i
|
10 ? ‘x’
|
||
|
i
|
27 ? ‘xxvii’
|
||
|
i
|
999 ? ‘im’
|
||
|
i
|
1000 ? ‘m’
|
||
|
Другой
|
Форматирует номер k как k-й член последовательности, начинающейся этим токеном. Если нумерация таким токеном не поддерживается, вместо него используется токен 1.
|
Не поддерживающийся токен
|
1 ? ‘1’
|
|
b
|
10 ? ‘k’
|
||
|
Б
|
2 ? ‘В’
|
||
|
Б
|
27 ? ‘Ы’
|
||
|
?
|
999 ? ‘???’
|
||
|
?
|
1000 ? ‘???’
|
||
<xsl:number format="1.&#х430;" level="multiple" count="chapter|section" from="doc"/>
<xsl:number format="i" ... />
<xsl:number format="[00000001]" grouping-separator="." grouping-size="2"/>
<xsl:template match="section">
<xsl:number format="{../@format}-1 " level="multiple" count="chapter|section"/>
<xsl:value-of select="@title"/></xsl:template>
<doc>
<chapter format="I" title="First Chapter">
<section title="First Section"/>
<section title="Second Section"/>
<section title="Third Section"/>
</chapter></doc>
Пример для XSLT 2.0
<?xml version="1.0"?><!-- items-to-number.xml --><book>
<chapter>
<title>Alfa Romeo</title>
<sect1>
<title>Bentley</title>
</sect1>
<sect1>
<title>Chevrolet</title>
<sect2>
<title>Dodge</title>
<sect3>
<title>Eagle</title>
</sect3>
</sect2>
</sect1>
</chapter>
<chapter>
<title>Ford</title>
<sect1>
<title>GMC</title>
<sect2>
<title>Honda</title>
<sect3><title>Isuzu</title></sect3>
<sect3><title>Javelin</title></sect3>
<sect3><title>K-Car</title></sect3>
<sect3><title>Lincoln</title></sect3>
</sect2>
<sect2><title>Mercedes</title></sect2>
<sect2>
<title>Nash</title>
<sect3><title>Opel</title></sect3>
<sect3><title>Pontiac</title></sect3>
</sect2>
<sect2>
<title>Quantum</title>
<sect3><title>Rambler</title></sect3>
<sect3><title>Studebaker</title></sect3>
</sect2>
</sect1>
<sect1><title>Toyota</title></sect1>
</chapter></book>
<?xml version="1.0"?><!-- number8.xsl --><xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="book">
<xsl:for-each select=".//sect2">
<xsl:number level="any" count="chapter|sect1|sect2|sect3" format="Ww - " ordinal="yes"/>
<xsl:value-of select="title"/>
<xsl:text></xsl:text>
</xsl:for-each>
</xsl:template></xsl:stylesheet>
<?xml version="1.0"?><!-- number9.xsl --><xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="book">
<xsl:for-each select=".//sect2">
<xsl:number level="any" count="chapter|sect1|sect2|sect3" format="w - " lang="de"/>
<xsl:value-of select="title"/>
<xsl:text></xsl:text>
</xsl:for-each>
</xsl:template></xsl:stylesheet>
<?xml version="1.0"?><!-- number10.xsl --><xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="book">
<xsl:for-each select=".//sect2">
<xsl:number level="any" count="chapter|sect1|sect2|sect3" format="w - " lang="pl"/>
<xsl:value-of select="title"/>
<xsl:text></xsl:text>
</xsl:for-each>
</xsl:template></xsl:stylesheet>
<?xml version="1.0"?><!-- number11.xsl --><xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="book">
<html>
<head>
<title>Thai numbering</title>
</head>
<body style="font-family: sans-serif;">
<h1>Thai numbering</h1>
<p style="font-size: 150%">
<xsl:for-each select=".//sect2">
<xsl:number level="any" count="sect2" format="๑ "/>
<xsl:value-of select="title"/>
<br/>
</xsl:for-each>
</p>
</body>
</html>
</xsl:template></xsl:stylesheet>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Thai numbering</title>
</head>
<body style="font-family: sans-serif;">
<h1>Thai numbering</h1>
<p style="font-size: 150%">๑ Dodge<br>
๒ Honda<br>๓ Mercedes<br>
๔ Nash<br>๕ Quantum<br></p>
</body></html>
Элемент <xsl:sort> - сортировка
Синтаксис
XSLT 1.0
<xsl:sort
select = "string-expression"
lang = "nmtoken"
data-type = "text | number | qname-but-not-ncname"
order = "ascending | descending"
case-order = "upper-first | lower-first" />
<xsl:apply-templates select="informationsystem_item">
<xsl:sort
select = "sorting"
data-type = "number"
order = "ascending"
/>
</xsl:apply-templates>
Атрибуты
-
select — обязательный атрибут, значением которого является выражение, называемое также ключевым выражением. Это выражение вычисляется для каждого узла обрабатываемого множества, преобразуется в строку и затем используется как значение ключа при сортировке. По умолчанию значением этого атрибута является ".", что означает, что в качестве значения ключа для каждого узла используется его строковое значение.
-
order — необязательный атрибут, определяет порядок, в котором узлы должны сортироваться по своим ключам. Этот атрибут может принимать только два значения — "ascending", указывающее на восходящий порядок сортировки, и "descending", указывающее на нисходящий порядок. Значением по умолчанию является "ascending", то есть восходящий порядок.
-
lang — необязательный атрибут, определяет язык ключей сортировки. Дело в том, что в разных языках символы алфавита могут иметь различный порядок, что, соответственно, должно учитываться при сортировке. Атрибут lang в XSLT может иметь те же самые значения, что и атрибут xml:lang (например: "en", "en-us", "ru" и т. д.). Если значение этого атрибута не определено, процессор может либо определять язык исходя из параметров системы, либо сортировать строки исходя из порядка кодов символов Unicode.
-
data-type — необязательный атрибут, определяет тип данных, который несут строковые значения ключей.
-
"text" — ключи должны быть отсортированы в лексикографическом порядке исходя из языка, определенного атрибутом lang или параметрами системы. Это значение используется по умолчанию;
-
"number" — ключи должны сравниваться в численном виде. Если строковое значение ключа не является числом, оно будет преобразовано к не-числу (NaN), и, поскольку нечисловые значения неупорядочены, соответствующий узел может появиться в отсортированном множестве где угодно;
-
"имя" — в целях расширяемости XSLT также позволяет указывать в качестве типа данных произвольное имя. В этом случае реализация сортировки полностью зависит от процессора.
-
case-order — необязательный атрибут, указывает на порядок сортировки символов разных регистров. Значениями этого атрибута могут быть "upper-first", что означает, что заглавные символы должны идти первыми, или "lower-first", что означает, что первыми должны быть строчные символы. К примеру, строки "ночь", "Улица", "фонарь", "Аптека", "НОЧЬ", "Фонарь" при использовании case-order="upper-first" будут иметь порядок "Аптека", "НОЧЬ", "ночь", "Фонарь", "фонарь", "улица". При использовании case-order="lower-first" те же строки будут идти в порядке "Аптека", "ночь", "НОЧЬ", "фонарь", "Фонарь", "улица". Значение case-order по умолчанию зависит от процессора и языка сортировки. В большинстве случаев заглавные буквы идут первыми.
XSLT 2.0 и XSLT 3.0
<xsl:sort
select? = expression
lang? = { nmtoken }
order? = { "ascending" | "descending" }
collation? = { uri }
stable? = { "yes" | "no" }
case-order? = { "upper-first" | "lower-first" }
data-type? = { "text" | "number" | qname-but-not-ncname }>
<!-- Content: sequence-constructor -->
</xsl:sort>
Описание и примеры
Пример
<list>
<person>
<name>William</name>
<surname>Gibson</surname>
</person>
<person>
<name>William</name>
<surname>Blake</surname>
</person>
<person>
<name>John</name>
<surname>Fowles</surname>
</person>
</list>
<xsl:template match="list">
<xsl:copy>
<xsl:for-each select="person">
<xsl:sort select="name" order="descending"/>
<xsl:sort select="surname"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<list>
<person>
<name>William</name>
<surname>Blake</surname>
</person>
<person>
<name>William</name>
<surname>Gibson</surname>
</person>
<person>
<name>John</name>
<surname>Fowles</surname>
</person>
</list>