Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
XSLT2.0:使用动态行创建HTML表的问题&;柱_Xslt_Xslt 2.0_Xslt Grouping - Fatal编程技术网

XSLT2.0:使用动态行创建HTML表的问题&;柱

XSLT2.0:使用动态行创建HTML表的问题&;柱,xslt,xslt-2.0,xslt-grouping,Xslt,Xslt 2.0,Xslt Grouping,我正在创建一个基于动态列(主机名)和行(VLAN)的HTML表。在中的第一个位置数据(所有主机1行)写入表后,我遇到了一个问题;很好地选择第二个位置数据,但$vCol变量将其带回$vCols变量的第一行 感谢您提供的任何指导。谢谢 XSLT-2.0代码: <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns

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

感谢您提供的任何指导。谢谢

XSLT-2.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: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数据

<?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>

开关-1
10.29.178.102
10
VLAN-10
开关-1
10.29.178.102
500
VLAN-500
开关-2
10.29.178.103
11
VLAN-11
开关-2
10.29.178.103
501
VLAN-500
开关-3
10.29.170.1
15
VLAN-15
开关-3
10.29.170.1
25
VLAN-25
开关-3
10.29.170.1
35
VLAN-35
开关-3
10.29.170.1
45
VLAN-45
开关-3
10.29.170.1
55
VLAN-55
输出(实际和期望):


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

<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>

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

<xsl:variable name="maxRows" select="max(//Row/count(key(hostNameByValue, Hostname)))" />
您还可以使用
不同的值
来获取不同的列名

<xsl:variable name="cols" select="distinct-values(//Row/Hostname)" />
(其中,
$doc
是对初始XML文档的引用,因为在
xsl:for each
中现在是一个原子值序列)

试试这个XSLT

<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>


中查看它的实际操作我不认为在XSLT 2或3中,一旦您对每个组使用了
,您就需要任何键,您可以存储分组结果,然后对其进行处理,例如将分组结果作为XML存储在您可以使用的XSLT 2或XSLT 3中

<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>

<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>
<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>
<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>