在确定每个唯一记录的唯一最高分数后对转换的XML进行排序
我编译了以下转换脚本。它的目的是为每个唯一的行ID找到最高分数。遗憾的是,这是通过拼凑类似问题的解决方案创建的,我不完全理解解决方案。我还试图在转换中加入的是按分数降序对返回的记录进行排序 示例代码:在确定每个唯一记录的唯一最高分数后对转换的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
<?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>