Xml 仅从与属性值匹配的列表中选择第一个元素
我希望能够从属性值匹配的集合中选择第一个XML元素。为了进一步解释,假设我们有以下XML:Xml 仅从与属性值匹配的列表中选择第一个元素,xml,xslt,xpath,Xml,Xslt,Xpath,我希望能够从属性值匹配的集合中选择第一个XML元素。为了进一步解释,假设我们有以下XML: <events> <event date="2013-06-17"> <person first="Joe" last="Bloggs" /> <person first="John" last="Smith" /> </event> <event date="2013-01-29"&
<events>
<event date="2013-06-17">
<person first="Joe" last="Bloggs" />
<person first="John" last="Smith" />
</event>
<event date="2013-01-29">
<person first="Jane" last="Smith" />
<person first="John" last="Smith" />
</event>
<event date="2012-09-03">
<person first="Joe" last="Bloggs" />
<person first="John" last="Doe" />
</event>
<event date="2012-04-05">
<person first="Jane" last="Smith" />
<person first="John" last="Smith" />
<person first="John" last="Doe" />
</event>
<event>
当然,
current()
函数不会喜欢这样,但我只是想知道是否有人知道如何在单个XPath语句中实现这一点?下面是一个XSLT 2.0方法,使用对每个组使用和按分组:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="events">
<xsl:for-each-group select="event/person" group-by="concat(@first, '|', @last)">
<xsl:copy-of select="."/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
使用XSLT2.0和对每个组都需要使用一个变量来存储项,例如
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="events">
<xsl:variable name="first-person-in-groups" as="element(person)*">
<xsl:for-each-group select="event/person" group-by="concat(@first, '|', @last)">
<xsl:copy-of select="."/>
</xsl:for-each-group>
</xsl:variable>
<xsl:apply-templates select="$first-person-in-groups"/>
</xsl:template>
<xsl:template match="person">
<foo>...</foo>
</xsl:template>
</xsl:stylesheet>
...
这样,您就有了一系列person
元素,您可以应用模板。这里是一个XSLT 2.0方法,使用对每个组和分组依据:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="events">
<xsl:for-each-group select="event/person" group-by="concat(@first, '|', @last)">
<xsl:copy-of select="."/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
使用XSLT2.0和对每个组都需要使用一个变量来存储项,例如
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="events">
<xsl:variable name="first-person-in-groups" as="element(person)*">
<xsl:for-each-group select="event/person" group-by="concat(@first, '|', @last)">
<xsl:copy-of select="."/>
</xsl:for-each-group>
</xsl:variable>
<xsl:apply-templates select="$first-person-in-groups"/>
</xsl:template>
<xsl:template match="person">
<foo>...</foo>
</xsl:template>
</xsl:stylesheet>
...
这样,您就有了一系列person
元素,可以应用模板。您能够使用XSLT 2.0或XSTL 1.0吗?在XSLT2.0中,可以对每个组元素使用xsl:。在XSLT 1.0中,您将使用一种称为Muenchian分组的技术。我可以使用XSL 2.0,但是,尽管for each group比我目前所做的工作更简洁,但它没有解决以下问题:例如,如何将选择声明为可以使用的单个XPath语句,在应用模板调用中。您能够使用XSLT 2.0或XSTL 1.0吗?在XSLT2.0中,可以对每个组元素使用xsl:。在XSLT 1.0中,您将使用一种称为Muenchian分组的技术。我可以使用XSL 2.0,但是,尽管for each group比我目前所做的工作更简洁,但它没有解决以下问题:例如,如何将选择声明为可以使用的单个XPath语句,这个答案与我已经采用的解决方案具有相同的结构,尽管有点简洁,但没有解决我提出的实际问题:这可以作为单个XPath语句来实现吗?如果可以,如何实现?不过,我想从这里可以猜到,答案是这是不可能的。我的XSLT 1.0解决方案是对XSLT 2.0的重写(在这里,每个组都需要),但我将向您展示如何在XSLT 1.0和2.0中定义键的情况下,使用单个表达式过滤掉每个组中的第一个表达式。@rumplestiltzkin,我对答案进行了编辑,以展示如何在节点集上分别按唯一的个人
项目顺序应用模板。但是,它是XSLT和XPath的组合,而不是单个XPath表达式!我曾尝试过使用Muenchian分组方法,但我无法让它用于元素和属性,只能用于原子数据。很明显,我搜索得不够深入。这个答案与我已经采用的解决方案的结构相同,虽然有点简洁,但没有解决我提出的实际问题:这可以作为一个XPath语句来完成吗?如果可以,如何完成?不过,我想从这里可以猜到,答案是这是不可能的。我的XSLT 1.0解决方案是对XSLT 2.0的重写(在这里,每个组都需要),但我将向您展示如何在XSLT 1.0和2.0中定义键的情况下,使用单个表达式过滤掉每个组中的第一个表达式。@rumplestiltzkin,我对答案进行了编辑,以展示如何在节点集上分别按唯一的个人
项目顺序应用模板。但是,它是XSLT和XPath的组合,而不是单个XPath表达式!我曾尝试过使用Muenchian分组方法,但我无法让它用于元素和属性,只能用于原子数据。很明显,我找得不够远。
<events>
<event date="2013-06-17">
<person first="Joe" last="Bloggs" />
<person first="John" last="Smith" />
</event>
<event date="2013-01-29">
<person first="Jane" last="Smith" />
<person first="John" last="Smith" />
</event>
<event date="2012-09-03">
<person first="Joe" last="Bloggs" />
<person first="John" last="Doe" />
</event>
<event date="2012-04-05">
<person first="Jane" last="Smith" />
<person first="John" last="Smith" />
<person first="John" last="Doe" />
</event>
</events>
<person first="Joe" last="Bloggs"/>
<person first="John" last="Smith"/>
<person first="Jane" last="Smith"/>
<person first="John" last="Doe"/>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="by-name" match="event/person" use="concat(@first, '|', @last)"/>
<xsl:template match="events">
<xsl:for-each select="event/person[generate-id() = generate-id(key('by-name', concat(@first, '|', @last))[1])]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="by-name" match="event/person" use="concat(@first, '|', @last)"/>
<xsl:template match="events">
<xsl:copy-of select="event/person[generate-id() = generate-id(key('by-name', concat(@first, '|', @last))[1])]"/>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="by-name" match="event/person" use="concat(@first, '|', @last)"/>
<xsl:template match="events">
<xsl:apply-templates select="event/person[generate-id() = generate-id(key('by-name', concat(@first, '|', @last))[1])]"/>
</xsl:template>
<xsl:template match="person">
<foo>...</foo>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="events">
<xsl:variable name="first-person-in-groups" as="element(person)*">
<xsl:for-each-group select="event/person" group-by="concat(@first, '|', @last)">
<xsl:copy-of select="."/>
</xsl:for-each-group>
</xsl:variable>
<xsl:apply-templates select="$first-person-in-groups"/>
</xsl:template>
<xsl:template match="person">
<foo>...</foo>
</xsl:template>
</xsl:stylesheet>