代码之家  ›  专栏  ›  技术社区  ›  hyperslug

将列表转换为动态确定列的表的XSLT

  •  0
  • hyperslug  · 技术社区  · 16 年前

    我需要这个XML,

    <list columns="3">
      <item>martin</item>
      <item>donald</item>
      <item>whistler</item>
      <item>mother</item>
      <item>carl</item>
      <item>liz</item>
      <item>cosmo</item>
    </list>
    

    看起来像这样:

    <table>
      <tr>
        <td>martin</td>
        <td>donald</td>
        <td>whistler</td>
      </tr>
      <tr>
        <td>mother</td>
        <td>carl</td>
        <td>liz</td>
      </tr>
      <tr>
        <td>cosmo</td>
        <td></td>
        <td></td>
      </tr>
    </table>
    

    什么时候? columns="4" ,应该如下所示:

    <table>
      <tr>
        <td>martin</td>
        <td>donald</td>
        <td>whistler</td>
        <td>mother</td>
      </tr>
      <tr>
        <td>carl</td>
        <td>liz</td>
        <td>cosmo</td>
        <td></td>
      </tr>
    </table>
    

    有什么关于XSLT文件应该是什么样子的提示吗?据我所知,它需要某种循环(递归?)但我不确定是否有更优雅的方式。

    3 回复  |  直到 11 年前
        1
  •  8
  •   Tim C    16 年前

    我将采用的方法是通过在每个项目上使用position()的“mod”函数来匹配第一、第四、第七位置中的项目。

    匹配每一个这样的项之后,只需根据列计数循环遍历以下同级。

    对于最后一行,如果可能没有足够的项目来完成该行,则根据最后一行中的项目数,有一个递归模板来添加空单元格。

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
       <!-- Global variable to get column count -->
       <xsl:variable name="columns" select="number(/list/@columns)"/>
    
       <!-- Match the root node -->
       <xsl:template match="list">
          <table>
             <!-- Match items in the 1st, 4th, 7th positions, etc (or whatever the column variable holds) -->
             <xsl:apply-templates select="item[position() mod $columns = 1]"/>
          </table>
       </xsl:template>
    
       <xsl:template match="item">
          <tr>
             <!-- Output the current item -->
             <td>
                <xsl:value-of select="."/>
             </td>
             <!-- Output the following items based on the number of required columns -->
             <xsl:for-each select="following-sibling::item[position() &lt; $columns]">
                <td>
                   <xsl:value-of select="."/>
                </td>
             </xsl:for-each>
             <!-- Add in any empty cells if numberof following items is not sufficient -->
             <xsl:call-template name="emptycell">
                <xsl:with-param name="cellcounter" select="count(following-sibling::item[position() &lt; $columns]) + 1" />
             </xsl:call-template>
          </tr>
       </xsl:template>
    
       <!-- Recursive template to add in empty cells when there are not enough items to complete a row -->
       <xsl:template name="emptycell">
          <xsl:param name="cellcounter" />
          <xsl:if test="$cellcounter &lt; $columns">
             <td></td>
             <xsl:call-template name="emptycell">
                <xsl:with-param name="cellcounter" select="$cellcounter + 1" />
             </xsl:call-template>
          </xsl:if>   
       </xsl:template>
    
    </xsl:stylesheet>
    
        2
  •  0
  •   ankon    16 年前

    一些有用但看起来有点难看的东西:滥用位置()。

    <xsl:param name="columns">4</xsl:param>
    <xsl:template match="list">
      <xsl:variable name="theList" select="."/>
      <xsl:for-each select="//*[position()<(count(item) / $columns)]>
        <xsl:variable name="idx" select="position()"/>
        <tr>
        <xsl:for-each select="//*[position()<$columns]">
           <td><xsl:value-of select="$theList/item[position() + $idx * $columns]"/></td>
        </xsl:for-each>
        </tr>
      </xsl:for-each>
    </xsl:template>
    

    还有其他方法:例如,首先选择列表中所有与其余0除以列的节点,然后遍历这些节点。

    http://www.ibm.com/developerworks/library/x-tipnodst.html 对于上述技术的更详细描述。

        3
  •  0
  •   Ms2ger    16 年前

    我建议使用 CSS3 columns . 这个规范很快就会成为一个候选建议(实现阶段的调用),并且已经在Gecko和WebKit(Firefox、Safari、Chrome)中实现,带有供应商前缀。

    代码:

    ul { -moz-column-count: 3; -webkit-column-count: 3; }