XSLT 1.0 Группировка по нескольким значениям на нескольких уровнях - PullRequest
2 голосов
/ 14 марта 2011
  • отредактировано в ответ на комментарии *

Здравствуйте,

Я нуб XSLT и мне нужна помощь. Я пытаюсь сделать комбинацию фильтра / группы с XSLT 1.0 (не могу использовать XSLT 2.0 для этого приложения).

Вот пример xml

<entry>
  <item>
    <name>Widget 2</name>
    <rank>2</rank>
    <types>
       <type>Wood</type>
       <type>Fixed</type>
       <type>Old</type>
    </types>
  </item>
   <item>
    <name>Widget 1</name>
    <rank>2</rank>
    <types>
       <type>Metal</type>
       <type>Broken</type>
       <type>Old</type>
    </types>
  </item>
  <item>
    <name>Widget 3</name>
    <rank>1</rank>
    <types>
       <type>Metal</type>
       <type>New</type>
    </types>
  </item>
</entry>

Теперь я хочу вывести html, где я получаю подмножество XML на основе <type>, а затем группируюсь по рангу. Например, если пользователь выбирает все элементы с типом «Металл», результат должен быть следующим:

<p class="nospace"><font color="#800000">
<b>Rank 1</b></font></p>
<li id="mylist"><b>Widget 3</b></li>
<br\>

<p class="nospace"><font color="#800000">
<b>Rank 2</b></font></p>
<li id="mylist"><b>Widget 1</b></li>
<br\>

из, если пользователь выбирает тип Old, вывод будет

<p class="nospace"><font color="#800000">
<b>Rank 2</b></font></p>
<li id="mylist"><b>Widget 1</b></li>
<li id="mylist"><b>Widget 2</b></li>
<br\>

Я могу сгруппировать, используя ключи по рангу достаточно легко, но попытка сделать и то и другое не работает. Вот пример xslt, который я пробовал:

<xsl:param name="typeParam"/>
<xsl:key name="byRank" use="rank" match="item"/>

<xsl:for-each select="item[count(.|key('byRank',rank)[1])=1]">
  <xsl:sort data-type="number" select="rank"/>
  <xsl:for-each select="key('byRank',rank)">
    <xsl:sort select="name"/>
    <xsl:if test="count(rank)&gt;0">
      <p class="nospace"><font color="#800000"><b>Rank<xsl:value-of select="rank"/></b></font></p>
      <xsl:for-each select="types[types=$typeParam]">
        <li id="mylist"><b><xsl:value-of select="../name"/></b></li>
      </xsl:for-each>
    <br/>
  </xsl:if>
</xsl:for-each>
</xsl:for-each>

В результате я получаю желаемое подмножество моего xml, но оно также отображает все различные значения ранга. Я хочу ограничить его только рангами типа, указанного в $ typeParam.

Я попытался переместить оператор for-each в код ранее, а также изменить оператор if, чтобы выбрать для $ typeParam, но ни один из них не работает. Я также попытался объединить мой ключ с рангом и типом, но, похоже, он тоже не работает (он работает, только если тип в $ typeParam - первый дочерний элемент под типами).

Спасибо

Джефф

1 Ответ

2 голосов
/ 14 марта 2011

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kItemByRank" match="item" use="rank"/>
    <xsl:param name="pType" select="'Old'"/>
    <xsl:template match="entry">
        <xsl:for-each select="item[count(.|key('kItemByRank',rank)[1])=1]">
            <xsl:sort select="rank" data-type="number"/>
            <xsl:variable name="vGroup" select="key('kItemByRank',rank)[
                                                   types/type = $pType
                                                ]"/>
            <xsl:if test="$vGroup">
                <p class="nospace">
                    <font color="#800000">
                        <b>
                            <xsl:value-of select="concat('Rank ',rank)"/>
                        </b>
                    </font>
                </p>
                <xsl:apply-templates select="$vGroup">
                    <xsl:sort select="name"/>
                </xsl:apply-templates>
                <br/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="item">
        <li id="mylist">
            <b>
                <xsl:value-of select="name"/>
            </b>
        </li>
    </xsl:template>
</xsl:stylesheet>

Выход:

<p class="nospace">
    <font color="#800000">
        <b>Rank 1</b>
    </font>
</p>
<li id="mylist">
    <b>Widget 3</b>
</li>
<br />
<p class="nospace">
    <font color="#800000">
        <b>Rank 2</b>
    </font>
</p>
<li id="mylist">
    <b>Widget 1</b>
</li>
<br />

И с pType параметром, установленным на 'Old', вывод:

<p class="nospace">
    <font color="#800000">
        <b>Rank 2</b>
    </font>
</p>
<li id="mylist">
    <b>Widget 1</b>
</li>
<li id="mylist">
    <b>Widget 2</b>
</li>
<br />
...