xslt - 限制xslt转换中的行

时间:2017-06-29 11:09:13

标签: xml xslt

我对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>
提前谢谢 加文

1 个答案:

答案 0 :(得分:1)

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

在讨论如何将XSLT应用于任务之前,我应首先指出您的XSLT编写过程程序,而不是XSLT的自然范例。即便在此范围内,它也无法利用一些可以使其更清晰,更简单的XSLT功能。一般建议:

  • 请勿xsl:for-each使用xsl:apply-templates,而是可以使用单独的模板。
  • 除此之外,请不要犹豫使用多个顶级模板。将一个大模板拆分成多个较小的模板就像将一个长函数分成几个较短的函数,在可读性,可维护性和可重用性方面具有许多相同的优点。
  • 首选使用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>