2010-05-10 10 views
5

Как использовать xsl:for-each в XSLT, чтобы получить значение итеративно из файла XML и Dispaly его в таблице fromatКак использовать цикл в XSLT

Например: файл XML, как

<order> 
    <item name ="a"/> 
    <item name ="b"/> 
    <item name ="c"/> 
    <item name ="d"/> 
    <item name ="e"/> 
    <item name ="f"/> 
    <item name ="g"/> 
</order> 

и вывод должен быть

a b c d 

    e f g 

цикл должен рассчитывать деталь и если он divisble на 4 он

должен закрыть текущую строку и добавить новую строку и так далее ..

я использую следующий XSLT для этого

, но я не могу отобразить его в виде таблицы

<xsl:template match="/"> 
    <html> 
    <body> 
    <xsl:call-template name ="incr"> 
     <xsl:with-param name ="value">1</xsl:with-param> 
     <xsl:with-param name ="limit"> 
      <xsl:value-of select ="count(//item)"/> 
     </xsl:with-param> 
     </xsl:call-template> 
    </body> 
</html> 
</xsl:template > 
<xsl:template name="incr"> 
    <xsl:param name="value"/> 
    <xsl:param name ="limit"/> 
    <xsl:if test ="$value!=$limit+1"> 
    <xsl:value-of select ="//item[$value]/@name"/> 
    <xsl:if test ="$value mod 4 =0"> 
     <br/> 
     <br/> 
    </xsl:if> 
    <xsl:call-template name ="incr"> 
     <xsl:with-param name ="value" select ="$value+1"/> 
     <xsl:with-param name ="limit" select ="$limit"/> 
    </xsl:call-template> 
    </xsl:if> 

</xsl:template> 

пожалуйста помочь мне сделать это

заранее спасибо

+1

Что вы сделали для решения этой проблемы до сих пор? Это выглядит как домашнее задание. –

+0

+1 для вопроса. См. Мой ответ для полного и правильного решения. :) –

ответ

-4
<table> 
<tr> 
    <xsl:for-each select="//order/item"> 
    <td> 
    <xsl:value-of select ="current()/@name"/> 
    </td> 
    <xsl:if test="position() mod 4 = 0"> 
    <xsl:text disable-output-escaping="yes"><![CDATA[</tr><tr>]]></xsl:text> 
    </xsl:if> 
    </xsl:for-each> 
</tr> 
</table> 
+0

его дает правильный выход, но это правильный путь? –

+0

Нет. В этом смысле безумие. Открывающий и закрывающий тег объявляет одну вещь. Вышеупомянутое решение - это ловушка. –

-1

Я не уверен на 100%, но ниже код должен это сделать:

<table> 
    <tr> 
    <xsl:for-each select="//order/item"> 
     <td> 
     <xsl:value-of select ="current()/@name"/> 
     </td> 
    <xsl:if test="position() mod 4 = 0"> 
    <xsl:text disable-output-escaping="yes"><![CDATA[</tr><tr>]]></xsl:text> 
    </xsl:if> 
    </xsl:for-each> 
    <xsl:variable name="item_count_mod4" select="count(//order/item) mod 4"/> 
    <xsl:choose> 
     <xsl:when test="$item_count_mod4 = 1"> 
     <td></td><td></td><td></td> 
     </xsl:when> 
     <xsl:when test="$item_count_mod4 = 2"> 
     <td></td><td></td> 
     </xsl:when> 
     <xsl:when test="$item_count_mod4 = 3"> 
     <td></td> 
     </xsl:when> 
     <xsl:otherwise> 
     </xsl:otherwise> 
    </xsl:choose> 
    </tr> 
</table> 
+0

мы не можем сделать это , так как не может быть правильно закрыт и отображается ошибка –

+0

Вы абсолютно правы о проблеме «». Сложность CDATA легко решает. Вы можете проверить измененный код выше. Я тестировал XML-блокнот, и он успешно преобразуется. – Cagdas

+1

Это абсолютно неправильный способ сделать это. –

7

Это преобразование:

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

<xsl:variable name="vNumCols" select="4"/> 

<xsl:template match="/*"> 
    <table> 
    <xsl:for-each select= 
    "item[position() mod $vNumCols = 1]"> 

    <tr> 
     <xsl:for-each select= 
     ". | following-sibling::* 
       [not(position() >= $vNumCols)]"> 
     <td><xsl:value-of select="@name"/></td> 
     </xsl:for-each> 
    </tr> 
    </xsl:for-each> 
    </table> 
</xsl:template> 
</xsl:stylesheet> 

при нанесении на предоставленном документе XML, производит нужные правильные результаты:

<table> 
    <tr> 
     <td>a</td> 
     <td>b</td> 
     <td>c</td> 
     <td>d</td> 
    </tr> 
    <tr> 
     <td>e</td> 
     <td>f</td> 
     <td>g</td> 
    </tr> 
</table> 
+0

Хорошее решение, но я нашел проблему, если «vNumCols» установлен в «1», он ничего не отобразит. –

+2

@ XiaodanMao, Да, и та же проблема существует для '$ vNumCols', установленного в 0. Это связано с тем, что по этой причине такие значения не входят в область видимости. Вы можете обнаружить, что любое решение о том, как полить воду в N чашек, не работает, если температура составляет -1 градус Цельсия. –

+0

Благодарим за отзыв. –

8

Путь думать о проблемах любой сложности в XSLT не «как я напишу программу для создания Y, учитывая X как входную?» а скорее, «учитывая выход Y, какой X я собираюсь преобразовать, чтобы произвести его?» Нелегкий принцип - понять (или сформулировать), но как только вы его получите, то, что кажется трудным в XSLT, становится тривиальным.

Если выход серии tr элементов, как это:

<tr> 
    <td>a</td><td>b</td><td>c</td> 
</tr> 
<tr> 
    <td>d</td><td>e</td><td>f</td> 
</tr> 
<tr> 
    <td>g</td><td>h</td><td>i</td> 
</tr> 
<tr> 
    <td>j</td><td/><td/> 
</tr> 

есть, по сути, четыре выходных элементов. Таким образом, должно быть четыре входных элемента.

Первый вопрос, который четыре? Довольно ясно, что это будет 1, 4, 7 и 10, т. Е. Каждые 3 элемента, начиная с первого. Таким образом, отправной точкой является преобразование этих четырех элементов:

<xsl:apply-templates select="/order/item[position() mod 3 = 1]"/> 

Хорошо, а теперь, когда мы выбрали каждый третий элемент, как мы собираемся создать tr из него и элементы сразу после него? Используя following-sibling ось:

<xsl:template match="item"> 
    <tr> 
     <td><xsl:value-of select="@name"/></td> 
     <td><xsl:value-of select="following-sibling::item[1]/@name"/></td> 
     <td><xsl:value-of select="following-sibling::item[2]/@name"/></td> 
    </tr> 
</xsl:template> 

Это хорошо, насколько это идет. Но есть много дублированного кода, и вам нужно изменить, если хотите (скажем) изменить количество столбцов от 3 до 6.Вы можете устранить дублированный код, сделав другой шаблон:

<xsl:template match="item"> 
    <tr> 
     <xsl:apply-templates select="@name | following-sibling::item[position() &lt;= 3]/@name"/> 
    </tr> 
</xsl:template> 

<xsl:template match="@name"> 
    <td><xsl:value-of select="."/></td> 
</xsl:template> 

И вы можете параметризовать количество столбцов, поместив его в переменной, как Dimitre сделал в своем примере.

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