2010-04-07 5 views
8

У меня есть ситуации, когда петля через отсортированный набор узлов и применить шаблон на каждом из узлов:Сортировка набор узлов, прежде чем перейти к XSL: для-каждого

<div id="contractscontainer"> 
    <xsl:for-each select="document"> 
    <xsl:sort select="content[@name='ClientName']/text()" /> 
    <xsl:apply-templates select="." mode="client-contract" /> 
    </xsl:for-each> 
</div> 

Я хочу сделать что-то особенное с " первых "5 узлов в наборе узлов и визуализировать их вложенный элемент. Проблема в том, что они должны быть в том же порядке, как если бы они были отсортированы (как они находятся в цикле).

Я планировал сделать это, используя два элемента xsl:for-each, каждый из которых имеет правильные узлы, выбранные из набора. Я не могу сделать это, однако, так как они должны быть отсортированы перед тем я могу выбрать «первый» 5.

Пример:

<div id="contractscontainer"> 
    <div class="first-five"> 
    <xsl:for-each select="document[position() < 6]"> 
     <xsl:sort select="content[@name='ClientName']/text()" /> 
     <xsl:apply-templates select="." mode="client-contract" /> 
    </xsl:for-each> 
    </div> 
    <div class="rest-of-them"> 
    <xsl:for-each select="document[position() > 5]"> 
     <xsl:sort select="content[@name='ClientName']/text()" /> 
     <xsl:apply-templates select="." mode="client-contract" /> 
    </xsl:for-each> 
    </div> 
</div> 

Я не думаю, что это будет работать, потому что я 'm выбор узлов по положению до их сортировка, но я не могу использовать xsl:sort за пределами xsl:for-each.

Я подхожу к этому неправильно?

Edit: Мой текущий решение сортировать их и хранить отсортированный набор в другой переменной:

<xsl:variable name="sorted-docs"> 
    <xsl:for-each select="document"> 
    <xsl:sort select="content[@name='ClientName']/text()" /> 
    <xsl:copy-of select="." /> 
    </xsl:for-each> 
</xsl:variable> 

Он работает, но есть способ лучше?

+0

Хороший вопрос (+1). Ваше текущее решение неплохое, но переменная xsl: с отсортированными элементами имеет тип RTF, и вам нужно использовать функцию расширения xxx: node-set() в XSLT 1.0. Посмотрите мое решение, как это сделать без необходимости каких-либо функций расширения. –

+0

Да, я закончил с этим: using exsl: node-set(). Спасибо за ваше решение! –

ответ

14

Вот один из способов сделать это в XSLT 1.0 без необходимости использовать функцию xxx:node-set() расширения:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/*"> 
    <html> 
    <div class="first-five"> 
    <xsl:apply-templates select="num"> 
     <xsl:sort select="." data-type="number"/> 
     <xsl:with-param name="pStart" select="1"/> 
     <xsl:with-param name="pEnd" select="5"/> 
    </xsl:apply-templates> 
    </div> 
    <div class="rest-of-them"> 
    <xsl:apply-templates select="num"> 
     <xsl:sort select="." data-type="number"/> 
     <xsl:with-param name="pStart" select="6"/> 
    </xsl:apply-templates> 
    </div> 
    </html> 
</xsl:template> 

<xsl:template match="num"> 
    <xsl:param name="pStart"/> 
    <xsl:param name="pEnd" select="999999999999"/> 

    <xsl:if test="position() >= $pStart 
       and 
       not(position() > $pEnd)"> 
    <p><xsl:value-of select="."/></p> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 

Когда выше преобразование применяется на этой простой XML-документ:

<nums> 
    <num>5</num> 
    <num>3</num> 
    <num>6</num> 
    <num>8</num> 
    <num>4</num> 
    <num>1</num> 
    <num>9</num> 
    <num>2</num> 
    <num>7</num> 
    <num>10</num> 
</nums> 

Требуемый результат::

<html> 
    <div class="first-five"> 
     <p>1</p> 
     <p>2</p> 
     <p>3</p> 
     <p>4</p> 
     <p>5</p> 
    </div> 
    <div class="rest-of-them"> 
     <p>6</p> 
     <p>7</p> 
     <p>8</p> 
     <p>9</p> 
     <p>10</p> 
    </div> 
</html> 
+0

Решил мою проблему, спасибо –

Смежные вопросы