XSLT-对输出中的元素进行分组
这是一个“我要我的蛋糕,吃它”的问题,有很多变量在起作用,但我会尽我最大的努力保持简洁 我们的软件产品具有三层分区的概念[A、B和C]。 我们客户的产品只有一层区域[X]。 客户的XML文件始终包含2000个区域,即使实际上只有少数几个区域分配给设备。 出于与此问题无关的原因,我必须从XSLT输出中去掉未使用的区域。 此输出用作我们其中一个软件模块的配置 我的xsl文件中有以下摘录:XSLT-对输出中的元素进行分组,xslt,Xslt,这是一个“我要我的蛋糕,吃它”的问题,有很多变量在起作用,但我会尽我最大的努力保持简洁 我们的软件产品具有三层分区的概念[A、B和C]。 我们客户的产品只有一层区域[X]。 客户的XML文件始终包含2000个区域,即使实际上只有少数几个区域分配给设备。 出于与此问题无关的原因,我必须从XSLT输出中去掉未使用的区域。 此输出用作我们其中一个软件模块的配置 我的xsl文件中有以下摘录: <xsl:for-each select="zoneX"> <xsl:if test="/
<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" .../>
为清晰起见,添加了空行
我已尝试为每种分区类型重复以下步骤:
<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>
这给了我一个漂亮的输出,但是使生成输出所需的时间增加了三倍
是否有另一种方法,我只需要迭代设备一次,然后生成区域类型分组在一起的输出
编辑
过于简洁,遗漏了一个重要的细节。阿波斯。
为每个区域查找设备花费了大量时间。请参见上面示例中的
真实场景示例:
客户配置中有5000多台设备。
大多数区域由多个设备组成。
2000款zoneX中只有200款被使用
在我的第一个解决方案中,我只在每个zoneX中迭代设备一次。一种方法是,使用另一个命名模板,该模板包含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模板。这不会导致对每个zoneX调用三次吗?这就是浪费大量时间的地方,特别是如果客户的配置有很多设备的话——例如:200个设备——每个区域类型只调用一次所有区域。