Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.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排序问题:具有多个相等值节点的前N个_Xslt_Sorting - Fatal编程技术网

XSLT排序问题:具有多个相等值节点的前N个

XSLT排序问题:具有多个相等值节点的前N个,xslt,sorting,Xslt,Sorting,我需要得到xml树中的前N个值,或者更好地说,我需要得到大于或等于第N个值的值,因此包括“exaeqos”。我从这个xml开始 <?xml version="1.0" encoding="UTF-8"?> <results> <node type="prov" id="1" name="GLD"> <node type="gem" id ="2" name="Wageningen" value="300" />

我需要得到xml树中的前N个值,或者更好地说,我需要得到大于或等于第N个值的值,因此包括“exaeqos”。我从这个xml开始

<?xml version="1.0" encoding="UTF-8"?>
<results>
    <node type="prov" id="1" name="GLD">
        <node type="gem" id ="2" name="Wageningen" value="300" />
        <node type="gem" id ="3" name="Arnhem" value="500" />
        <node type="gem" id ="4" name="Nijmegen" value="80" />
        <node type="gem" id ="5" name="Beekbergen" value="40" />
        <node type="gem" id ="6" name="Apeldoorn" value="3000" />
        <node type="gem" id ="7" name="Rhenen" value="20" />
        <node type="gem" id ="8" name="Bennekom" value="750" />
        <node type="gem" id ="9" name="Velp" value="500" />
        <node type="gem" id ="10" name="Ede" value="250" />
    </node>
    <node type="prov" id="11" name="LI">
        <node type="gem" id ="12" name="Maastricht" value="1300" />
        <node type="gem" id ="13" name="Heerlen" value="5010" />
        <node type="gem" id ="14" name="Venlo" value="1300" />
        <node type="gem" id ="15" name="Sittard" value="240" />
        <node type="gem" id ="16" name="Roermond" value="100" />
        <node type="gem" id ="17" name="Valkenburg" value="120" />
        <node type="gem" id ="18" name="Geleen" value="1750" />
        <node type="gem" id ="19" name="Venray" value="1300" />
        <node type="gem" id ="20" name="Beek" value="850" />
    </node>
</results>

在N=3的情况下,以此结束

<?xml version="1.0" encoding="UTF-8"?>
<results>
    <provincie id="1" name="GLD">
        <gemeente id="6" name="Apeldoorn" value="3000"/>
        <gemeente id="8" name="Bennekom" value="750"/>
        <gemeente id="3" name="Arnhem" value="500"/>
        <gemeente id="9" name="Velp" value="500"/>
    </provincie>
    <provincie id="11" name="LI">
        <gemeente id="13" name="Heerlen" value="5010"/>
        <gemeente id="18" name="Geleen" value="1750"/>
        <gemeente id="12" name="Maastricht" value="1300"/>
        <gemeente id="14" name="Venlo" value="1300"/>
        <gemeente id="19" name="Venray" value="1300"/>
    </provincie>
</results>

当我使用下面的xslt时,结构还可以,但它显然不会返回id为9、14和19的元素

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes" />

    <xsl:template match="/">
        <results>
            <xsl:apply-templates select="/results/node"/>
         </results>"'
    </xsl:template>

    <xsl:template match="/results/node">
        <xsl:variable name="provname" select="@name"/>
        <xsl:variable name="provid" select="@id"/>
        <provincie id="{$provid}" name="{$provname}">
            <xsl:apply-templates select="./node">
                <xsl:sort select="@value" data-type="number" order="descending"/>
            </xsl:apply-templates>
        </provincie>
    </xsl:template>

    <xsl:template match="results/node/node">
        <xsl:variable name="gemname" select="@name"/>
        <xsl:variable name="gemid" select="@id"/>
        <xsl:variable name="value" select="@value"/>

        <xsl:if test="position() &lt;= 3">
            <gemeente id="{$gemid}" name="{$gemname}" value="{$value}" />
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

"'
现在不知道该走哪条路。下面的代码不起作用

<xsl:variable name="limitvalue" select="./node[3]/@value"/>
<xsl:if test="@value &gt;= $limitvalue">
    <gemeente id="{$gemid}" name="{$gemname}">
        <xsl:value-of select="@value"/> 
    </gemeente>
</xsl:if>

感谢您的帮助

更新,基于@ThomasW的解决方案,并允许设置limitrank

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes" />

    <!--set limitrank as the rank that we use to cut off-->
    <xsl:variable name="limitrank" select="3"/>

    <xsl:template match="/">
        <results>
            <xsl:apply-templates select="/results/node"/>
        </results>
    </xsl:template>

    <xsl:template match="/results/node">
        <!-- We generate a string of decending @value numbers; 
         Each number covers exactly 5 characters (spaces are added if there are less than 5 digits) -->
        <xsl:variable name="sortedValues">
            <xsl:for-each select="node">
                <xsl:sort select="@value" data-type="number" order="descending"/>
                <!-- Here we add spaces and strip everything that exceeds 5 characters -->
                <xsl:value-of select="substring(concat(@value,'    '),1,5)"/>
            </xsl:for-each>
        </xsl:variable>
        <!-- Now, we get the Nth number, which covers bytes (limitrank-1)*5+1 to limitrank*5;
         So that we get a meaningful result if there were less than three numbers, we add two trailing zeroes -->
        <xsl:variable name="limitValue" select="substring(concat($sortedValues,'0    0'),($limitrank - 1) * 5 + 1,5)"/>

        <provincie>
            <xsl:copy-of select="@id|@name"/>
            <xsl:apply-templates select="node[@value &gt;= $limitValue]">
                <xsl:sort select="@value" data-type="number" order="descending"/>
            </xsl:apply-templates>
        </provincie>
    </xsl:template>

    <xsl:template match="results/node/node">
        <gemeente>
            <xsl:copy-of select="@id|@name|@value"/>
        </gemeente>
    </xsl:template>
</xsl:stylesheet>

我对这个问题的理解是:对于每个省,你按照其
@值对市镇进行排序。然后你选择前三名,如果还有其他与第三名具有相同
@值的市镇,你也会将其包括在内。对吗

我相信这只能通过一些字符串技巧来实现(请参见代码中的注释):


你对这个问题的理解是正确的。我确实喜欢耍花招,你也喜欢。我看到了一些优化,例如,你只需要将前3个值合并为SortedValue。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes" />

  <xsl:template match="/">
    <results>
      <xsl:apply-templates select="/results/node"/>
    </results>
  </xsl:template>

  <xsl:template match="/results/node">
    <!-- We generate a string of decending @value numbers; 
         Each number covers exactly 5 characters (spaces are added if there are less than 5 digits) -->
    <xsl:variable name="sortedValues">
      <xsl:for-each select="node">
        <xsl:sort select="@value" data-type="number" order="descending"/>
        <!-- Here we add spaces and strip everything that exceeds 5 characters -->
        <xsl:value-of select="substring(concat(@value,'    '),1,5)"/>
      </xsl:for-each>
    </xsl:variable>
    <!-- Now, we get the 3rd number, which covers characters 11 to 15;
         So that we get a meaningful result if there were less than three numbers, we add two trailing zeroes -->
    <xsl:variable name="limitValue" select="substring(concat($sortedValues,'0    0'),11,5)"/>

    <provincie>
      <xsl:copy-of select="@id|@name"/>
      <xsl:apply-templates select="node[@value &gt;= $limitValue]"/>
    </provincie>
  </xsl:template>

  <xsl:template match="results/node/node">
    <gemeente>
      <xsl:copy-of select="@id|@name|@value"/>
    </gemeente>
  </xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<results>
  <provincie id="1" name="GLD">
    <gemeente id="3" name="Arnhem" value="500"/>
    <gemeente id="6" name="Apeldoorn" value="3000"/>
    <gemeente id="8" name="Bennekom" value="750"/>
    <gemeente id="9" name="Velp" value="500"/>
  </provincie>
  <provincie id="11" name="LI">
    <gemeente id="12" name="Maastricht" value="1300"/>
    <gemeente id="13" name="Heerlen" value="5010"/>
    <gemeente id="14" name="Venlo" value="1300"/>
    <gemeente id="18" name="Geleen" value="1750"/>
    <gemeente id="19" name="Venray" value="1300"/>
  </provincie>
</results>
    <provincie>
      <xsl:copy-of select="@id|@name"/>
      <xsl:apply-templates select="node[@value &gt;= $limitValue]">
        <xsl:sort select="@value" data-type="number" order="descending"/>
      </xsl:apply-templates>
    </provincie>