Как использовать для цикла в xslt

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

Например: 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>

помогите мне сделать это

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

5
задан Dimitre Novatchev 3 December 2012 в 12:44
поделиться

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> 
-4
ответ дан 13 December 2019 в 22:03
поделиться

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

<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>
7
ответ дан 13 December 2019 в 22:03
поделиться

Я не уверен на 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>
-1
ответ дан 13 December 2019 в 22:03
поделиться

О проблемах любой сложности в 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>

И вы можете параметризовать количество колонок, поместив его в переменную, как это сделал Дмитрий в своем примере.

8
ответ дан 13 December 2019 в 22:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: