我正在创建一个HTML表,它基于动态列(Hostname)和行(VLAN)。在中的第一个位置数据(所有主机为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>输出(实际和所需):

发布于 2019-06-16 05:03:32
我认为使用group by可能会让事情变得更加复杂。基本上,对于每一行,您需要迭代所有列并输出单元格(如果存在),否则输出一个空单元格。这意味着您应该遍历索引,而不是行元素:
<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>发布于 2019-06-16 16:31:04
首先,我认为您的maxRows变量可以简化为
<xsl:variable name="maxRows" select="max(//Row/count(key(hostNameByValue, Hostname)))" />其中,我定义了如下hostNameByValue密钥:
<xsl:key name="hostNameByValue" match="Row" use="Hostname"/>还可以使用distinct-values获取不同的列名
<xsl:variable name="cols" select="distinct-values(//Row/Hostname)" />因此,假设$rowNum是当前数字(在<xsl:for-each select="1 to $maxRows">块中,获取当前像元值的代码如下所示
<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
<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上查看它的实际效果
发布于 2019-06-16 21:06:08
我不认为在XSLT2或3中,一旦使用了for-each-group,就需要任何键,您只需存储分组结果,然后对其进行处理,例如,在XSLT2或3中将分组结果存储为XML,您可以使用
<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中,可以将分组结果存储在一系列数组中:
<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://stackoverflow.com/questions/56613926
复制相似问题