Функции string в XSLT
В спецификации описано, как работают функции string. Поясняется, что при приведении списка узлов к строке, результатом будет строковое значение первого узла. На примере это будет выглядеть следующим образом:
<node>node 1</node>
<node>node 2</node>
<node>node 3</node>
</nodes>
<!-- Выведет "node 1" -->
В коде выше использована функция string(). Вообще в сочетании с value-of её использовать не нужно, потому что результатом value-of и так будет приведённое к строке значение. Это объясняет, почему следующие 2 инструкции дадут разные результаты:
<xsl:apply-templates select="nodes/node"/>
</p>
<p>
<xsl:value-of select="nodes/node"/>
</p>
Но зачем это знать? value-of применимо к node set вряд ли будет когда-нибудь использоваться.
Помнить о том, как узлы приводятся к типу string, необходимо, потому что незнание может привести к забавным результатам в случае использования строковых функций в предикате.
Рассмотрим xml, который содержит список человек, сгруппированных по округам, в которых они живут:
<region name="ЦАО">
<person>Бобров</person>
<person>Иванов</person>
<person>Акунин</person>
</region>
<region name="СЗАО">
<person>Анисин</person>
<person>Никитин</person>
<person>Топуриа</person>
</region>
</persons>
Необходимо вывести из этого списка всех, чья фамилия начинается на «А». Вывод также должен быть сгруппирован по округам. Ожидаемые выходные данные такие:
Очевидно, что заголовок 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>
Tags: xml/xsl