【问题标题】:XSL: Transforming xml into a sorted multicolumn html tableXSL:将 xml 转换为已排序的多列 html 表
【发布时间】:2011-04-04 20:08:43
【问题描述】:

我正在研究与此处介绍的问题类似的问题

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>

我曾尝试在各种应用模板中插入命令,但这不起作用。

想法?

杰夫

来自 cmets 的更新

我想输出一个多列表 条目所在的 3 列 按字母顺序垂直

【问题讨论】:

    标签: xml xslt


    【解决方案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>
    

    【讨论】:

    • @Jeffrey-Hersh:在 SO,您应该接受两个答案之一——@Alejandro 和我都提供了正确和好的答案。要接受答案,请单击它旁边的绿色复选标记。
    【解决方案2】:

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

    <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 用于两相变换的扩展函数。

    【讨论】:

    • 谢谢,但这不太行。同时,它适用于我作为示例指定的 XML 的顺序。但是,假设我在 XML 的任意位置添加了一个项目 F。 XSL 不会按照我需要的顺序对其进行排序(第一行:A C E,第二行:B D F)。
    • @Jeffrey Hersh:你写了“不太好用”,还写了“很好用”。我认为你需要下定决心......如果涉及到一些排序,你应该在你的问题中描述它。
    • 对不起,我不清楚。您的解决方案适用于我提出的说明性示例,但在一般情况下不起作用。一般情况是我需要的。
    • 对不起...具体来说,我有一个长 xml 文件,其中包含各种节点和各种子字段。我想对其中一个子字段进行排序,以便在指定的字段上有一个按字母顺序排列的多列表。因此,在我发布的说明性案例中,我的 xml 可以有任意数量的 条目,并且这些条目可以按任意顺序排列。我想输出一个包含 3 列的多列表,其中条目垂直按字母顺序排列。这就是我所说的一般情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 2020-05-04
    • 1970-01-01
    • 2013-06-14
    • 1970-01-01
    • 2014-09-10
    • 2012-10-24
    相关资源
    最近更新 更多