【发布时间】:2018-04-04 19:43:37
【问题描述】:
这是一个“我想要我的蛋糕并吃掉它”的问题,其中有很多变数,但我会尽力保持简洁。
我们的软件产品具有三层区域 [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] 被分配给一个设备。
在这一点上我必须强调,我们的软件模块对于这些元素的这种特定顺序绝对没有问题。
我的“强迫症”发挥作用(以及同行的)是我们的示例配置和我们的配置文档总是将区域类型组合在一起。
因此,所需的输出将显示为:
<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 多台设备。 大多数区域包括多个设备。 仅使用了(2000 个)zoneX 中的 200 个。
在我的第一个解决方案中,我每个 zoneX 只迭代一次设备。
【问题讨论】:
标签: xslt