这是一个“我想要我的蛋糕并吃掉它”的问题,并且有很多变数在起作用,但我会尽力保持简洁。
我们的软件产品具有三层区域[A,B和C]的概念。 我们客户的产品只有一层区域[X]。 客户的XML文件始终包含2000个区域,即使实际只为设备分配了少量区域。 由于与此问题无关的原因,我必须从XSLT输出中删除未使用的区域。 此输出用作我们的一个软件模块的配置。
我在xsl文件中有这个(摘录):
<xsl:for-each select="zoneX">
<xsl:if test="/{path}/device[zone=current()/@id]">
<xsl:call-template name="ZoneTypeA"/>
<xsl:call-template name="ZoneTypeB"/>
<xsl:call-template name="ZoneTypeC"/>
</xsl:if>
</xsl:for-each>
这将生成这样的输出(示例):
<zoneA id="0" .../>
<zoneB id="0" .../>
<zoneC id="0" .../>
<zoneA id="1" .../>
<zoneB id="1" .../>
<zoneC id="1" .../>
因为在此示例中,仅将zoneX [id = 0]和zoneX [id = 1]分配给设备。
我必须强调的是,我们的软件模块对这些元素的特定排序绝对没有问题。
我的'OCD'开始(以及同伴的)是我们的示例配置和我们的配置上的文档总是将区域类型组合在一起。
因此,所需的输出将为:
<zoneA id="0" .../>
<zoneA id="1" .../>
<zoneB id="0" .../>
<zoneB id="1" .../>
<zoneC id="0" .../>
<zoneC id="1" .../>
(为清晰起见,添加了空行)
我尝试为每个区域类型重复<for-each>
:
<xsl:for-each select="zones/zone">
<xsl:if test="/{long-path}/devices[zone=current()/@id]">
<xsl:call-template name="ZoneTypeA"/>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="zones/zone">
<xsl:if test="/{long-path}/devices[zone=current()/@id]">
<xsl:call-template name="ZoneTypeB"/>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="zones/zone">
<xsl:if test="/{long-path}/devices[zone=current()/@id]">
<xsl:call-template name="ZoneTypeC"/>
</xsl:if>
</xsl:for-each>
这给了我漂亮的输出,但是生成输出所花费的时间增加了三倍。
还有另一种方法,我只需要迭代设备一次,然后生成区域类型组合在一起的输出吗?
修改
保持简洁,错过了一个重要的细节。者。
花费大量时间为每个区域寻找设备。请参阅上面示例中的<xsl:if>
。
真实场景示例: 客户配置中包含5000多个设备。 大多数区域包含多个设备。 仅使用了200个(2000年)的zoneX。
在我的第一个解决方案中,我只在每个zoneX 中迭代一次设备。
答案 0 :(得分:1)
一种方法是使用另一个包含xsl:for-each
的命名模板,该模板可以传递带有区域类型的参数...
<xsl:template name="AllZones">
<xsl:param name="zoneType" />
<xsl:for-each select="zones/zone">
<xsl:if test="/{long-path}/devices[zone=current()/@id]">
<xsl:choose>
<xsl:when test="$zoneType='A'"><xsl:call-template name="ZoneTypeA"/></xsl:when>
<xsl:when test="$zoneType='B'"><xsl:call-template name="ZoneTypeB"/></xsl:when>
<xsl:when test="$zoneType='C'"><xsl:call-template name="ZoneTypeC"/></xsl:when>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</xsl:template>
你会这样称呼它三次,就像这样......
<xsl:call-template name="AllZones">
<xsl:with-param name="zoneType" select="'A'" />
</xsl:call-template>
<xsl:call-template name="AllZones">
<xsl:with-param name="zoneType" select="'B'" />
</xsl:call-template>
<xsl:call-template name="AllZones">
<xsl:with-param name="zoneType" select="'C'" />
</xsl:call-template>
三个命名模板ZoneTypeA,ZoneTypeB和ZoneTypeC中的代码有何不同?如果代码相似,您可以将它们组合到一个模板中,并将区域类型作为参数传递,从而避免需要所有单独的xsl:call-templates
。