在 table 中重复打印 xml-node
repeatedly printing xml-node in a table
我在 xml 文件中有数据,其中一个表示形式在 n 列 table 中,将作为标签打印。我现在的方式是每个打印的标签对应于 xml 文件中的一个节点:
xml:
<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet type='text/xsl' href='table.xsl'?>
<nodes>
<node name="A" />
<node name="A" />
<node name="A" />
<node name="B" />
<node name="B" />
<node name="B" />
<node name="B" />
<node name="C" />
<node name="C" />
</nodes>
xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" media-type="text/html" />
<xsl:param name="cols">3</xsl:param> <!-- set the number of columns here -->
<xsl:template match="nodes">
<table>
<tr>
<xsl:apply-templates select="node[position() mod $cols = 1 ]" mode="row"/>
</tr>
</table>
</xsl:template>
<xsl:template match="node" mode="row">
<tr>
<xsl:apply-templates select=". | following-sibling::node[position() < $cols]" mode="cell"/>
</tr>
</xsl:template>
<xsl:template match="node" mode="cell">
<td style="border: 1px dotted #999;">
<xsl:value-of select="./@name"/>
</td>
</xsl:template>
</xsl:stylesheet>
结果:
A A A
B B B
B C C
为了更好的可维护性和数据完整性,我想以这种方式重新定义 xml,节点不重复,但有自己的计数作为属性,所以:
xml:
<nodes>
<node name="A" n="3"/>
<node name="B" n="4"/>
<node name="C" n="2"/>
</nodes>
我的问题是,现在 position() 不再对应于打印标签的数量。看起来我需要一种 for i=1 to n
循环。这是如何实现的?
我建议您分两步进行:首先,生成所需的单个单元格;然后将它们组织成行 table:
XSLT 1.0(+ EXSLT 节点集())
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="html"/>
<xsl:param name="cols">3</xsl:param> <!-- set the number of columns here -->
<xsl:template match="/nodes">
<!-- first pass -->
<xsl:variable name="cells">
<xsl:for-each select="node">
<xsl:call-template name="generate-cells">
<xsl:with-param name="name" select="@name"/>
<xsl:with-param name="n" select="@n"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<!-- output -->
<table border="1">
<xsl:for-each select="exsl:node-set($cells)/td[position() mod $cols = 1]">
<tr>
<xsl:copy-of select=". | following-sibling::td[position() < $cols]"/>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="generate-cells">
<xsl:param name="name"/>
<xsl:param name="n"/>
<xsl:if test="$n">
<td>
<xsl:value-of select="$name"/>
</td>
<xsl:call-template name="generate-cells">
<xsl:with-param name="name" select="$name"/>
<xsl:with-param name="n" select="$n - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
对于 XSLT 3,例如在使用 Saxon JS 2 的浏览器中支持,您可以使用
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:param name="cols" as="xs:integer" select="3"/>
<xsl:function name="mf:repeat" as="item()*">
<xsl:param name="item" as="item()"/>
<xsl:param name="count" as="xs:integer"/>
<xsl:sequence
select="(1 to $count) ! $item"/>
</xsl:function>
<xsl:template match="/">
<html>
<head>
<title>Example</title>
</head>
<body>
<h1>Example</h1>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="nodes">
<table>
<tbody>
<xsl:for-each-group select="node ! mf:repeat(., @n)" group-adjacent="(position() - 1) idiv $cols">
<tr>
<xsl:apply-templates select="current-group()"/>
</tr>
</xsl:for-each-group>
</tbody>
</table>
</xsl:template>
<xsl:template match="node">
<td>{@name}</td>
</xsl:template>
</xsl:stylesheet>
我在 xml 文件中有数据,其中一个表示形式在 n 列 table 中,将作为标签打印。我现在的方式是每个打印的标签对应于 xml 文件中的一个节点:
xml:
<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet type='text/xsl' href='table.xsl'?>
<nodes>
<node name="A" />
<node name="A" />
<node name="A" />
<node name="B" />
<node name="B" />
<node name="B" />
<node name="B" />
<node name="C" />
<node name="C" />
</nodes>
xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" media-type="text/html" />
<xsl:param name="cols">3</xsl:param> <!-- set the number of columns here -->
<xsl:template match="nodes">
<table>
<tr>
<xsl:apply-templates select="node[position() mod $cols = 1 ]" mode="row"/>
</tr>
</table>
</xsl:template>
<xsl:template match="node" mode="row">
<tr>
<xsl:apply-templates select=". | following-sibling::node[position() < $cols]" mode="cell"/>
</tr>
</xsl:template>
<xsl:template match="node" mode="cell">
<td style="border: 1px dotted #999;">
<xsl:value-of select="./@name"/>
</td>
</xsl:template>
</xsl:stylesheet>
结果:
A A A
B B B
B C C
为了更好的可维护性和数据完整性,我想以这种方式重新定义 xml,节点不重复,但有自己的计数作为属性,所以:
xml:
<nodes>
<node name="A" n="3"/>
<node name="B" n="4"/>
<node name="C" n="2"/>
</nodes>
我的问题是,现在 position() 不再对应于打印标签的数量。看起来我需要一种 for i=1 to n
循环。这是如何实现的?
我建议您分两步进行:首先,生成所需的单个单元格;然后将它们组织成行 table:
XSLT 1.0(+ EXSLT 节点集())
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="html"/>
<xsl:param name="cols">3</xsl:param> <!-- set the number of columns here -->
<xsl:template match="/nodes">
<!-- first pass -->
<xsl:variable name="cells">
<xsl:for-each select="node">
<xsl:call-template name="generate-cells">
<xsl:with-param name="name" select="@name"/>
<xsl:with-param name="n" select="@n"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<!-- output -->
<table border="1">
<xsl:for-each select="exsl:node-set($cells)/td[position() mod $cols = 1]">
<tr>
<xsl:copy-of select=". | following-sibling::td[position() < $cols]"/>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="generate-cells">
<xsl:param name="name"/>
<xsl:param name="n"/>
<xsl:if test="$n">
<td>
<xsl:value-of select="$name"/>
</td>
<xsl:call-template name="generate-cells">
<xsl:with-param name="name" select="$name"/>
<xsl:with-param name="n" select="$n - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
对于 XSLT 3,例如在使用 Saxon JS 2 的浏览器中支持,您可以使用
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:param name="cols" as="xs:integer" select="3"/>
<xsl:function name="mf:repeat" as="item()*">
<xsl:param name="item" as="item()"/>
<xsl:param name="count" as="xs:integer"/>
<xsl:sequence
select="(1 to $count) ! $item"/>
</xsl:function>
<xsl:template match="/">
<html>
<head>
<title>Example</title>
</head>
<body>
<h1>Example</h1>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="nodes">
<table>
<tbody>
<xsl:for-each-group select="node ! mf:repeat(., @n)" group-adjacent="(position() - 1) idiv $cols">
<tr>
<xsl:apply-templates select="current-group()"/>
</tr>
</xsl:for-each-group>
</tbody>
</table>
</xsl:template>
<xsl:template match="node">
<td>{@name}</td>
</xsl:template>
</xsl:stylesheet>