Принятие XML Schema также оказывает определенное влияние на XPath. В схемах ХМL-документов можно определять типы данных атрибутов и элементов. Соответственно, семантика XPath выражений должна отражать эту метаинформацию: например, оператор сложения '+
' будет вести себя по-разному на строковых и числовых операндах.
Рассмотрим выражение int/x + int/y
на простейшем документе:
<int>
<x>2</x>
<y>2</y>
</int>
В первой версии XPath результатом вычисления int/x + int/у
в любом случае будет 4
. Между тем, старшие версии могут учитывать метаинформацию о типе обрабатываемых данных и возвращать 4
в случае числовых операндов и '22'
в случае строковых.
На момент написания этих строк работа над XSLT 2.0 и XPath 2.0 идет полным ходом. Конечно, пока еще рано заглядывать вперед и раскрывать секреты рабочей группы XSL, однако, основываясь на опубликованных спецификациях XLST 1.1 и требованиях к версии XSLT 2.0, кое-какие выводы сделать все же можно.
Отличия XSLT 1.1 от XSLT 1.0
Отсутствие result tree fragment
Главное и наиболее существенное отличие XSLT 1.1 от XSLT 1.0 состоит в том, что тип данных, известный в XSLT 1.0 как result tree fragment (результирующий фрагмент дерева) в XSLT 1.1. отсутствует. Вместо него в версии 1.1 используется множество узлов, состоящее из единственного корневого узла результирующего фрагмента.
На первый взгляд, разница между двумя этими методами представления фрагментов деревьев минимальна. Но если принять во внимание положения языка XPath о том, что ни один тип данных не может быть преобразован во множество узлов, разница эта оказывается огромной. Получается, что, несмотря на то, что результирующий фрагмент и множество, состоящее из его корня, представляют одни и те же данные и структуры, с фрагментом нельзя делать многое из того, что можно делать с множеством узлов.
В преобразованиях часто бывает необходимо использовать массивы статических данных, и логично было бы присваивать их переменным, чтобы использовать затем в выражениях. К несчастью, простое создание фрагмента дерева в переменной мало помогает. Конструкция
<xsl:variable name='colors'>
<color>#0E0E0E</color>
<color>#FFFFFF</color>
</xsl:variable>
создает в переменной colors
результирующий фрагмент дерева. В соответствии со спецификацией XPath 1.0 выражение $colors/color[1]
будет некорректным, поскольку типом colors
является результирующий фрагмент дерева, который не может быть напрямую преобразован во множество узлов. Иными словами, совершенно логичное и оправданное выражение не является корректным. Конечно, существуют способы обойти этот запрет — с помощью расширений и тому подобного, но нельзя не согласиться с тем, что результирующие фрагменты являются самой большой занозой в XSLT 1.0.
XSLT 1.1 исправляет этот просчет. Переменная colors
, определенная выше, будет иметь своим значение не фрагмент дерева, а множество из одного, корневого, узла этого фрагмента и ее можно использовать везде, где только можно использовать тип данных node-set
.
Несколько выходящих документов
Как известно, преобразование в XSLT 1.0 имеет один основной входящий документ (плюс документы, доступные при помощи функции document
) и ровно один выходящий документ. То есть, для того, чтобы сгенерировать на основе одного входящего документа несколько выходящих следует просто выполнить несколько преобразований.
Следуя многочисленным запросам программистов, почти все разработчики XSLT-процессоров предоставили в своих продуктах возможность генерировать несколько выходящих документов непосредственно из одного преобразования. Элемент xsl:document
, добавленный в XSLT 1.1, сделал эту возможность стандартной.
Самым простым применением xsl:document
является разбиение одного документа на несколько. Например, имея документ вида
<book>
<chapter>Text 1</chapter>
<chapter>Text 2</chapter>
<chapter>Text 3</chapter>
</book>
мы можем выделить элементы chapter
в отдельные файлы, а в самом выходящем документе создать оглавление со ссылками.
<xsl:stylesheet
version='1.1'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match='book'>
<xsl:copy>
<xsl:apply-templates select='chapter'/>
</xsl:copy>
</xsl:template>
<xsl:template match='chapter'>
<chapter href='chapter{position()}.xml'/>
<xsl:document href='chapter{position()}.xml'>
<xsl:copy-of select='.'/>
</xsl:document>
</xsl:template>
</xsl:stylesheet>
Результатом этого преобразования будут следующие четыре документа.
<book>
<chapter href='chapter1.xml'/>
<chapter href='chapter2.xml'/>
<chapter href='chapter3.xml'/>