Стивен Холзнер - XSLT
<xsl:template match="PLANET">
<xsl:for-each select="NAME">
<P>
<xsl:value-of select="."/>
</P>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Эта таблица стилей охватывает все элементы <NAME>, помещает их значения в элемент <Р> и добавляет их в выходной документ следующим образом:
<HTML>
<P>Mercury</P>
<P>Closest planet to the sun</P>
<P>Venus</P>
<P>Earth</P>
</HTML>
Вот еще один пример, впервые появившийся в главе 3, «Создание и применение шаблонов», где при помощи элемента <xsl:for-each> в цикле перебирались все атрибуты элемента:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="*">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Следующий пример появился в главе 2, «Создание и применение таблиц стилей». Это упрощенная таблица стилей, в которой нельзя использовать какие-либо элементы высокого уровня, то есть нельзя использовать <xsl:template> или <xsl:apply-templates>, однако можно пройти по узлам в цикле при помощи <xsl:for-each>:
<HTML xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0">
<HEAD>
<TITLE>
The Planets Table
</TITLE>
</HEAD>
<BODY>
<H1>
The Planets Table
</H1>
<TABLE BORDER="2">
<TR>
<TD>Name</TD>
<TD>Mass</TD>
<TD>Radius</TD>
<TD>Day</TD>
</TR>
<xsl:for-each select="//PLANET">
<TR>
<TD><xsl:value-of select="NAME"/></TD>
<TD><xsl:value-of select="MASS"/></TD>
<TD><xsl:value-of select="RADIUS"/></TD>
<TD><xsl:value-of select="DAY"/></TD>
</TR>
</xsl:for-each>
</TABLE>
</BODY>
</HTML>
Эта упрощенная таблица стилей форматирует planets.xml в planets.html практически так же хорошо, как и шаблон, использующий <xsl:apply-templates>, в связи с чем появляется интересный вопрос: когда следует для прохода по узлам применять <xsl:for-each>, а когда <xsl:apply-templates>?
Как правило, <xsl:apply-templates> хорошо применять в тех случаях, когда организация дочерних узлов неизвестна, и вы хотите применить различные шаблоны к потомкам разных видов — независимо от количества уровней, на которые углубляется их структура. С другой стороны, если дочерние узлы обладают регулярной, хорошо определенной организацией, можно задать <xsl:for-each> для обработки всех этих узлов.
Элемент <xsl:for-each> работает во многом так же, как и <xsl:apply-templates>; можно даже вкладывать шаблоны при помощи <xsl:for-each>, как это делается при помощи последовательных элементов <xsl:apply-templates>. В листинге 5.8 я прохожу в цикле по каждому элементу <PLANET>, а затем во вложенном в него цикле по всем элементам, содержащимся в элементе <PLANET>, перечисляя их данные из элементов <DATA> следующим образом.
Листинг 5.8. Второй пример <xsl:for-each><?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="PLANETS">
<PLANETS>
<xsl:for-each select="PLANET">
<PLANET>
<xsl:for-each select="*">
<DATA>
<xsl:value-of select="."/>
</DATA>
</xsl:for-each>
</PLANET>
</xsl:for-each>
</PLANETS>
</xsl:template>
</xsl:stylesheet>
И вот результат:
<?xml version="1.0" encoding="UTF-8"?>
<PLANETS>
<PLANET>
<DATA>Mercury</DATA>
<DATA>.0553</DATA>
<DATA>58.65</DATA>
<DATA>1516</DATA>
<DATA>.983</DATA>
<DATA>43.4</DATA>
</PLANET>
<PLANET>
<DATA>Venus</DATA>
<DATA>.815</DATA>
<DATA>116.75</DATA>
<DATA>3716</DATA>
<DATA>.943</DATA>
<DATA>66.8</DATA>
</PLANET>
<PLANET>
<DATA>Earth</DATA>
<DATA>1</DATA>
<DATA>1</DATA>
<DATA>2107</DATA>
<DATA>1</DATA>
<DATA>128.4</DATA>
</PLANET>
</PLANETS>
Сортирующие элементы
При помощи элемента <xsl:sort> можно сортировать узлы. Этот элемент устанавливает порядок обработки узлов для <xsl:apply-templates> и <xsl:for-each>. В следующем списке перечислены атрибуты <xsl:sort>:
• select (необязательный). Принимает значение выражения XPath, возвращающего набор узлов для сортировки. По умолчанию — «string(.)»;
• order (необязательный). Задает порядок сортировки, устанавливается в «ascending» (по возрастанию) или «descending» (по убыванию);
• case-order (необязательный). Определяет, будут ли буквы в верхнем регистре располагаться перед буквами в нижнем регистре. Устанавливается в «upper-first» (сначала верхний) или «lower-first» (сначала нижний);
• lang (необязательный). Задает язык, чьи соглашения о сортировке будут применяться. Устанавливается в код языка, допустимый в атрибуте xml:lang;
• data-type (необязательный). Определяет, будет ли сортировка вестись в алфавитном или числовом порядке. Устанавливается в «text» (текст), «number» (число) или в QName.
Этот элемент не включает содержимое. Его следует применять внутри элементов <xsl:apply-templates> или <xsl:for-each> для сортировки наборов узлов, с которыми работают эти элементы.
В листинге 5.9 я только отсортирую элементы <PLANET> в planets.xml в возрастающем алфавитном порядке по их именам, используя <xsl:for-each> в упрощенной таблице стилей.
Листинг 5.9. Сортировка данных<HTML xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0">
<HEAD>
<TITLE>
The Sorted Planets Table
</TITLE>
</HEAD>
<BODY>
<H1>
The Sorted Planets Table
</H1>
<TABLE BORDER="2">
<TR>
<TD>Name</TD>
<TD>Mass</TD>
<TD>Radius</TD>
<TD>Day</TD>
</TR>
<xsl:for-each select="//PLANET">
<xsl:sort/>
<TR>
<TD><xsl:value-of select="NAME"/></TD>
<TD><xsl:value-of select="MASS"/></TD>
<TD><xsl:value-of select="RADIUS"/></TD>
<TD><xsl:value-of select="DAY"/></TD>
</TR>
</xsl:for-each>
</TABLE>
</BODY>
</HTML>
А вот результат. Обратите внимание на то, что планеты действительно отсортированы как Earth, Mercury и затем Venus:
<HTML>
<HEAD>
<TITLE>
The Sorted Planets Table
</TITLE>
</HEAD>
<BODY>
<H1>
The Sorted Planets Table
</H1>
<TABLE BORDER="2">
<TR>
<TD>Name</TD>
<TD>Mass</TD>
<TD>Radius</TD>
<TD>Day</TD>
</TR>
<TR>
<TD>Earth</TD>
<TD>1</TD>
<TD>2107</TD>
<TD>1</TD>
</TR>
<TR>
<TD>Mercury</TD>
<TD>.0553</TD>
<TD>1516</TD>
<TD>58.65</TD>
</TR>
<TR>
<TD>Venus</TD>
<TD>.815</TD>
<TD>3716</TD>
<TD>116.75</TD>
</TR>
</TABLE>
</BODY>
</HTML>
Вид документа показан на рис. 5.1.