【问题标题】:XSLT: How to generate an HTML table with 3 cells per rowXSLT:如何生成每行 3 个单元格的 HTML 表格
【发布时间】:2014-06-16 21:34:00
【问题描述】:

我按照this post from StackOverflow 的说明生成了一个每行包含 2 个单元格的 HTML 表格

但我想将我的数据分布在一个 HTML 表格中,每行三个单元格。我在帖子的 XSLT 样式表中更改了 sibling 的数字和 position 的计算,但它似乎不起作用。

这是我的 XML 源代码:

<?xml version="1.0" encoding="UTF-8"?>
<report>
    <frontmatter>
        <title>Relatório da 4ª Sessão Intercalar</title>
        <subtitle>Projecto Integrado de Engenharia de Linguagens</subtitle>

        <authors>
            <author>
                <name>Marina Mac</name>
                <nident>pg999</nident>
                <email>pg999@minho.pt</email>
                <url>https://www.linkedin.com</url>
                <affil>Universidade do Minho</affil>
                <photo>source/img/authors/marina.png</photo>
            </author>
            <author>
                <name>Nuno Vie</name>
                <nident>pg998</nident>
                <email>pg998@minho.pt</email>
                <url>https://www.linkedin.com</url>
                <photo>source/img/authors/nuno.jpg</photo>
                <affil>Universidade do Minho</affil>
            </author>
            <author>
                <name>Damien Va</name>
                <nident>pg997</nident>
                <photo>source/img/authors/damien.jpg</photo>
                <url>https://www.linkedin.com</url>
                <email>pg997@minho.pt</email>
                <affil>Universidade do Minho</affil>
            </author>
            <author>
                <name>Tiago Mach</name>
                <nident>pg996</nident>
                <email>pg996@minho.pt</email>
                <url>https://www.linkedin.com</url>
                <affil>Universidade do Minho</affil>
                <photo>source/img/authors/marina.png</photo>
            </author>
            <author>
                <name>Manuel Vie</name>
                <nident>pg995</nident>
                <email>pg995@minho.pt</email>
                <url>https://www.linkedin.com</url>
                <photo>source/img/authors/nuno.jpg</photo>
                <affil>Universidade do Minho</affil>
            </author>
            <author>
                <name>Damien Vim</name>
                <nident>pg994</nident>
                <photo>source/img/authors/damien.jpg</photo>
                <url>https://www.linkedin.com</url>
                <email>pg994@alunos.uminho.pt</email>
                <affil>Universidade do Minho</affil>
            </author>
        </authors>
    </frontmatter>
</report>

这是我的 XSLT 代码,它不符合我的要求:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs" version="2.0">

    <xsl:output indent="yes"/>

    <xsl:template match="/report">
        <html>
            <head>
                <meta charset="utf-8"/>
                <title><xsl:value-of select="frontmatter/title"/></title>
            </head>
            <body>
                <xsl:apply-templates select="frontmatter"/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="frontmatter" >
        <table width="100%">
            <tr align="center">
                <td>
                    <h1><xsl:value-of select="title"/></h1>
                </td>
            </tr>
            <xsl:if test="subtitle != '' ">
                <tr align="center">
                    <td>
                        <xsl:value-of select="subtitle"/>
                    </td>
                </tr>
            </xsl:if>
        </table>
        <hr width="90%"/>
        <h2>Autores</h2>
        <table width="90%" align="center">
            <xsl:apply-templates select="authors/author[position() mod 2 = 1]"/>
        </table>
    </xsl:template>

    <xsl:template match="authors/author">
        <tr>
            <xsl:for-each select=". | following-sibling::author[1]" >
                <td>
                    <p><xsl:value-of select="name"></xsl:value-of></p>
                </td>
            </xsl:for-each>
            <xsl:if test="not(following-sibling::author)">
                <td/>
                <td/>
            </xsl:if>
        </tr>
    </xsl:template>

</xsl:stylesheet>

如何修复我的样式表,使其生成每行包含 3 个单元格的 HTML 表格?

【问题讨论】:

标签: xml xslt


【解决方案1】:

如果您有 6 位作者,我假设您期望得到这样的结果:

  <table width="90%" align="center" border="1">
     <tr>
        <td>Marina Machado</td>
        <td>Damien Vaz</td>
        <td>Manuel Vieira</td>
     </tr>
     <tr>
        <td>Nuno Vieira</td>
        <td>Tiago Machado</td>
        <td>Damien Vaz</td>
     </tr>
  </table>

如果您有三位或更多作者,您将始终拥有三列。唯一少于三列的情况是,如果您有零个、一个或两个作者。列将从从左到右填充,因此如果您有 7 个作者,则最后一行在第一列中只有一个作者。

这将是五位作者的结果:

  <table width="90%" align="center" border="1">
     <tr>
        <td>Marina Machado</td>
        <td>Damien Vaz</td>
        <td>Manuel Vieira</td>
     </tr>
     <tr>
        <td>Nuno Vieira</td>
        <td>Tiago Machado</td>
     </tr>
  </table>

如果你有七个,将创建一个新行:

  <table width="90%" align="center" border="1">
     <tr>
        <td>Marina Machado</td>
        <td>Damien Vaz</td>
        <td>Manuel Vieira</td>
     </tr>
     <tr>
        <td>Nuno Vieira</td>
        <td>Tiago Machado</td>
        <td>William Shakespeare</td>
     </tr>
     <tr>
        <td>Heitor Villa-Lobos</td>
     </tr>
  </table>

在给定源 XML 的情况下,您可以使用此样式表生成满足这些要求的 HTML 表(我将其简化为代码的基本部分以处理分组问题 - 您可以稍后重新适应您的代码):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="cols">3</xsl:param> <!-- set the number of rows here -->

    <xsl:template match="frontmatter" >
        <table width="90%" align="center" border="1">
            <xsl:apply-templates select="authors/author[position() mod $cols = 1 or position() = 1]" mode="row"/>
        </table>
    </xsl:template>

    <xsl:template match="authors/author" mode="row">
        <tr>
            <xsl:apply-templates select=". | following-sibling::author[position() &lt; $cols]" mode="cell"/>
        </tr>
    </xsl:template>

    <xsl:template match="authors/author" mode="cell">
        <td>
            <xsl:value-of select="name"/>
        </td>
    </xsl:template>

</xsl:stylesheet>

如果您决定将作者分布在不同数量的列中,您可以传递具有不同值的cols 参数,或者将参数&lt;xsl:param name="cols"&gt;3&lt;/xsl:param&gt; 中的值替换为另一个值。例如,如果您将其更改为 4 列,它将像这样分配您的作者:

<table width="90%" align="center" border="1">
   <tr>
      <td>Marina Machado</td>
      <td>Nuno Vieira</td>
      <td>Damien Vaz</td>
      <td>Tiago Machado</td>
   </tr>
   <tr>
      <td>Manuel Vieira</td>
      <td>Damien Vaz</td>
   </tr>
</table>

在此模板中计算行数:

<xsl:template match="frontmatter" >
    <table width="90%" align="center" border="1">
        <xsl:apply-templates select="authors/author[position() mod $cols = 1 or position() = 1]" mode="row"/>
    </table>
</xsl:template>

XPath 表达式选择 position 除以列数余数为 1 的作者。对于三列,它将选择 &lt;author&gt; 元素编号 1、4、7、10,... 它还将选择 last 元素(可能不是其中之一)。它将调用第一个带有mode="row" 标记的author 模板。

该模板选择将包含每行单元格数据的元素:

<xsl:template match="authors/author" mode="row">
    <tr>
        <xsl:apply-templates select=". | following-sibling::author[position() &lt; $cols]" mode="cell"/>
    </tr>
</xsl:template>

它将选择当前 author (.),以及距离$cols - 1 的以下兄弟。如果$cols 为3,那么它将选择当前的author 和接下来的两个authors(如果存在)。这样,它将选择将放置在一行中的所有元素。例如,如果之前的模板选择了元素 1 和 4(3 列),则此模板将选择元素 1(当前)、2 和 3 作为第一列,并选择元素 4(当前)、5 和 6 作为第二列。此选择将用于应用 mode="cell" 模板,该模板仅在 &lt;td&gt; 块内打印作者的 name 子元素。

此解决方案适用于 XSLT 1.0 2.0。

你可以看到代码在这个XSLT Fiddle

【讨论】:

    【解决方案2】:

    您可以使用xsl:for-each-group 并使用group-ending-with 对作者元素进行分组,其中匹配的作者元素的position() mod 3 等于0。

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
    
        <xsl:output indent="yes"></xsl:output>
    
        <xsl:template match="/report">
            <html>
                <head>
                    <meta charset="utf-8"/>
                    <title><xsl:value-of select="frontmatter/title"/></title>
                </head>
                <body>
                    <xsl:apply-templates select="frontmatter"/>
                </body>
            </html>
        </xsl:template>
    
        <xsl:template match="frontmatter" >
            <table width="100%">
                <tr align="center">
                    <td>
                        <h1><xsl:value-of select="title"/></h1>
                    </td>
                </tr>
                <xsl:if test="subtitle != '' ">
                    <tr align="center">
                        <td>
                            <xsl:value-of select="subtitle"/>
                        </td>
                    </tr>
                </xsl:if>
            </table>
            <hr width="90%"/>
            <h2>Autores</h2>
            <table width="90%" align="center">
                <xsl:apply-templates select="authors"/>
            </table>
        </xsl:template>
    
        <xsl:template match="authors">
            <xsl:param name="cols" select="3" as="xs:integer"/>
            <xsl:for-each-group select="author" 
                              group-ending-with="author[position() mod $cols = 0]">
             <tr>
                 <xsl:for-each select="current-group()">
                     <td>
                         <p><xsl:value-of select="name"></xsl:value-of></p>
                     </td>
                 </xsl:for-each>
                 <!--ensure that there are an equal number of columns for every row
                     by generating empty cols if there is a "remainder" -->
                 <xsl:for-each select="0 to ($cols - count(current-group())-1)">
                     <td></td>
                 </xsl:for-each>
             </tr>   
            </xsl:for-each-group>
        </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

      猜你喜欢
      • 2021-08-23
      • 1970-01-01
      • 2016-05-26
      • 1970-01-01
      • 2013-03-29
      • 1970-01-01
      • 1970-01-01
      • 2023-02-20
      • 1970-01-01
      相关资源
      最近更新 更多