Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.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
在确定每个唯一记录的唯一最高分数后对转换的XML进行排序_Xml_Sorting_Xslt - Fatal编程技术网

在确定每个唯一记录的唯一最高分数后对转换的XML进行排序

在确定每个唯一记录的唯一最高分数后对转换的XML进行排序,xml,sorting,xslt,Xml,Sorting,Xslt,我编译了以下转换脚本。它的目的是为每个唯一的行ID找到最高分数。遗憾的是,这是通过拼凑类似问题的解决方案创建的,我不完全理解解决方案。我还试图在转换中加入的是按分数降序对返回的记录进行排序 示例代码: <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output

我编译了以下转换脚本。它的目的是为每个唯一的行ID找到最高分数。遗憾的是,这是通过拼凑类似问题的解决方案创建的,我不完全理解解决方案。我还试图在转换中加入的是按分数降序对返回的记录进行排序

示例代码:

<?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" version="1.0" encoding="UTF-8" indent="yes" standalone="yes"/>
   <xsl:key name="kRecordByRowID" match="record" use="CON_ROW_ID"/>
   <xsl:template match="record" />
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
        <xsl:apply-templates select="node()|@*"> <!-- Insert sort here for partially working sorting--> 
            <xsl:sort select="/SCORE" order="descending"/>        
        </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="record[count(.|key('kRecordByRowID',CON_ROW_ID)[1]) = 1]">
        <xsl:for-each select="key('kRecordByRowID',CON_ROW_ID)"> 
            <xsl:if test="position()=1">
                <xsl:call-template name="identity"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

样本输入:

<records>   
    <record>
        <CON_ROW_ID>F</CON_ROW_ID>
        <SCORE>80</SCORE>
    </record>
    <record>
        <CON_ROW_ID>D</CON_ROW_ID>
        <SCORE>90</SCORE>
    </record>
    <record>
        <CON_ROW_ID>D</CON_ROW_ID>
        <SCORE>75</SCORE>
    </record>
    <record>
        <CON_ROW_ID>F</CON_ROW_ID>
        <SCORE>85</SCORE>
    </record>
</records>

F
80
D
90
D
75
F
85
正如您在代码中看到的,有一条注释说我可以将排序代码()插入标记中,但它返回不正确的结果。结果被排序到一个点,然后变成随机的


该排序代码应放在何处以正确返回分数递减列表

没有
/SCORE
元素(排序
永远不会选择它)。您想要的是使用
record
中上下文相关的
SCORE
元素,因此这将是简单的
SCORE

<xsl:template match="node()|@*" name="identity">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"> <!-- Insert sort here for partially working sorting--> 
            <xsl:sort select="SCORE" order="descending"/>        
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

可悲的是,这是通过将类似的解决方案拼凑在一起而产生的 问题,我不完全理解解决方案

你为什么不用更明智的方式重写它,例如:

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

<xsl:key name="record-by-ID" match="record" use="CON_ROW_ID"/>

<xsl:template match="/">
    <output>
        <!-- for each first record in its group -->
        <xsl:for-each select="records/record[count(.|key('record-by-ID',CON_ROW_ID)[1]) = 1]">
            <!-- sort the group by score -->
            <xsl:for-each select="key('record-by-ID',CON_ROW_ID)">
                <xsl:sort select="SCORE" order="descending"/>   
                <!-- output the highest scoring record -->
                <xsl:if test="position() = 1">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>


编辑 它应该为每个唯一的CON_ROW_ID取最高分数,然后 按分数降序再次返回这些

如果您的处理器支持一些基本的EXSLT功能,那么这可能非常简短:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:set="http://exslt.org/sets"
xmlns:math="http://exslt.org/math"
extension-element-prefixes="set math">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="record-by-ID" match="record" use="CON_ROW_ID"/>

<xsl:template match="/">
    <output>
        <xsl:for-each select="set:distinct(records/record/CON_ROW_ID)">
            <xsl:sort select="math:max(key('record-by-ID', .)/SCORE)" order="descending"/>   
            <xsl:copy-of select="math:highest(key('record-by-ID', .)/SCORE)/parent::record"/>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

否则,您需要分两次执行此操作(并在此过程中使用EXSLT node-set()函数):



这无疑使代码更清晰易懂。我试着在一些地方放置排序标签,根据分数对最终结果进行排序,但到目前为止没有成功。我得到的输出的一个例子是“(D,90),(E,90),(B,85),(F,85),(C,80),(A,90),(J,85),(G,80)”。我把它们成对地放在一起,使它更容易阅读。看起来排序一开始是有效的,然后又出错了。@Strzelec你的意思是你只想拥有另一种得分最高的记录吗?这是正确的。它应该为每个唯一的CON_ROW_ID获取最高分数,然后按分数降序再次返回这些分数。如果不清楚,我深表歉意。@Strzelec我在回答中添加了两种替代方法。
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="record-by-ID" match="record" use="CON_ROW_ID"/>

<xsl:template match="/">
    <!-- FIRST PASS -->
    <xsl:variable name="highest-scoring-records">
        <!-- for each first record in its group -->
        <xsl:for-each select="records/record[count(.|key('record-by-ID',CON_ROW_ID)[1]) = 1]">
            <!-- sort the group by score -->
            <xsl:for-each select="key('record-by-ID',CON_ROW_ID)">
                <xsl:sort select="SCORE" order="descending"/>   
                <!-- output the highest scoring record -->
                <xsl:if test="position() = 1">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:variable>
    <!-- OUTPUT -->
    <output>
        <xsl:for-each select="exsl:node-set($highest-scoring-records)/record">
            <xsl:sort select="SCORE" order="descending"/>
            <xsl:copy-of select="."/>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>