Стивен Холзнер - XSLT
Листинг 5.13. Многоуровневая нумерация
<?xml version="1.0"?>
<хsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="node()">
<xsl:copy>
<xsl:number format="1.1.1." level="multiple" count="*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Вот результат преобразования planets.xml в новый XML-документ, в котором перенумерованы все уровни элементов в соответствии с иерархией документа:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xml" href="planets.xsl"?>
<PLANETS>1.
<PLANET>1.1.
<NAME>1.1.1. Mercury</NAME>
<MASS>1.1.2. .0553</MASS>
<DAY>1.1.3. 58.65</DAY>
<RADIUS>1.1.4. 1516</RADIUS>
<DENSITY>1.1.5. .983</DENSITY>
<DISTANCE>1.1.6. 43.4</DISTANCE><!--В перигелии-->
</PLANET>
<PLANET>1.2.
<NAME>1.2.1. Venus</NAME>
<MASS>1.2.2. .815</MASS>
<DAY>1.2.3. 116.75</DAY>
<RADIUS>1.2.4. 3716</RADIUS>
<DENSITY>1.2.5. .943</DENSITY>
<DISTANCE>1.2.6 66.8</DISTANCE><!--В перигелии-->
</PLANET>
<PLANET>1.3.
<NAME>1.3.1. Earth</NAME>
<MASS>1.3.2. 1</MASS>
<DAY>1.3.3. 1</DAY>
<RADIUS>1.3.4. 2107</RADIUS>
<DENSITY>1.3.5. 1</DENSITY>
<DISTANCE>1.3.6. 128.4</DISTANCE><!--В перигелии-->
</PLANET>
</PLANETS>
На этом мы завершаем рассмотрение нумерации документов и переходим к последней теме этой главы — расширяемости XSLT.
Расширяемость XSLT
Несмотря на кажущуюся сложность XSLT, он во многих отношениях ограничен по сравнению с языками программирования, и в процессорах XSLT сразу же начали появляться расширения XSLT. Например, Saxon представил элемент <saxon:while>, реализуя в XSLT стандартный для программирования цикл while (до тех пор, пока). Xalan представил такие элементы, как <redirect:write>, для поддержки вывода нескольких документов. А процессор MSXML3 от Microsoft позволяет писать функции на языках таких сценариев, как JavaScript, и затем вызывать их и выполнять их код.
Можно представить, с каким беспокойством на это смотрит W3C. Его работа, в принципе, заключается в стандартизации работы таких языков, как XSLT, но производители постоянно представляли свои собственные, нестандартные расширения в виде новых элементов и функций. С другой стороны, W3C не может предугадать все новые элементы и функции, поэтому консорциум начал работать над стандартизацией способов включения функций расширения и элементов в XSLT. Расширения должны удовлетворять ряду общих правил:
• расширения должны использовать пространства имен во избежание конфликтов с элементами XSL;
• процессор XSLT должен быть в состоянии распознать применение расширения — и в случае ошибки расширения реагировать хорошо определенным способом;
• таблица стилей должна быть в состоянии проверить, доступно ли определенное расширение, и если нет, вернуться назад.
НОВОЕ В XSLT 2.0
Легко представить сложности W3C даже с этими общими правилами, и комитет XSLT 2.0 собирается исследовать возможность реализации всех расширений на «чистом» XSLT, вообще не прибегая к каким-либо внешним языкам программирования.
W3C разрешил расширения двух видов, главным образом, потому, что они уже были приняты де-факто — функции расширения и элементы расширения. Хотя они пользуются популярностью, это весьма неясная область, поскольку различные производители представили разные способы их реализации.
В XSLT 1.0 проверить доступность функции расширения можно при помощи функции function-available, а доступность элемента расширения — при помощи функции element-available.
XSLT 2.0 готовится определить стандартные средства связывания XSLT с элементами расширения и, вероятно, они будут гораздо лучше проработаны, чем имеющиеся сейчас.
Давайте посмотрим на все это в работе. В следующих разделах мы рассмотрим и функции, и элементы расширения, начав с функций.
ИНИЦИАТИВА EXSLT
Теперь, после того, как механизмы расширения в рабочем проекте XSLT 1.1 были отложены до XSLT 2.0, роль других разнообразных попыток стандартизации расширений XSLT значительно повысилась. Познакомьтесь, например, с EXSLT на www.exslt.org. EXSLT — это инициатива открытого сообщества, работающего над стандартизацией расширений XSLT.
Функции расширения
В XSLT 1.0 W3C определил способ отделения функций расширения от встроенных функций, установив требование, чтобы для обращения к функциям расширения использовались имена с заданным пространством имен, как в starpowder:calculate(). В XSLT 1.0 также имеется функция function-available() для проверки наличия функции по ее имени.
В рабочем проекту XSLT 1.1 на функции расширения были наложены некоторые дополнительные ограничения:
• функции расширения должны работать как встроенные функции;
• для Java и ECMAScript должны быть реализованы привязки к языку;
• механизм должен позволять естественное расширение для поддержки других языков в будущем;
• для реализации переносимой привязки функции расширения для любого конкретного языка не должен быть нужен процессор;
• процессор, реализующий функции расширения для любого языка, чья привязка обеспечивается спецификацией XSLT, должен соответствовать этим языкам;
• должны быть разрешены как встроенные реализации функций расширения, так и внешние;
• в функции расширения должно быть возможно передавать аргументы всех типов данных XPath;
• функции расширения должны иметь возможность возвращать в качестве результата все типы данных XPath;
• функции расширения должны иметь возможность создавать и возвращать наборы узлов фрагментов XML;
• должна иметься возможность включать или импортировать функции расширения из другой таблицы стилей;
• при неоднозначности выбора реализации функции расширения процессор должен выдать ошибку и прекратить работу;
• процессор должен преобразовывать аргументы способом, согласованным со встроенными функциями;
• функции расширения должны быть способны вернуть объект любого типа основного языка;
• должна существовать возможность передать в функцию расширения объект любого типа основного языка.
Вплоть до недавнего времени процессоры XSLT полностью самостоятельно определяли способ реализации функций расширения. Например, в Saxon и Xalan существует возможность непосредственно выполнять код Java, если определить пространство имен, задающее класс Java в качестве последней части URI. Я поступил так в следующем случае, определив пространство имен Date, соответствующее классу Java Date:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl=http://www.w3.org/1999/XSL/Transform
xmlns:Date="http://www.saxon.com/java/java.util.Date">
.
.
.
После этого я могу воспользоваться такими функциями класса Date Java, как toString и new, для того чтобы заключить текущую дату в элементы заголовка <Н1> HTML в выходном документе (листинг 5.14).
Листинг 5.14. Применение функций Date Java<?xml version="1.0"?>
<xsl:stylesheel version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:Date="http://www.saxon.com/java/java.util.Date">
<xsl:template match="/PLANETS">
<HTML>
<HEAD>
<TITLE>
The Planets Table
</TITLE>
</HEAD>
<BODY>
<H1>
The Planets Table
</H1>
<BR/>
<H1>
<xsl:value-of select="Date:toString(Date:new())"/>
</H1>
<TABLE BORDER="2">
<TD>Name</TD>
<TD>Mass</TD>
<TD>Radius</TD>
<TD>Day</TD>
<xsl:apply-templates/>
</TABLE>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="PLANET">
<TR>
<TD><xsl:value-of select="NAME"/></TD>
<TD><xsl:apply-templates select="MASS"/></TD>
<TD><xsl:apply-templates select="RADIUS"/></TD>
<TD><xsl:applу-templates select="DAY"/></TD>
</TR>
</xsl:template>
<xsl:template match="MASS">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="RADIUS">
<xsl:value-of select="."/>