Функции string в XSLT

В спецификации описано, как работают функции string. Поясняется, что при приведении списка узлов к строке, результатом будет строковое значение первого узла. На примере это будет выглядеть следующим образом:

<nodes>
  <node>node 1</node>
  <node>node 2</node>
  <node>node 3</node>
</nodes>
<xsl:value-of select="string(nodes/node)"/>
<!-- Выведет "node 1" -->

В коде выше использована функция string(). Вообще в сочетании с value-of её использовать не нужно, потому что результатом value-of и так будет приведённое к строке значение. Это объясняет, почему следующие 2 инструкции дадут разные результаты:

<p>
  <xsl:apply-templates select="nodes/node"/>
</p>
<p>
  <xsl:value-of select="nodes/node"/>
</p>
<p>node 1node 2node 3</p>
<p>node 1</p>

Но зачем это знать? value-of применимо к node set вряд ли будет когда-нибудь использоваться.
Помнить о том, как узлы приводятся к типу string, необходимо, потому что незнание может привести к забавным результатам в случае использования строковых функций в предикате.
Рассмотрим xml, который содержит список человек, сгруппированных по округам, в которых они живут:

<persons>
  <region name="ЦАО">
    <person>Бобров</person>
    <person>Иванов</person>
    <person>Акунин</person>
  </region>
  <region name="СЗАО">
    <person>Анисин</person>
    <person>Никитин</person>
    <person>Топуриа</person>
  </region>
</persons>

Необходимо вывести из этого списка всех, чья фамилия начинается на «А». Вывод также должен быть сгруппирован по округам. Ожидаемые выходные данные такие:

<div>
  <h1>Люди на букву "А"</h1>
  <h2>Люди из ЦАО</h2>
  <ul>
    <li>Акунин</li>
  </ul>
  <h2>Люди из СЗАО</h2>
  <ul>
    <li>Анисин</li>
  </ul>

Очевидно, что заголовок h1 должен появится только в том случае, если есть, хотя бы один округ, в котором есть люди с фамилией на буквы «А». Следующий шаблон для вывода заголовка

<xsl:apply-templates select="news" mode="h1"/>

<xsl:template math="news" mode="h1"/>
<xsl:template math="news[starts-with(region/person, "A")]" mode="h1">
   <!-- тут код -->
</xsl:template>

для приведённого выше xml не выведет ничего. Всё потому, что функция starts-with принимает на вход строковое значение, к которому приводится набор узлов region/person. А согласно изложенному выше, строковое значение — это значение первого узла. То есть строка «Бобров».
Однако правильное решение изложенной задачи содержится уже в самой формулировке «если есть, хотя бы один округ, в котором есть люди...». Условие, сравнивающее первую букву фамилии, необходимо применить непосредственно к людям в округе, а не к контейнеру region. Таким образом, предикат необходимо написать так:

<xsl:template math="news[region/person[starts-with(., "A")]]" mode="h1">
   <!-- тут код -->
</xsl:template>


Tags:
This entry was posted on Wednesday, April 15th, 2009 at 2:40 pm and is filed under Заметки. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

Your comment