Книга: XSLT

Элементы , и

Элементы <xsl:choose>, <xsl:when> и <xsl:otherwise>

Элемент <xsl:choose> похож на оператор Java switch, который позволяет сравнивать значение условия с несколькими возможными вариантами.

У элемента <xsl:choose> нет атрибутов. Он содержит один или более элементов <xsl:when> и (не обязательно) один элемент <xsl:otherwise>, который в случае применения должен стоять последним.

Вот как это работает: в элемент <xsl:choose> заключаются элементы <xsl:when>, каждый с условием true/false. Применяется тело шаблона в первом элементе <xsl:when>, чье условие имеет значение true, все остальные не применяются. Последним элементом внутри элемента <xsl:choose> может быть элемент <xsl:otherwise> тело шаблона внутри этого элемента применяется, если ни одно из предыдущих условий <xsl:when> не имело значения true:

<xsl:choose>
 <xsl:when test="expression1">
  <!--template-body 1-->
 </xsl:when>
 <xsl:when test="expression">
  <!-- template-body 2-->
 </xsl:when>
 <xsl:when test="expression3">
  <!--template-body 3-->
 </xsl:when>
 <xsl:otherwise>
  <!--template body 4-->
 </xsl:otherwise>
</xsl:choose>

В предыдущем разделе для осуществления этого преобразования нам потребовалось три элемента <xsl:if>:

<?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>
    The first three planets are: <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>
  <xsl:value-of select="NAME"/>
  <xsl:if test="position()!=last()">, </xsl:if>
  <xsl:if test="position()=last()-1>and </xsl:if>
  <xsl:if test="position()=last()">.</xsl:if>
 </xsl:template>
</xsl:stylesheet>

Теперь то же самое можно сделать при помощи единственного элемента <xsl:choose>:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xml:output method="xml"/>
 <xsl:template match="PLANETS">
  <DOCUMENT>
   <TITLE>
    The Planets
   </TITLE>
   <PLANETS>
    The first three planets are: <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>
  <xsl:value-of select="NAME"/>
  <xsl:choose>
   .
   .
   .
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

Нам нужно проверить, в каком месте документа мы находимся, при помощи включения нескольких элементов <xsl:when>. У этого элемента только один атрибут:

• test (обязательный). Принимает логическое (Boolean) значение (true/false) проверяемого условия.

Элемент <xsl:when> содержит тело шаблона.

Атрибут проверки принимает значение true/false выражения, определяющего, будет ли применяться заключенное в элементе <xsl:when> тело шаблона или нет. Например, вот как я добавил элементы <xsl:when> с соответствующими знаками пунктуации для всех планет, кроме последней:

<?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>
    The first three planets are: <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>
  <xsl:value-of select="NAME"/>
  <xsl:choose>
   <xsl:when test="position()!=last()">, </xsl:when>
   <xsl:when test="position()=last()-1">and </xsl:when>
   .
   .
   .
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

Эти два элемента <xsl:when> выбирают все элементы <PLANET> за исключением последнего, поэтому элемент <xsl:otherwise> можно применить для последнего элемента <PLANET>. Тело шаблона в этом элементе будет применено, если ни в одном элементе <xsl:when> в элементе <xsl:choose> условие не примет значение true.

У элемента <xsl:otherwise> нет атрибутов, и он содержит тело шаблона. Вот как это выглядит в листинге 5.4.

Листинг 5.4. Применение <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>
    The first three planets are: <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>
  <xsl:value-of select="NAME"/>
  <xsl:choose>
   <xsl:when test="position()!=last()">, </xsl:when>
   <xsl:when test="position()=last()-1">and </xsl:when>
   <xsl:otherwise>.</xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

Вот как это работает; этот код дает тот же результат, что и код, проверяющий позицию элементов <PLANET> при помощи <xsl:if>:

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

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


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