Книга: XSLT

Элемент

Элемент <xsl:for-each>

Элемент <xsl:for-each> позволяет применять тело шаблона в цикле снова и снова для всех элементов набора узлов. С технической точки зрения, он работает с набором узлов, который возвращает выражение XPath и выполняет одно и то же действие с каждым узлом в наборе. При каждом шаге цикла тело шаблона применяется к следующему узлу из набора узлов, что дает возможность легко обрабатывать несколько узлов.

<XSL:FOR-EACH> ПРОТИВ <XSL:APPLY-TEMPLATES>

Вы могли заметить, что это описание практически такое же, как и у элемента <xsl:apply-templates>, и я сравню элементы <xsl:for-each> и <xsl:apply-templates> через несколько страниц.

У элемента <xsl:for-each> один атрибут:

• select (обязательный). Принимает значение выражения XPath, возвращающее набор узлов, который нужно обработать в цикле.

Элемент может содержать ноль или более элементов <xsl:sort>, за которыми следует тело шаблона. Работу с элементом <xsl:sort> мы изучим позже в этой главе.

В теле шаблона функция position возвращает позицию текущего узла в наборе узлов, a last возвращает число узлов в наборе. Если <xsl:sort> не используется, узлы обрабатываются в порядке документа (в порядке, в котором они перечислены в документе); если же используется элемент <xsl:sort>, набор узлов будет сначала отсортирован в порядке, заданном этим элементом.

Предположим, нам нужно отформатировать все названия планет, заключив их в элементы HTML <Р>, — это можно сделать следующим образом:

<xsl:template match="PLANET">
 <Р>
  <xsl:value-of select="NAME"/>
 </P>
</xsl:template>

Но что делать, если у некоторых планет по два названия, как, например:

<PLANET>
 <NAME>Mercury</NAME>
 <NAME>Closest planet to the sun</NAME>
 <MASS UNITS="(Earth = 1)">.0553</MASS>
 <DAY UNITS="days">58.65</DAY>
 <RADIUS UNITS="miles">1516</RADIUS>
 <DENSITY UNITS="(Earth = 1)">.983</DENSITY>
 <DISTANCE UNITS="million miles">43.4</DISTANCE><!--B перигелии-->
</PLANET>

Это проблема, поскольку атрибут select элемента <xsl:value-of> сам по себе выберет только первый элемент <NAME>. Чтобы пройти в цикле все возможные варианты, вместо него следует применить элемент <xsl:for-each> (листинг 5.7).

Листинг 5.7. Применение <xsl:for-each>

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:template match="PLANETS">
  <HTML>
   <xsl:apply-templates/>
  </HTML>
 </xsl:template>
 <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>

Оглавление книги


Генерация: 0.044. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз