XSL: применение шаблона с «внутренним» условием

Содержание

Часто бывает нужно применить шаблон для элемента только если этот элемент (или его содержимое) удовлетворяет некоторому условию. Простой пример: применить шаблон для элемента <Brands> если внутри есть хотя бы один элемент <Brand>. Рассмотрим несколько вариантов как можно сделать эту проверку.

Вариант 1

<xsl:template match="Something">
    <xsl:if test="Brands/Brand">
        <xsl:apply-templates select="Brands"/>
    </xsl:if>
</xsl:template>

<xsl:template match="Brands">
    <h2>Производители</h2>
    <ul>
        <xsl:apply-templates select="Brand"/>
    </ul>
</xsl:template>

Неудачное решение, поскольку, написав проверку в шаблоне для <Something>, мы поместили в этот шаблон знание об особенности трансформации <Brands>.

Вариант 2

<xsl:template match="Something">
    <xsl:apply-templates select="Brands[Brand]"/>
</xsl:template>

<xsl:template match="Brands">
    <h2>Производители</h2>
    <ul>
        <xsl:apply-templates select="Brand"/>
    </ul>
</xsl:template>

Немного компактнее, но проблема первого варианта осталась.

Вариант 3

<xsl:template match="Something">
    <xsl:apply-templates select="Brands"/>
</xsl:template>

<xsl:template match="Brands">
    <xsl:if test="Brand">
        <h2>Производители</h2>
        <ul>
            <xsl:apply-templates select="Brand"/>
        </ul>
    </xsl:if>
</xsl:template>

Гораздо лучше. Шаблон для <Something> просто вызывает шаблон для <Brands>, не заморачиваясь о внутреннем устройстве <Brands>. Шаблон для <Brands> сам разбирается как трансформировать <Brands>.

Вариант 4

<xsl:template match="Something">
    <xsl:apply-templates select="Brands"/>
</xsl:template>

<xsl:template match="Brands"/>

<xsl:template match="Brands[Brand]">
    <h2>Производители</h2>
    <ul>
        <xsl:apply-templates select="Brand"/>
    </ul>
</xsl:template>

Я предпочитаю этот вариант. Он также хорошо работает и в случае с несколькими условиями — вместо громоздкого xsl:choose мы получаем компактные шаблончики.

<xsl:template match="Brands"/>

<xsl:template match="Brands[Brand]">
    <h2>Производители</h2>
    <ul>
        <xsl:apply-templates select="Brand"/>
    </ul>
</xsl:template>

<xsl:template match="Brands[count(Brand) > 10]">
    <h2>Много производителей</h2>
    <!-- Выводим бренды в три колонки -->
</xsl:template>


12 октября 2008 г.
Степан Резников
http://sreznikov.blogspot.com/2008/10/xsl.html