Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
XSLT-对输出中的元素进行分组_Xslt - Fatal编程技术网

XSLT-对输出中的元素进行分组

XSLT-对输出中的元素进行分组,xslt,Xslt,这是一个“我要我的蛋糕,吃它”的问题,有很多变量在起作用,但我会尽我最大的努力保持简洁 我们的软件产品具有三层分区的概念[A、B和C]。 我们客户的产品只有一层区域[X]。 客户的XML文件始终包含2000个区域,即使实际上只有少数几个区域分配给设备。 出于与此问题无关的原因,我必须从XSLT输出中去掉未使用的区域。 此输出用作我们其中一个软件模块的配置 我的xsl文件中有以下摘录: <xsl:for-each select="zoneX"> <xsl:if test="/

这是一个“我要我的蛋糕,吃它”的问题,有很多变量在起作用,但我会尽我最大的努力保持简洁

我们的软件产品具有三层分区的概念[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" .../>
为清晰起见,添加了空行

我已尝试为每种分区类型重复以下步骤:

<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个设备——每个区域类型只调用一次所有区域。