我有一个要在HTML表中显示的项目列表。不过,该列表具有"孔",需要填写才能正确显示(x
和y
是表中的列和行)。我什至无法弄清楚在哪里可以做到这一点。
<items>
<row y="1">
<item x="1" y="1" data="importantStuff1"/>
</row>
<row y="2">
<item x="2" y="2" data="importantStuff3"/>
</row>
<row y="3">
<item x="5" y="3" data="importantStuff1"/>
</row>
<row y="4">
<item x="3" y="4" data="importantStuff2"/>
<item x="4" y="4" data="importantStuff3"/>
</row>
</items>
我需要的是以下内容:
<items>
<row y="1">
<item x="1" y="1" data="importantStuff1"/>
<item x="2" y="1" data="padding"/>
<item x="3" y="1" data="padding"/>
<item x="4" y="1" data="padding"/>
<item x="5" y="1" data="padding"/>
</row>
<row y="2">
<item x="1" y="2" data="padding"/>
<item x="2" y="2" data="importantStuff3"/>
<item x="3" y="2" data="padding"/>
<item x="4" y="2" data="padding"/>
<item x="5" y="2" data="padding"/>
</row>
<row y="3">
<item x="1" y="3" data="padding"/>
<item x="2" y="3" data="padding"/>
<item x="3" y="3" data="padding"/>
<item x="4" y="3" data="padding"/>
<item x="5" y="3" data="importantStuff1"/>
</row>
<row y="4">
<item x="1" y="4" data="padding"/>
<item x="2" y="4" data="padding"/>
<item x="3" y="4" data="importantStuff2"/>
<item x="4" y="4" data="importantStuff3"/>
<item x="5" y="4" data="padding"/>
</row>
</items>
如何将列表添加到这样?保证这些项目被订购,我知道每个轴上有多少个项目。
编辑:我没有意识到这个问题可以解释为我想要一个简单的列表。每个项目中都有其他数据,使得保留现有项目节点很重要。因此,我需要的是一种仅创建填充节点并将现有节点留下的方法。
为了创建一个最小的示例来证明我的问题,我有点过分了。对此很抱歉。
如果您的示例与实际数据一样简单,则应使用递归模板调用来检查5个项目中的每一个。如果在那里,请对其进行申请。如果不是,请创建它。
示例...
XML输入
<items>
<row y="1">
<item x="1" y="1" data="importantStuff1"/>
</row>
<row y="2">
<item x="2" y="2" data="importantStuff3"/>
</row>
<row y="3">
<item x="5" y="3" data="importantStuff1"/>
</row>
<row y="4">
<item x="3" y="4" data="importantStuff2"/>
<item x="4" y="4" data="importantStuff3"/>
</row>5
</items>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="items" select="5"/>
<!--Identity transform. Copy everything as-is unless overridden by
a more specific template.-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="row">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:call-template name="outputItems">
<xsl:with-param name="count" select="1"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="outputItems">
<xsl:param name="count"/>
<xsl:choose>
<!--Item already exists.-->
<xsl:when test="item[@x=$count]">
<xsl:apply-templates select="item[@x=$count]"/>
</xsl:when>
<!--Item does not exist. create it.-->
<xsl:otherwise>
<item x="{$count}" y="{@y}" data="padding"/>
</xsl:otherwise>
</xsl:choose>
<!--Call this template again if needed.-->
<xsl:if test="$items > $count">
<xsl:call-template name="outputItems">
<xsl:with-param name="count" select="$count + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
输出
<items>
<row y="1">
<item x="1" y="1" data="importantStuff1"/>
<item x="2" y="1" data="padding"/>
<item x="3" y="1" data="padding"/>
<item x="4" y="1" data="padding"/>
<item x="5" y="1" data="padding"/>
</row>
<row y="2">
<item x="1" y="2" data="padding"/>
<item x="2" y="2" data="importantStuff3"/>
<item x="3" y="2" data="padding"/>
<item x="4" y="2" data="padding"/>
<item x="5" y="2" data="padding"/>
</row>
<row y="3">
<item x="1" y="3" data="padding"/>
<item x="2" y="3" data="padding"/>
<item x="3" y="3" data="padding"/>
<item x="4" y="3" data="padding"/>
<item x="5" y="3" data="importantStuff1"/>
</row>
<row y="4">
<item x="1" y="4" data="padding"/>
<item x="2" y="4" data="padding"/>
<item x="3" y="4" data="importantStuff2"/>
<item x="4" y="4" data="importantStuff3"/>
<item x="5" y="4" data="padding"/>
</row>5
</items>
我知道每个轴上有多少个项目。
假设您可以将此知识作为参数传递给样式表,我建议您这样做:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="rows" select="4"/>
<xsl:param name="cols" select="5"/>
<xsl:key name="item" match="item" use="concat(@x, '|', @y)" />
<xsl:template match="/items">
<xsl:copy>
<xsl:call-template name="generate-rows"/>
</xsl:copy>
</xsl:template>
<xsl:template name="generate-rows">
<xsl:param name="y" select="1"/>
<xsl:if test="$y <= $rows">
<row y="{$y}">
<xsl:call-template name="generate-cols">
<xsl:with-param name="y" select="$y"/>
</xsl:call-template>
</row>
<!-- recursive call -->
<xsl:call-template name="generate-rows">
<xsl:with-param name="y" select="$y + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="generate-cols">
<xsl:param name="y"/>
<xsl:param name="x" select="1"/>
<xsl:if test="$x <= $cols">
<item x="{$x}" y="{$y}" >
<xsl:variable name="exisiting-item" select="key('item', concat($x, '|', $y))" />
<xsl:attribute name="data">
<xsl:choose>
<xsl:when test="$exisiting-item">
<xsl:value-of select="$exisiting-item/@data"/>
</xsl:when>
<xsl:otherwise>padding</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</item>
<!-- recursive call -->
<xsl:call-template name="generate-cols">
<xsl:with-param name="y" select="$y"/>
<xsl:with-param name="x" select="$x + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
这将预先生成所提供的尺寸的表,并在每个单元格中填充来自相应项目的数据(如果存在)。
-
添加:
如果需要从输入中推导表尺寸,则更改:
<xsl:param name="rows" select="4"/>
<xsl:param name="cols" select="5"/>
to:
<xsl:variable name="rows" select="/items/row[last()]/@y"/>
<xsl:variable name="cols">
<xsl:for-each select="/items/row/item">
<xsl:sort select="@x" data-type="number" order="ascending"/>
<xsl:if test="position()=last()">
<xsl:value-of select="@x"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
这将最后一行的 y
值和任何项目的最大 x
值作为表尺寸。
您可以使用以下XSLT实现此目标。这是一种特殊的解决方案,但是使用名称XML岛创建"计数"变量是模仿固定计数的" For"循环的一种通用方法。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cnt="http://cnt.com" exclude-result-prefixes="cnt">
<xsl:output method="xml" indent="yes" />
<!-- creating a "count" XML structure -->
<cnt:count>
<x cnt="1" />
<x cnt="2" />
<x cnt="3" />
<x cnt="4" />
<x cnt="5" />
</cnt:count>
<xsl:template match="items">
<items>
<xsl:for-each select="row">
<xsl:variable name="varY" select="@y" /> <!-- saving the value of '@y' -->
<row y="{$varY}">
<xsl:for-each select="document('')/xsl:stylesheet/cnt:count/x">
<item x="{@cnt}" y="{$varY}" />
</xsl:for-each>
</row>
</xsl:for-each>
</items>
</xsl:template>
</xsl:stylesheet>
输出是根据需要的。