KnigaRead.com/

Стивен Холзнер - XSLT

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Стивен Холзнер, "XSLT" бесплатно, без регистрации.
Перейти на страницу:

<?xml version="1.0" encoding="UTF-8"?>

<DOCUMENT>

 <TITLE>

  The Planets

 </TITLE>

 <PLANETS>

  The first three planets are: Mercury, Venus, and Earth.

 </PLANETS>

</DOCUMENT>

Вот еще один пример преобразования XML-XML. В этом случае я преобразую planets.xml в новый XML-документ, сохраняя только название каждой планеты и добавляя описание:

<?xml version="1.0" encoding="UTF-8"?>

<DOCUMENT>

 <TITLE>

  The Planets

 </TITLE>

 <PLANETS>

  <PLANET>

   <NAME>Mercury</NAME>

   <DESCRIPTION>Hottest</DESCRIPTION>

  </PLANET>

  <PLANET>

   <NAME>Venus</NAME>

   <DESCRIPTION>Hot</DESCRIPTION>

  </PLANET>

  <PLANET>

   <NAME>Earth</NAME>

   <DESCRIPTION>OK</DESCRIPTION>

  </PLANET>

 </PLANETS>

</DOCUMENT>

Это преобразование можно реализовать, выбирая значение каждого элемента <NAME>, то есть заключенный в нем текст (заметьте, что такого рода строки в XSLT учитывают регистр) (листинг 5.5).

Листинг 5.5. Второй пример <xsl:choose>

<?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">

  <DOCUMENT>

   <TITLE>

    The Planets

   </TITLE>

   <PLANETS>

    <xsl:apply-templates select="PLANET"/>

   </PLANETS>

  </DOCUMENT>

 </xsl:template>


 <xsl:template match="PLANET">

  <xsl:if test="NAME[not(text())]">

   <xsl:message terminate="yes">

    Each planet must have a name!

   </xsl:message>

  </xsl:if>

  <PLANET>

   <NAME>

    <xsl:value-of select="NAME"/>

   </NAME>

   <DESCRIPTION>

    <xsl:choose>

     <xsl:when test="NAME='Mercury'">Hottest</xsl:when>

     <xsl:when test="NAME='Venus'">Hot</xsl:when>

     <xsl:when test="NAME='Earth'">OK</xsl:when>

    </xsl:choose>

   </DESCRIPTION>

  </PLANET>

 </xsl:template>

</xsl:stylesheet>

Вот и все.

Предположим теперь, что нам нужно добавить в каждый элемент <PLANET> атрибут COLOR:

<?xml version="1.0"?>

<?xml-stylesheet type="text/xml" href="planets.xsl"?>

<PLANETS>

 <PLANET COLOR="RED">

  <NAME>Mercury</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>

 <PLANET COLOR="WHITE">

  <NAME>Venus</NAME>

  <MASS UNITS="(Earth = 1)">.815</MASS>

  <DAY UNITS="days">116.75</DAY>

  <RADIUS UNITS="miles">3716</RADIUS>

  <DENSITY UNITS="(Earth = 1)">.943</DENSITY>

  <DISTANCE UNITS="million miles">66.8</DISTANCE><!--B перигелии-->

 </PLANET>

 <PLANET COLOR="BLUE">

  <NAME>Earth</NAME>

  <MASS UNITS="(Earth = 1)">1</MASS>

  <DAY UNITS="days">1</DAY>

  <RADIUS UNITS="miles">2107</RADIUS>

  <DENSITY UNITS="(Earth = 1)">1</DENSITY>

  <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

 </PLANET>

</PLANETS>

Отобразить названия различных планет при помощи элемента <xsl:choose>, отформатированные по-разному при помощи тегов HTML <В>, <I> и <U> в зависимости от значения атрибута COLOR, можно следующим образом (листинг 5.6).

Листинг 5.6. Форматирование при помощи <xsl:choose>

<?xml version="1.0"?>

<xsl:stylesheet version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:template match="PLANETS">

  <HTML>

   <HEAD>

    <TITLE>

     Planets

    </TITLE>

   </HEAD>

   <BODY>

    <xsl:apply-templates select="PLANET"/>

   </BODY>

  </HTML>

 </xsl:template>


 <xsl:template match="PLANET">

  <xsl:choose>

   <xsl:when test="@COLOR = 'RED'">

    <В>

     <xsl:value-of select="NAME"/>

    </B>

   </xsl:when>

   <xsl:when test="@COLOR = 'WHITE'">

    <I>

     <xsl:value-of select="NAME"/>

    </I>

   </xsl:when>

   <xsl:when test="@COLOR = 'BLUE'">

    <U>

     <xsl:value-of select="NAME"/>

    </U>

   </xsl:when>

   <xsl:otherwise>

   <PRE>

    <xsl:value-of select="."/>

   </PRE>

  </xsl:otherwise>

 </xsl:choose>

</xsl:template>

</xsl:stylesheet>

Вот результирующий документ:

<HTML>

 <HEAD>

  <TITLE>

   Planets

  </TITLE>

 </HEAD>

 <BODY>

  <B>Mercury</B>

  <I>Venus</I>

  <U>Earth</U>

 </BODY>

</HTML>

Как вы видели, при помощи <xsl:if> можно проверять единственное условие, а при помощи <xsl:choose> — несколько; аналогичные конструкции присутствуют в большинстве языков программирования. Кроме подобных этим условных операторов, в большей части языков программирования существуют также операторы цикла, и в XSLT содержится нечто похожее — элемент <xsl:for-each>.

Элемент <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">

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*