首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >XSLT 2.0:创建具有动态行和列的HTML表格的问题

XSLT 2.0:创建具有动态行和列的HTML表格的问题
EN

Stack Overflow用户
提问于 2019-06-16 04:25:58
回答 3查看 193关注 0票数 1

我正在创建一个HTML表,它基于动态列(Hostname)和行(VLAN)。在中的第一个位置数据(所有主机为1行)写入到表中后,我遇到了一个问题;选择第二个位置数据很好,但是$vCol变量将它带回到$vCols变量的第一行。

感谢你能提供的任何方向。谢谢

XSLT-2.0代码:

代码语言:javascript
复制
<?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:key name="kHostNameByValue" match="Hostname" use="."/>
  <xsl:key name="kVLAN" match="Hostname" use="."/>
  <xsl:variable name="vCols" select="/*/*/Hostname[generate-id()=generate-id(key('kHostNameByValue',.)[1])]"/> 

  <xsl:variable name="vMaxRows">
      <xsl:for-each select="$vCols">
        <xsl:sort data-type="number" order="descending" select="count(key('kVLAN', .))"/>
          <xsl:if test="position() = 1">
             <xsl:value-of select="count(key('kVLAN', .))"/>
          </xsl:if>
      </xsl:for-each>
  </xsl:variable>

    <xsl:template match="DocumentRoot">
      <table border="1">
        <!--  Print out column headings by Hostname    -->
       <tr>
            <xsl:apply-templates select="$vCols"/>
       </tr>

          <!--  Print out VLANs by Hostname    -->
          <xsl:for-each-group select="(//Row)[not(position() > $vMaxRows)]" group-by="VLAN">
              <tr>     
                 <xsl:variable name="vPos" select="position()"/>
                  <!-- Issue on 2nd position when $vCols goes back to 1st hostname at line 3 -->
                  <xsl:for-each select="$vCols"> 
                    <td>  
                        <xsl:value-of select="..[$vPos]/VLAN"/>
                    </td>    
                 </xsl:for-each> 
              </tr>
            </xsl:for-each-group>
      </table>
    </xsl:template>

    <xsl:template match="Hostname">
        <td>
            <b>
                <xsl:value-of select="." />
            </b>
        </td>   
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

以下是示例XML数据。

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<DocumentRoot>
    <Row>
        <Hostname>switch-1</Hostname>
        <HostIP>10.29.178.102</HostIP>
        <VLAN>10</VLAN>
        <VLANName>VLAN-10</VLANName>
    </Row>
    <Row>
        <Hostname>switch-1</Hostname>
        <HostIP>10.29.178.102</HostIP>
        <VLAN>500</VLAN>
        <VLANName>VLAN-500</VLANName>
    </Row>
    <Row>
        <Hostname>switch-2</Hostname>
        <HostIP>10.29.178.103</HostIP>
        <VLAN>11</VLAN>
        <VLANName>VLAN-11</VLANName>
    </Row>
    <Row>
        <Hostname>switch-2</Hostname>
        <HostIP>10.29.178.103</HostIP>
        <VLAN>501</VLAN>
        <VLANName>VLAN-500</VLANName>
    </Row>
    <Row>
        <Hostname>switch-3</Hostname>
        <HostIP>10.29.170.1</HostIP>
        <VLAN>15</VLAN>
        <VLANName>VLAN-15</VLANName>
    </Row>
    <Row>
        <Hostname>switch-3</Hostname>
        <HostIP>10.29.170.1</HostIP>
        <VLAN>25</VLAN>
        <VLANName>VLAN-25</VLANName>
    </Row>
    <Row>
        <Hostname>switch-3</Hostname>
        <HostIP>10.29.170.1</HostIP>
        <VLAN>35</VLAN>
        <VLANName>VLAN-35</VLANName>
    </Row>
    <Row>
        <Hostname>switch-3</Hostname>
        <HostIP>10.29.170.1</HostIP>
        <VLAN>45</VLAN>
        <VLANName>VLAN-45</VLANName>
    </Row>
    <Row>
        <Hostname>switch-3</Hostname>
        <HostIP>10.29.170.1</HostIP>
        <VLAN>55</VLAN>
        <VLANName>VLAN-55</VLANName>
    </Row>
</DocumentRoot>

输出(实际和所需):

EN

回答 3

Stack Overflow用户

发布于 2019-06-16 05:03:32

我认为使用group by可能会让事情变得更加复杂。基本上,对于每一行,您需要迭代所有列并输出单元格(如果存在),否则输出一个空单元格。这意味着您应该遍历索引,而不是行元素:

代码语言:javascript
复制
<xsl:for-each select="1 to $numRows">
    <xsl:variable name="rowIndex" select="position()" />
    <tr>
    <xsl:for-each select="$vCols">
        <xsl:variable name="cell" select="//Row[string(Hostname) = .][position() = $rowIndex]" />
        <xsl:apply-templates select="$cell">
        <xsl:if test="not($cell)">
            <td></td>
        </xsl:if>
    </xsl:for-each>
    <tr>
</xsl:for.each>
票数 1
EN

Stack Overflow用户

发布于 2019-06-16 16:31:04

首先,我认为您的maxRows变量可以简化为

代码语言:javascript
复制
<xsl:variable name="maxRows" select="max(//Row/count(key(hostNameByValue, Hostname)))" />

其中,我定义了如下hostNameByValue密钥:

代码语言:javascript
复制
<xsl:key name="hostNameByValue" match="Row" use="Hostname"/>

还可以使用distinct-values获取不同的列名

代码语言:javascript
复制
<xsl:variable name="cols" select="distinct-values(//Row/Hostname)" />

因此,假设$rowNum是当前数字(在<xsl:for-each select="1 to $maxRows">块中,获取当前像元值的代码如下所示

代码语言:javascript
复制
<xsl:for-each select="$cols">
  <th><xsl:value-of select="key('hostNameByValue', ., $doc)[position() = $rowNum]/VLAN"/></th>
</xsl:for-each>

(其中$doc是对初始XML文档的引用,因为在xsl:for-each中现在是一系列原子值)

试试这个XSLT

代码语言:javascript
复制
<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 method="xml" indent="yes" />

  <xsl:key name="hostNameByValue" match="Row" use="Hostname"/>

  <xsl:variable name="cols" select="distinct-values(//Row/Hostname)" />
  <xsl:variable name="maxRows" select="max(//Row/count(key('hostNameByValue', Hostname)))" />
  <xsl:variable name="doc" select="/" />

  <xsl:template match="DocumentRoot">
    <table>
    <tr>
      <xsl:for-each select="$cols">
        <th><xsl:value-of select="."/></th>
      </xsl:for-each>
      </tr>
      <xsl:for-each select="1 to $maxRows">
        <xsl:variable name="rowNum" select="position()"/>
        <tr>
          <xsl:for-each select="$cols">
            <th><xsl:value-of select="key('hostNameByValue', ., $doc)[position() = $rowNum]/VLAN"/></th>
          </xsl:for-each>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>

http://xsltfiddle.liberty-development.net/6r5Gh3N上查看它的实际效果

票数 1
EN

Stack Overflow用户

发布于 2019-06-16 21:06:08

我不认为在XSLT2或3中,一旦使用了for-each-group,就需要任何键,您只需存储分组结果,然后对其进行处理,例如,在XSLT2或3中将分组结果存储为XML,您可以使用

代码语言:javascript
复制
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>.NET XSLT Fiddle Example</title>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="DocumentRoot">
      <table>
          <xsl:variable name="cols" as="element(col)*">
              <xsl:for-each-group select="Row" group-by="Hostname">
                  <col name="{current-grouping-key()}">
                      <xsl:sequence select="current-group()"/>
                  </col>
              </xsl:for-each-group>
          </xsl:variable>
          <thead>
              <tr>
                  <xsl:for-each select="$cols">
                      <th>{@name}</th>
                  </xsl:for-each>
              </tr>
          </thead>
          <tbody>
              <xsl:variable name="rows" select="max($cols!count(Row))"/>
              <xsl:for-each select="1 to $rows">
                  <xsl:variable name="row" select="."/>
                  <tr>
                      <xsl:for-each select="$cols">
                          <td>{Row[$row]/VLAN}</td>
                      </xsl:for-each>
                  </tr>
              </xsl:for-each>
          </tbody>
      </table>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/94rmq6Q/3是带有!映射操作符和文本值模板的XSLT3,但是https://xsltfiddle.liberty-development.net/94rmq6Q/4使用value-of将其重写为XSLT2。

或者,在XSLT 3中,可以将分组结果存储在一系列数组中:

代码语言:javascript
复制
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>.NET XSLT Fiddle Example</title>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="DocumentRoot">
      <table>
          <xsl:variable name="cols" as="array(element(Row))*">
              <xsl:for-each-group select="Row" group-by="Hostname">
                  <xsl:sequence select="array{ current-group() }"/>
              </xsl:for-each-group>
          </xsl:variable>
          <thead>
              <tr>
                  <xsl:for-each select="$cols">
                      <th>{?1/Hostname}</th>
                  </xsl:for-each>
              </tr>
          </thead>
          <tbody>
              <xsl:variable name="rows" select="max($cols!array:size(.))"/>
              <xsl:for-each select="1 to $rows">
                  <xsl:variable name="row" select="."/>
                  <tr>
                      <xsl:for-each select="$cols">
                          <td>{if ($row le array:size(.)) 
                               then .($row)/VLAN 
                               else ()}</td>
                      </xsl:for-each>
                  </tr>
              </xsl:for-each>
          </tbody>
      </table>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/94rmq6Q/2

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56613926

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档