XML и сопутствующие технологии
О рассылке
Сайт рассылки: http://www.frnet.narod.ru/. На нем вы найдете все выпуски рассылки, а также полезную информацию по web-дизайну и web-программированию.
Выпуск №5: Группировки в XSLT
Исаак Тынгылчав

Типовая задача XSLT- группировка элементов по одному из параметров. Например, есть список сотрудников с указанием подразделений, в которых они работают.

<items>
    <item dep="отдел 301">Иванов И.И.</item>
    <item dep="отдел 302">Петрова П.П.</item>
    <item dep="АХО">Тынгылчав И.И.</item>
    <item dep="ВОХР">Рабинович П.Е.</item>
    <item dep="отдел 301">Вышку Н.Н.</item>
    <item dep="ВОХР">Штырц-Кобер С.С.</item>
    <item dep="АХО">Хидияттулин Г.Г.</item>
    <item dep="отдел 302">Непийпиво С.С.</item>
    <item dep="ВОХР">Говорухо-Отрок С.П.</item>
</items>

Необходимо сгруппировать всех сотрудников по подразделениям в следующем виде:

<h1>отдел 301</h1>
<ul>
<li>Иванов И.И.</li>
<li>Вышку Н.Н.</li>
</ul>
<h1>отдел 302</h1>
<ul>
<li>Петрова П.П.</li>
<li>Непийпиво С.С.</li>
</ul>

Ниже рассмотрим вариант решения задачи:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">     <xsl:output indent="yes" />
        <xsl:template match="*">
            <-- ПЕРВЫЙ ЦИКЛ - отбор подразделений -- >
            <xsl:for-each select="item[not(@dep=preceding-sibling::item/@dep)]" >
                <xsl:variable name="dep" select="@dep" />
                <h1>         <xsl:value-of select="$dep"/>         </h1>
                    <ul>
                    <-- ВТОРОЙ ЦИКЛ - отбор сотрудников -- >
                        <xsl:for-each select="../item[@dep = $dep]">
                            <li>         <xsl:value-of select="."/>         </li>
                        </xsl:for-each>
                    <-- ВТОРОЙ ЦИКЛ - отбор сотрудников -- >
                    </ul>
            </xsl:for-each>
            <-- / ПЕРВЫЙ ЦИКЛ - отбор подразделений -- >
        </xsl:template>
</xsl:stylesheet>

Пример лаконичен и прост для понимания тех, кто привык к обычным языкам программирования.

Первый цикл (см. комментарии в листинге) формирует список отделов из общего списка сотрудников. Если бы у каждого сотрудника был параметр, указывающий на должность, можно было бы отобрать по этому параметру начальников, а по параметру @dep отобрать название подразделений. Но такого параметра нет. Поэтому для составления списка отделов используется фильтр, отбирающий предшествующих в списке соседей (ось preceding-sibling):

item[not(@dep=preceding-sibling::item/@dep)]

Этот фильтр определяет тех сотрудников, для которых нет предшествующих в списке (preceding-sibling::item) коллег из такого же отдела, т.е. не выполняется условие: @dep=preceding-sibling::item/@dep.

Вложенный цикл xsl:for-each повторно проходит по всему списку сотрудников, и выводит только тех сотрудников, которые принадлежат отделу отобранному в первом цикле.

Архив
Архив рассылок сайта: http://www.frnet.narod.ru/subscribe.html.
Спасибо за внимание. С уважением, Алексей Голубев.
Hosted by uCoz