XSL:将xml转换为已排序的多列html表

时间:2011-04-04 20:08:43

标签: xml xslt

我正在考虑与此处涉及的问题类似的问题

Transforming List into a 2-D Table

但有轻微的皱纹。我的XML没有任何特定的顺序,我想将它排序显示。例如,我的XML是

<items>  
  <item>A</item>  
  <item>C</item>  
  <item>E</item>  
  <item>B</item>  
  <item>D</item> 
  <!-- ... any number of item nodes ... -->
<item>  

我希望我的输出是(为了说明目的,我忽略了非命名节点)

<table>
    <tr>
        <td>A</td>
        <td>C</td>
        <td>E</td>
    </tr>
    <tr>
        <td>B</td>
        <td>D</td>
        <td />
    </tr>
</table>

我基于此的XSL来自上面的链接(我需要使用XSL 1.0):

    

<xsl:template match="/*">
    <table>
        <xsl:call-template name="make-columns">
            <xsl:with-param name="nodelist" select="item"/>
        </xsl:call-template>
    </table>
</xsl:template>

<xsl:template name="make-columns">
    <xsl:param name="nodelist"/>
    <xsl:param name="columns-number" select="3"/>

    <tr>
        <xsl:apply-templates select="$nodelist[
                        not(position() > $columns-number)
                        ]"/>
        <xsl:if test="count($nodelist) &lt; $columns-number">
            <xsl:call-template name="empty-cells">
                <xsl:with-param name="finish" 
                                select="$columns-number - count($nodelist)"/>
            </xsl:call-template>
        </xsl:if>
    </tr>

    <!-- If some nodes are left, recursively call current
    template, passing only nodes that are left -->
    <xsl:if test="count($nodelist) > $columns-number">
        <xsl:call-template name="make-columns">
            <xsl:with-param name="nodelist" select="$nodelist[
                                    position() > $columns-number
                                    ]"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:template match="item">
    <td>
        <xsl:apply-templates/>
    </td>
</xsl:template>

<xsl:template name="empty-cells">
    <xsl:param name="finish"/>
    <td/>
    <xsl:if test="not($finish = 1)">
        <xsl:call-template name="empty-cells">
            <xsl:with-param name="finish" select="$finish - 1"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

我尝试在各种apply-templates中插入命令,但这不起作用。

想法?

杰夫

从评论中更新

  

我想输出一个多语言表   条目有3列   按字母顺序垂直

2 个答案:

答案 0 :(得分:1)

更新:现在,解释了新的requeriment,这个样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="msxsl">
    <xsl:strip-space elements="*"/>
    <xsl:param name="pColumns" select="3"/>
    <xsl:template match="items">
        <xsl:variable name="vrtfChilds">
            <xsl:for-each select="*">
                <xsl:sort/>
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </xsl:variable>
        <xsl:variable name="vChilds" select="msxsl:node-set($vrtfChilds)/*"/>
        <xsl:variable name="vRows" 
                      select="ceiling(count($vChilds) div $pColumns)"/>
        <table>
            <xsl:for-each select="$vChilds[$vRows >= position()]">
                <tr>
                    <xsl:call-template name="columns">
                        <xsl:with-param name="pRows" select="$vRows"/>
                    </xsl:call-template>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>
    <xsl:template name="columns">
        <xsl:param name="pData" select="."/>
        <xsl:param name="pColumn" select="$pColumns"/>
        <xsl:param name="pRows" select="0"/>
        <xsl:if test="$pColumn">
            <td>
                <xsl:apply-templates select="$pData"/>
            </td>
            <xsl:call-template name="columns">
                <xsl:with-param name="pData"
                     select="$pData/following-sibling::*[$pRows]"/>
                <xsl:with-param name="pColumn" select="$pColumn - 1"/>
                <xsl:with-param name="pRows" select="$pRows"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

输出:

<table>
    <tr>
        <td>A</td>
        <td>C</td>
        <td>E</td>
    </tr>
    <tr>
        <td>B</td>
        <td>D</td>
        <td></td>
    </tr>
</table>

注意node-set扩展功能,用于两阶段转换。

答案 1 :(得分:1)

此转化

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

 <xsl:param name="pNumCols" select="3"/>

 <xsl:variable name="vNumRows" select=
      "ceiling(count(/*/*) div $pNumCols)"/>

 <xsl:variable name="vrtfSorted">
   <xsl:for-each select="/*/*">
    <xsl:sort/>
    <xsl:copy-of select="."/>
   </xsl:for-each>
 </xsl:variable>

 <xsl:variable name="vSorted"
      select="ext:node-set($vrtfSorted)/*"/>

 <xsl:template match="/">
  <table>
   <xsl:apply-templates select=
     "$vSorted[not(position() > $vNumRows)]"/>
  </table>
 </xsl:template>

 <xsl:template match="item">
  <tr>
   <xsl:apply-templates select=
   "(.|following-sibling::*[position() mod $vNumRows =0])/text()"/>
  </tr>
 </xsl:template>

 <xsl:template match="text()">
  <td><xsl:value-of select="."/></td>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<items>
    <item>A</item>
    <item>C</item>
    <item>E</item>
    <item>B</item>
    <item>D</item>
</items>

会产生想要的正确结果:

<table>
  <tr>
    <td>A</td>
    <td>C</td>
    <td>E</td>
  </tr>
  <tr>
    <td>B</td>
    <td>D</td>
  </tr>
</table>