Книга: XSLT

Работа с переменными

Работа с переменными

Давайте рассмотрим примеры применения переменных. В следующем примере (листинг 9.1) я присваиваю переменной copyright сообщение об авторских правах и затем с ее помощью добавляю атрибут copyright во все элементы planets.xml.

Листинг 9.1. Применение переменной

<?xml version="1.0"?>
<xsl:stylesheet version="1.1"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml"/>
 <xsl:variable name="copyright" select="'(c)2002 Starpowder Inc.'"/>
 <xsl:template match="*">
  <xsl:copy>
   <xsl:attribute name="copyright">
    <xsl:value-of select="$copyright"/>
   </xsl:attribute>
   <xsl:apply-templates/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

Вот результирующий документ, дополненный атрибутами copyright

<?xml version="1.0" encoding="utf-8"?>
<PLANETS copyright="(c)2002 Starpowder Inc.">
 <PLANET copyright="(c)2002 Starpowder Inc.">
  <NAME copyright="(c)2002 Starpowder Inc.">Mercury</NAME>
  <MASS copyright="(c)2002 Starpowder Inc.">.0553</MASS>
  <DAY copyright="(с)2002 Starpowder Inc.">58.65</DAY>
  <RADIUS copyright="(c)2002 Starpowder Inc.">1516</RADIUS>
  <DENSITY copyright="(c)2002 Starpowder Inc.">.983</DENSITY>
  <DISTANCE copyright="(с)2002 Starpowder Inc.">43.4</DISTANCE>
 </PLANET>
 <PLANET copyright="(c)2002 Starpowder Inc.">
  <NAME copyright="(c)2002 Starpowder Inc.">Venus</NAME>
  <MASS copyright="(c)2002 Starpowder Inc.">.815</MASS>
  <DAY copyright="(с)2002 Starpowder Inc.">116.75</DAY>
  <RADIUS copyright="(c)2002 Starpowder Inc.">3716</RADIUS>
  <DENSITY copyright="(c)2002 Starpowder Inc.">.943</DENSITY>
  <DISTANCE copyright="(c)2002 Starpowder Inc.">66.8</DISTANCE>
 </PLANET>
 .
 .
 .

Переменные зачастую удобны для хранения значении, зависимых от контекста, и мы сейчас рассмотрим еще один пример, о котором я упоминал в начале главы. В этом случае я преобразую planets.xml в новый документ, в котором для каждой планеты будет один элемент. Каждый из этих новых элементов будет содержать два элемента <SIBLINGPLANET>, содержащих планеты-братья текущей планеты — например, братьями Земли будут Венера и Меркурий:

<?xml version="1.0" encoding="utf-8"?>
<Mercury>
 <SIBLINGPLANET>
  Venus
 </SIBLINGPLANET>
 <SIBLINGPLANET>
  Earth
 </SIBLINGPLANET>
</Mercury>
<Venus>
 <SIBLINGPLANET>
  Mercury
 </SIBLINGPLANET>
 <SIBLINGPLANET>
  Earth
 </SIBLINGPLANET>
</Venus>
<Earth>
 <SIBLINGPLANET>
  Mercury
 </SIBLINGPLANET>
 <SIBLINGPLANET>
  Venus
 </SIBLINGPLANET>
</Earth>

Для примера я поочередно выбираю каждый элемент <PLANET> и прохожу в цикле <xsl:for-each> по всем планетам, создавая элементы <SIBLINGPLANET> для всех планет, не являющихся контекстным узлом. Однако откуда мне известно внутри элемента <xsl:for-each>, какая из планет является контекстным узлом, выбранным шаблоном? Внутри элемента <xsl:for-each> «.» ссылается на текущий узел, с которым работает <xsl:for-each>, но не на контекстный узел шаблона. Проблему можно решить, если сохранить контекстный узел в переменной, которую я назвал contextnode:

<?xml version="1.0"?>
<xsl:stylesheet version="1.1"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml"/>
 <xsl:template match="PLANETS">
  <xsl:for-each select="PLANET">
   <xsl:element name="{NAME}">
    <xsl:variable name="contextnode" select="."/>
    .
    .
    .

Теперь для проверки в цикле <xsl:for-each> того, что текущий элемент не является контекстным узлом, я могу обратиться к контекстному узлу шаблона как $contextnode (листинг 9.2).

Листинг 9.2. Хранение в переменной информации, зависимой от контекста

<?xml version="1.0"?>
<xsl:stylesheet version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
 <xsl:template match="PLANETS">
  <xsl:for-each select="PLANET">
   <xsl:element name="{NAME}">
    <xsl:variable name="contextnode" select="."/>
    <xsl:for-each select="//PLANET">
     <xsl:if test=". != $contextnode">
      <xsl:element name="SIBLINGPLANET">
       <xsl:value-of select="NAME"/>
      </xsl:element>
     </xsl:if>
    </xsl:for-each>
   </xsl:element>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

Теперь наша проблема решена.

Если у элемента <xsl:variable> есть тело, он создает переменную, чье значение является фрагментом результирующего дерева. В следующем примере при помощи фрагмента результирующего дерева я задаю значение по умолчанию для атрибута COLOR (цвет), если значение для него уже не задано. Значение по умолчанию я устанавливаю в «blue» (голубой):

<xsl:variable name="COLOR">
 <xsl:choose>
  <xsl:when test="@COLOR">
   <xsl:value-of select="@COLOR"/>
  </xsl:when>
  <xsl:otherwise>blue</xsl:otherwise>
 </xsl:choose>
</xsl:variable>

Строковое значение фрагмента результирующего дерева (то есть либо значение атрибута COLOR, либо значение по умолчанию, «blue») присваивается переменной COLOR. Теперь в выражениях XPath можно обращаться к значению этой переменной, $COLOR, а не к значению атрибута (@COLOR, гарантированно получая при этом значение цвета, даже если у соответствующего элемента отсутствует атрибут COLOR.

Вот еще один пример фрагмента результирующего дерева. В этом случае я сохраняю элемент буквального результата в переменной START_HTML:

<?xml version="1.0"?>
<xsl:stylesheet version="1.1"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html"/>
 <xsl:variable name="START_HTML">
  <HEAD>
   <TITLE>
    My page
   </TITLE>
  </HEAD>
 </xsl:variable>
 .
 .
 .

Теперь я могу использовать этот элемент буквального результата где угодно:

<?xml version="1.0"?>
<xsl:stylesheet version="1.1"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html"/>
 <xsl:variable name="START_HTML">
  <HEAD>
   <TITLE>
    My page
   </TITLE>
  </HEAD>
 </xsl:variable>
 <xsl:template match="PLANETS">
  <HTML>
   <xsl:copy-of select="$START HTML"/>
   <BODY>
    <H1>Welcome to my page</H1>
   </BODY>
  </HTML>
 </xsl:template>
</xsl:stylesheet>

И вот результат:

<HTML>
 <HEAD>
  <TITLE>
   My page
  </TITLE>
 </HEAD>
 <BODY>
  <H1>Welcome to my page</H1>
 </BODY>
</HTML>

Однако поскольку теперь фрагменты результирующего дерева не допускаются в XSLT 1.1, этот пример работать не будет. Как же тогда сохранить весь элемент буквального результата одновременно с возможностью простого вызова? Вы можете создать именованный шаблон.

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


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