我需要XPATH 1.0中的帮助来过滤以下XML,以便我仅获得具有独特'id''的条,并且具有最高的"有效性/日期":
<foo name="fooName">
<bar name="barName">
<id>1111</id>
<validity>
<date>20170920</date>
</validity>
</bar>
<bar name="barName">
<id>1111</id>
<validity>
<date>20170922</date>
</validity>
</bar>
<bar name="barName">
<id>1111</id>
<validity>
<date>20170921</date>
</validity>
</bar>
<bar name="barName">
<id>2222</id>
<validity>
<date>20170921</date>
</validity>
</bar>
<bar name="barName">
<id>2222</id>
<validity>
<date>20170923</date>
</validity>
</bar>
</foo>
我尝试了很多选择和研究,但无法弄清楚确切的解决方案。
过滤后的预期XML应该看起来像:
<foo name="fooName">
<bar name="barName">
<id>1111</id>
<validity>
<date>20170922</date>
</validity>
</bar>
<bar name="barName">
<id>2222</id>
<validity>
<date>20170923</date>
</validity>
</bar>
</foo>
您应该在" Muenchian分组"上阅读,Michael.hor257k已经为您提供了一个指针。(网络搜索会找到其他许多。)
Muenchian分组所做的是使您可以在没有它的情况下更快地做什么。在某些情况下,增加的速度使"原则上可能"one_answers"实践中可行"之间的差异。但是在某些情况下,解决这个问题的一种简单的方法就足够了。
问题1:您只想为每个不同的" ID"输出中的一个" bar"元素。(请注意,您的示例输出显示您的描述是错误的:您不希望"只有具有唯一'ID''的栏",因为没有ID 1111或2222的条形在输入中具有唯一的ID。您想要一个单个输出对于" id"的每个独特价值。不是同一件事。)
解决此问题的一种方法:为" bar"编写两个模板,一个为给定的" ID"发射(实际上是在找到最大的有效性/日期值的工作),而另一个这会导致所有以后的" bar"出现,而" iD"被忽略。
<xsl:template match="bar" priority="10.0">
<!--* find the highest validity/date with this ID here,
* do what needs to be done. *-->
...
</xsl:template>
<xsl:template match="bar[id = preceding-sibling::bar/id]"
priority="20.0"/>
我给出了明确的优先事项,以警告未来我,我正在尝试在这里聪明的事情(并防止未来我通过更改匹配模式以更改相对优先级的方式将其搞砸了)。
另一种方法是在" bar"模板中放置一个选择/。
<xsl:template match="bar">
<xsl:variable name="id" select="string(id)"/>
<xsl:choose>
<xsl:when test="preceding::bar[id=$id]"/>
<xsl:otherwise>
<!--* this is the first of this ID, deal with this ID now *-->
...
</
</
</
第二个模式可能会使制定实际要复制到输出所需的'bar'元素所需的逻辑变得更加容易。您想不是处理每个ID的第一个实例,而是要处理具有最高有效性/日期值的实例:
<xsl:template match="bar">
<xsl:variable name="id" select="string(id)"/>
<xsl:choose>
<!--* the behavior of comparisons here requires a little
* bit of standing on our heads. We want this 'bar' if
* its validity/date value is greater than or equal to
* all other such values for this ID. So first we filter
* out all cases where there is a higher validity/date value
* on another 'bar' with this ID. *-->
<xsl:when test="validity/date < //bar[id=$id]/validity/date"/>
<!--* The 'otherwise' case handles situations where this
* is the only 'bar' with this ID, or where there is no
* higher validity/date value. *-->
<xsl:otherwise>
<xsl:copy-of select="."/>
</
</
</
如果这是一次性或跑步的样式表在"可管理"输入上运行,则可能足够快,并且这种模式可能比Muenchian分组更容易理解,除非您已经对钥匙有很好的了解和他们的用途。如果太慢,穆罕默德分组将向您展示通常是一种更快的方法的方法。
[注意:答案的初始版本具有maxdate
变量
<xsl:variable name="maxdate"
select="max(//bar[id=$id]/validity/date)"/>
,简单地将当前值与之比较:
<xsl:when test="validity/date = $maxdate">
<xsl:copy-of select="."/>
</
,但是XPATH 1.0中唯一的聚集功能是Count()和SUM()。我会说:"在XSLT 2.0中,这要容易得多?"但是,如果您在2.0中,整个事情将是
<xsl:sequence select="for $v in distinct-values(//bar/id)
for $max in max(//bar[id=$v]/validity/date)
return //bar[id=$v and validity/date = $max]"/>
和max()函数在使事情变得更简单时起着相对适度的作用。]
如建议,我想到了下面的XSLT,它似乎正常:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:key name="bars-by-id" match="foo/bar" use="id" />
<xsl:template match="foo">
<foo name="fooName">
<xsl:for-each select="bar[count(. | key('bars-by-id', id)[1]) = 1]">
<xsl:variable name="currentID" select="id" />
<xsl:variable name="barsForID" select="key('bars-by-id', $currentID)"/>
<xsl:copy-of select="$barsForID[not(../bar[id=$currentID]/validity/date > validity/date)]" />
</xsl:for-each>
</foo>
</xsl:template>
</xsl:stylesheet>
感谢您的建议,确实有所帮助。请随时纠正我。