【问题标题】:xslt - limiting the rows in xslt transformationxslt - 限制 xslt 转换中的行
【发布时间】:2017-06-29 11:09:13
【问题描述】:

我对 xslt 比较陌生,一直在尝试使用 xml 结构创建表,但我发现很难限制每行中的字段数量..

<report>
<status>
    <statuscheck>
        <node>node1</node>
        <RAG>red</RAG>
        <url>http://www.google.com</url>
        <area>area1</area>
    </statuscheck>
    <statuscheck>
        <node>node2</node>
        <RAG>red</RAG>
        <url>http://www.google.com</url>
        <area>area1</area>
    </statuscheck>
    <statuscheck>
        <node>node3</node>
        <RAG>red</RAG>
        <url>http://www.google.com</url>
        <area>area1</area>
    </statuscheck>
    <statuscheck>
        <node>node4</node>
        <RAG>red</RAG>
        <url>http://www.google.com</url>
        <area>area1</area>
    </statuscheck>
    <statuscheck>
        <node>node5</node>
        <RAG>red</RAG>
        <url>http://www.google.com</url>
        <area>area1</area>
    </statuscheck>
    <statuscheck>
        <node>node1</node>
        <RAG>red</RAG>
        <url>http://www.google.com</url>
        <area>area2</area>
    </statuscheck>
</status>
<area>
    <area_name>area1</area_name>
    <area_name>area2</area_name>
</area>

我有以下 xslt,但有没有办法让它在每 4 个项目后开始一个新行?实际的 xml 每个区域最多有 20 个组件。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <head>
                <style>
                </style>
            </head>

            <body style="font-family: Sky Text;">
            <xsl:for-each select="/report/area/area_name">
                            <div style="font-size: 20px; font-weight: bold; margin: 10px 0 10px 0;"><xsl:value-of select="."/></div>
                            <table style="font-family: Sky Text; border-collapse: collapse; width: 960px;">
                                <tbody>
                                    <xsl:variable name="active_area" select="./text()"></xsl:variable>
                                    <xsl:for-each select="/report/status/statuscheck[area/text() = $active_area]">
                                        <td style="width: 240px; border: 1px solid black; text-align: center;" valign="middle">
                                            <xsl:attribute name="class">
                                                <xsl:value-of select="RAG"/>
                                            </xsl:attribute>
                                            <div style="margin: 10px; font-size: 16px;">
                                            <a>
                                                <xsl:attribute name="href">
                                                    <xsl:value-of select="url"/>
                                                </xsl:attribute>
                                                <xsl:value-of select="node"/>
                                            </a>
                                            </div>
                                        </td>
                                    </xsl:for-each>
                                </tbody>
                            </table>
                        </xsl:for-each> 
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>

提前致谢 加文

【问题讨论】:

  • 看到XSLT 1.0 Grouping Key for different Nodes and Elements 有一个非常相似的问题。 Related search 有更多类似问题。
  • 你有什么理由真的需要这张桌子吗?老实说,从您的 HTML 来看,您最好为每个 statuscheck 创建一个 div 块,然后使用 CSS 进行布局。
  • 谢谢.. 我对 html 很陌生,但是用谷歌搜索了 CSS 布局,看起来它可以满足我的需要.. 谢谢
  • 这应该相当简单——只需将单个 div 设置为 display:inline(或者可能是 display:inline-block),如果它们和包含的 div 具有适当的固定宽度,您应该最终得到四个行。

标签: xml xslt


【解决方案1】:

从风格的角度来看,我倾向于同意 @Flynn1179 的评论。 HTML 表格应该用于呈现表格数据,而不是严格用于布局目的。如果您的数据本质上是表格的,那么将它们映射到列和行是很自然的。但这并不意味着 XSLT 不能完成所介绍的工作。

然而,在讨论如何将 XSLT 应用于任务之前,我首先要指出的是,您的 XSLT 是像过程程序一样编写的,这不是 XSLT 的自然范例。即使在其中,它也未能利用一些 XSLT 特性,使其更清晰、更简单。一般建议:

  • 不要在xsl:apply-templates 的位置使用xsl:for-each,而可以使用单独的模板。
  • 除此之外,不要犹豫使用多个顶级模板。将一个大模板拆分为多个较小的模板就像将一个长函数拆分为几个较短的函数,在可读性、可维护性和可重用性方面具有许多相同的优势。
  • 优先使用文字结果元素和属性,而不是使用xsl:elementxsl:attribute。除非需要通过转换计算元素/属性名称,否则很少需要后者。
  • 请特别注意,文字结果属性的值是“属性值模板”,您可以在其中计算 XPath 表达式。
  • 了解xsl:keykey() 函数。这些比新手想象的要有用得多。除此之外,它们对于分组非常有用。

话虽如此,那么请考虑对样式表进行以下重构:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="html"/>

  <!-- group the statuscheck elements by their areas -->    
  <xsl:key name="area" match="/report/status/statuscheck" use="area"/>

  <!-- Provides the top-level document structure -->
  <xsl:template match="/">
    <html>
      <head>
        <style>
        </style>
      </head>
      <body style="font-family: Sky Text;">
        <!-- generate the body contents by transforming the area_name elements -->
        <xsl:apply-templates select="report/area/area_name"/>
      </body>
    </html>
  </xsl:template>

  <!-- Transforms area_name elements to produce area information.  Note that
       The template is not restricted to drawing on the subtree rooted at the
       context node. -->
  <xsl:template match="area_name">
    <xsl:variable name="active_area" select="string(.)"/>
    <div style="font-size: 20px; font-weight: bold; margin: 10px 0 10px 0;"><xsl:value-of select="$active_area"/></div>
    <table style="font-family: Sky Text; border-collapse: collapse; width: 960px;">
      <tbody>
        <!-- each row is generated by transforming a distinguished element;
             specifically, the first -->
        <xsl:apply-templates select="key('area', $active_area)[position() mod 4 = 1]" mode="row-head">
          <!-- this is one way to tell the template we're about to apply which are
               the other statuscheck element's in the context node's group: -->
          <xsl:with-param name="area-checks" select="key('area', $active_area)"/>
        </xsl:apply-templates>
      </tbody>
    </table>
  </xsl:template>

  <!-- transform a statuscheck node by emitting a <tr> element with a <td> child
       for each item in the row -->
  <xsl:template match="statuscheck" mode="row-head">
    <xsl:param name="area-checks"/>
    <xsl:variable name="row-start" select="position() * 4 - 3"/>
    <tr>
      <!-- the <td> elements are generated by a separate template -->
      <xsl:apply-templates select="$area-checks[position() >= $row-start and position() &lt; $row-start + 4]"/>
    </tr>
  </xsl:template>

  <!-- This template and the other matching the same elements are distinguished
       by their modes. -->
  <xsl:template match="statuscheck">
    <!-- Note how the value of the 'class' literal result attribute is expressed
         via an XPath expression.  You don't need xsl:attribute for that. -->
    <td class="{RAG}" style="width: 240px; border: 1px solid black; text-align: center;" valign="middle">
      <div style="margin: 10px; font-size: 16px;">
        <a href="{url}"><xsl:value-of select="node"/></a>
      </div>
    </td>
  </xsl:template>

</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 2014-09-17
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2017-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多