Функция расширения nodeset
Функция расширения nodeset
Одной из самых полезных функций расширения, которая, как правило, уже штатно реализована во многих процессорах (то есть, не требует дополнительного программирования) является функция nodeset. Эта функция позволяет в обход прямого запрета спецификации конвертировать результирующий фрагмент дерева во множество узлов.
Предположим, что мы создаем в переменной rtf результирующий фрагмент дерева следующего вида:
<xsl:variable name="rtf">
<item>1</item>
<item>2</item>
<item>3</item>
</xsl:variable>
При попытке вычислить выражение вида $rtf/item[2] процессор в соответствии со спецификацией должен вывести ошибку, поскольку в этом фильтрующем выражении (см. продукцию [XP20] FilterExpr) переменная rtf должна содержать множество узлов, а не фрагмент дерева.
Текущая спецификация языка XPath совершенно явно говорит о том, что ни один тип данных не может быть преобразован во множество узлов. Функция nodeset действует в обход этого запрещения: она принимает на вход результирующий фрагмент дерева и возвращает множество, состоящее из корневого узла этого фрагмента.
В разных процессорах эта функция имеет различный синтаксис: она может носить имя nodeset или node-set, или nodeSet, однако семантика ее во всех случаях одинакова:
nodeset nodeset(result-tree-fragment)
Функция принимает на вход единственный аргумент, являющийся фрагментом дерева и возвращает множество узлов, состоящее из его корня.
Пример
Предположим, что мы обрабатываем входящий документ, содержащий трехбуквенные коды языков.
Листинг 10.10. Входящий документ
<items>
<item>ENG</item>
<item>FRE</item>
<item>GER</item>
<item>GRE</item>
<item>ITA</item>
<item>NOR</item>
<item>POR</item>
<item>SPA</item>
</items>
Фрагмент шаблона, обрабатывающий этот список, может выглядеть следующим образом:
<select name="language">
<xsl:for-each select="items/item">
<option>
<xsl:value-of select="."/>
</option>
</xsl:for-each>
</select>
Если в преобразовании нам понадобится доопределить входящий список кодами RUS и UKR, не исправляя входящий документ, можно поступить следующим образом:
? создать в переменной фрагмент дерева, содержащий элементы item входящего документа плюс элементы item, доопределяющие этот список;
? преобразовать дерево в список узлов;
? обрабатывать список узлов точно так же, как мы бы обрабатывали сам входящий документ.
Преобразование, реализующее эти три шага, приведено ниже.
Листинг 10.11. Преобразование
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan"
exclude-result-prefixes="xalan">
<xsl:template match="items">
<!--
| Создаем переменную tree, содержащую элементы item
| входящего документа а также два дополнительных элемента
+-->
<xsl:variable name="tree">
<xsl:copy-of select="item"/>
<item>RUS</item>
<item>UKR</item>
</xsl:variable>
<!--
| Конвертируем переменную tree во множество узлов,
| результат присваиваем переменной items
+-->
<xsl:variable name="items" select="xalan:nodeset($tree)"/>
<!--
| Обрабатываем узлы $items/item точно так же,
| как мы обрабатывали бы узлы items/item
+-->
<select name="language">
<xsl:for-each select="$items/item">
<option>
<xsl:value-of select="."/>
</option>
</xsl:for-each>
</select>
</xsl:template>
</xsl:stylesheet>
Результат этого преобразования приведен на следующем листинге.
Листинг 10.12. Выходящий документ
<select name="language">
<option>ENG</option>
<option>FRE</option>
<option>GER</option>
<option>GRE</option>
<option>ITA</option>
<option>NOR</option>
<option>POR</option>
<option>SPA</option>
<option>USA</option>
<option>RUS</option>
<option>UKR</option>
</select>
Вне всякого сомнения, функция nodeset является одним из наиболее востребованных в XSLT расширений, ведь возможность не только создавать, но и манипулировать уже созданными древовидными структурами является чрезвычайно полезной.
В качестве одного из примеров применения функции nodeset можно привести реализацию с ее помощью многошаговых преобразований.
В качестве примера рассмотрим схему трансформации, изображенную на рис. 10.3, в которой документ А сначала нужно обработать преобразованием 1, затем полученный результат (документ В) обработать преобразованием 2. Конечным результатом цепочки преобразований в данном случае является документ С.
Рис. 10.3. Двухшаговое преобразование
При выполнении преобразования процессор применяет шаблоны ко множеству узлов входящего документа и выстраивает результирующее дерево. Таким образом, для того, чтобы повторно применить шаблоны к уже обработанному документу (читай: к полученному дереву), нужно просто иметь возможность преобразовывать дерево во множество узлов.
Пример
Представим себе два простых преобразования, first.xsl и second.xsl, первое из которых заменяет во входящем документе элементы а на элементы b, а второе — элементы b на элементы с.
Листинг 10.13. Преобразование first.xsl
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="a">
<b>
<xsl:apply-templates select="@*|node()"/>
</b>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Листинг 10.14. Преобразование second.xsl
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="b">
<c>
<xsl:apply-templates select="@*|node()"/>
</c>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Для того чтобы последовательно применить два этих преобразования к некоторому входящему документу a.xml, мы можем, например, дважды вызвать процессор:
java org.apache.xalan.xslt.Process -IN a.xml -XSL first.xsl -OUT b.xml
java org.apache.xalan.xslt.Process -IN b.xml -XSL second.xsl -OUT c.xml
В результате этих вызовов XSLT-процессор Xalan сначала применит преобразование first.xsl к документу a.xml и сохранит результат в файле b.xml, а затем обработает полученный документ b.xml при помощи преобразования second.xml и сохранит результат в файле c.xml.
В качестве альтернативы, например, для тех случаев, когда пакетная обработка невозможна, мы можем создать преобразование, последовательно применяющее шаблоны преобразований first.xsl и second.xsl к входящему документу. Для этого:
? назначим шаблонам преобразования first.xsl режим first, а шаблонам преобразования second.xsl — режим second;
? в основном шаблоне применим шаблоны режима first к узлам входящего документа, сохранив результат в переменной b;
? приведем результирующее дерево, содержащееся в переменной b ко множеству узлов;
? обработаем полученное множество узлов шаблонами режима second.
Следующий листинг демонстрирует предложенный подход.
Листинг 10.5. Преобразование first-then-second.xsl
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan"
exclude-result-prefixes="xalan">
<!-- Шаблоны преобразования first -->
<xsl:template match="a" mode="first">
<b>
<xsl:apply-templates select="@*|node()" mode="first"/>
</b>
</xsl:template>
<xsl:template match="@*|node()" mode="first">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="first"/>
</xsl:copy>
</xsl:template>
<!-- Шаблоны преобразования second -->
<xsl:template match="@*|node()" mode="second">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="second"/>
</xsl:copy>
</xsl:template>
<xsl:template match="b" mode="second">
<c>
<xsl:apply-templates select="@*|node()" mode="second"/>
</c>
</xsl:template>
<!-- Основное преобразование -->
<xsl:template match="/">
<!-- Присваиваем переменной а корень входящего документа -->
<xsl:variable name="a" select="/"/>
<!-- Выводим переменную a -->
<xsl:comment> a: </xsl:comment>
<xsl:copy-of select="$a"/>
<!-- Присваиваем переменной b результат обработки переменной a -->
<xsl:variable name="b">
<xsl:apply-templates select="$a" mode="first"/>
</xsl:variable>
<!-- Выводим переменную b -->
<xsl:comment> b: </xsl:comment>
<xsl:copy-of select="$b"/>
<!-- Присваиваем переменной с результат обработки переменной b -->
<xsl:variable name="c">
<xsl:apply-templates select="xalan:nodeset($b)" mode="second"/>
</xsl:variable>
<!-- Выводим переменную c -->
<xsl:comment> c: </xsl:comment>
<xsl:copy-of select="$c"/>
</xsl:template>
</xsl:stylesheet>
Ход этого преобразования лучше всего прокомментирует полученный результат.
Листинг 10.16. Входящий документ
<а>
<a>1</a>
<a>2</a>
</а>
Листинг 10.17. Выходящий документ
<!-- а: -->
<а>
<a>1</a>
<a>2</a>
</а>
<!-- b:-->
<b>
<b>1</b>
<b>2</b>
</b>
<!-- с: -->
<с>
<c>1</c>
<c>2</c>
</с>
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Отношение расширения
Отношение расширения Отношение расширения определяет взаимосвязь экземпляров отдельного варианта использования с более общим вариантом, свойства которого определяются на основе способа совместного объединения данных экземпляров. В метамодели отношение расширения
R.18.1 Расширения
R.18.1 Расширения В этом разделе перечисляются основные расширения языка С, введенные в
19.3.3. Базовые расширения
19.3.3. Базовые расширения Одно из достоинств Rails — наличие широкого набора вспомогательных методов, определенных в модуле ActiveSupport::CoreExtensions. Они «безвредны» и после добавления в основные классы становятся доступны всему приложению.Некоторые из этих методов имеют отношение
Расширения
Расширения Слово extensible (англ. расширяемый) в расшифровке аббревиатуры XSLT исторически происходит из названия языка XSL, но оно вполне применимо и к самому XSLT: спецификация этого языка позволяет разрабатывать собственные функции и элементы и использовать их в
Элементы расширения
Элементы расширения Другой, несколько реже используемой, но не менее мощной возможностью расширения XSLT являются элементы расширения. В отличие от обычных элементов, при выполнении преобразования элементы расширения не просто копируются в выходящее дерево. При их
Расширения
Расширения Xalan С++ позволяет вызывать в XSLT-преобразовании пользовательские функции расширения, написанные на языке С. Кроме того, в дополнение к базовым функциям XSLT, Xalan С++ реализует несколько наиболее часто используемых функций, например, функцию nodeset. В текущей версии (1.2)
Расширения
Расширения Расширения для Saxon могут быть созданы на языке Java в виде функций и элементов. Saxon отличает возможность использования Java-функций расширения, написанных для других Java-процессоров (в частности Xalan и Oracle XSLT Processor).Для программирования элементов расширения Saxon
Расширения
Расширения Java-версия Oracle XSLT Processor может расширяться пользовательскими функциями, написание которых, в принципе, ничем не отличаются от стандартных методов создания Java-функций расширения.К сожалению, Oracle XSLT Processor не поддерживает пользовательские элементы расширения.
Расширения
Расширения В xt реализован стандартный метод вызова Java-функций расширения (если быть до конца откровенными, Кларк фактически и придумал этот "стандартный" способ). Функции реализуются в Java-классах, которые затем подключаются при помощи URI пространств имен.Сверх этого, xt
Расширения
Расширения Другим преимуществом libxslt по сравнению с Sablotron является возможность использования расширений, причем как в виде функций, так и в виде элементов. Функции и элементы расширения в libxslt оформляются в виде C-функций, затем регистрируются в процессоре перед вызовом и
PGP 2.х.х и ее расширения.
PGP 2.х.х и ее расширения. PGP 2 — это "классическая" PGP. С помощью команд строчного интерфейса ее пользователь может выполнять все базовые криптографические функции, а именно:• генерацию пары из закрытого/открытого ключа;• шифрование файла с помощью открытого ключа любого
15. Отличия от C 15.1 Расширения
15. Отличия от C 15.1 Расширения Типы параметров функции могут быть заданы (#8.4) и будут проверяться (#7.1). Могут выполняться преобразования типов (# 7.1).Для выражений с числами с плавающей точкой может исползоваться плавающая арифметика одинарной точности; #6.2.Имена функций