xslt - 如何检查下一个节点值以及相同的id,组子节点

时间:2017-10-22 12:47:01

标签: xml xslt

我是XSLT的新手,我想知道如何降低当前XSLT之一的速度..它目前正在获取一系列体育项目,以及一系列组,通过这些组循环,然后通过列表体育运动,看看它们是否匹配。

如果你有200个团体和50个体育项目,这是一个快速的10.000迭代..这必须更快。

我正在考虑编写一个新的查询来实现这样的结果:

<groups>
   <group>
        <id>12</id>
        <sport>Football</sport>
    </group>
    <group>
        <id>12</id>
        <sport>Hockey</sport>
    </group>
    <group>
        <id>12</id>
        <sport>Swimming</sport>
    </group>
    <group>
        <id>13</id>
        <sport>Tennis</sport>
    </group>
    <group>
        <id>13</id>
        <sport>Basketball</sport>
    </group>
</groups>    

这样你只需要循环结果集,这样可以减少迭代次数。每次迭代都应检查下一次迭代是否具有相同的ID。是的,然后将这项运动作为一个参数传递到下一次迭代,如果是第二次迭代,它应该将它们传递到下一次。直到它到达下一次迭代不具有相同ID的点,这是应该将体育分组到单个对象的位置。

预期结果如下:

<groups>
    <group>
        <id>12</id>
        <sport>Football</sport>
        <sport>Swimming</sport>
        <sport>Hockey</sport>
    </group>
    <group>
        <id>13</id>
        <sport>Tennis</sport>
        <sport>Basketball</sport>
    </group>
</groups>

我一直在尝试,但没有运气,这就是我现在的xslt的样子:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

<xsl:template name="main" match="/">

    <groups>
    <xsl:for-each select="*/*/row">
        <xsl:variable name="current" select="position()" />
        <xsl:variable name="next" select="*/*/row[$current + 1]" />

        <xsl:choose>
            <xsl:when test="field[@name='GID'] = $next/field[@name='GIID']">
                <xsl:variable name="sports" >
                    <sport><xsl:value-of select="field[@name='SPORT']" /></sport>
                </xsl:variable>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test="count($sports) &gt; 0">
                        <xsl:call-template name="groups">
                          <xsl:with-param name="receivingSports" select="$sports" />
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:call-template name="groups" />
                    </xsl:otherwise>
                </xsl:choose>

            </xsl:otherwise>
        </xsl:choose>

    </xsl:for-each>
    </groups>
</xsl:template>



<xsl:template name="groups">
    <xsl:param name="receivingSports" />
    <group>
            <xsl:value-of select="$receivingSports"/>
            <id>
                <xsl:value-of select="field[@name='BIID']" />
            </id>

    </group>
</xsl:template>

</xsl:stylesheet>

2 个答案:

答案 0 :(得分:1)

问题的解决方案是xsl:for-each-group。 (我假设您使用的是XSLT 2.0;如果您处于仅限1.0的环境中,通常的建议是使用Muenchian分组(请参阅@JLRishe的回答)并考虑采取措施摆脱该环境。

答案 1 :(得分:0)

当你需要在XSLT 1.0中进行分组时,一个好的解决方案通常会使用Muenchian Grouping,就像在这里一样:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="sports" match="group" use="id"/>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="group[generate-id() =
                                           generate-id(key('sports', id)[1])]" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="group">
    <xsl:copy>
      <xsl:copy-of select="id"/>
      <xsl:copy-of select="key('sports', id)/sport" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

它不仅比使用count快得多,而且更加简洁。

在样本输入上运行此操作时,结果为:

<groups>
  <group>
    <id>12</id>
    <sport>Football</sport>
    <sport>Hockey</sport>
    <sport>Swimming</sport>
  </group>
  <group>
    <id>13</id>
    <sport>Tennis</sport>
    <sport>Basketball</sport>
  </group>
</groups>