Этого можно достичь в чистом XSLT путем группировки. В XLST 1.0 вы бы использовали мюнхенскую группировку, и в этом случае вам понадобится две группы. Во-первых, вы должны сгруппировать по object , что означает определение ключа для поиска object элементов по ID
<xsl:key name="objects" match="object" use="@id" />
И для поиска первого элемента в каждой группе (т. Е. Уникального идентификатора объекта) вы должны использовать ключ следующим образом:
<xsl:apply-templates
select="//object[generate-id() = generate-id(key('objects', @id)[1])]" />
Затем вы группируете по значению , что означает определение ключа для поиска значения элементов в их соответствующих объектах элементах
<xsl:key name="values" match="value" use="concat(../@id, '|', @name)" />
В этом случае вам действительно нужен последний элемент в каждой группе, поэтому вы должны использовать ключ следующим образом:
<xsl:apply-templates
select="//object[@id = $id]
/value[generate-id()
= generate-id(key('values', concat($id, '|', @name))[last()])]">
Вот полный XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes"/>
<xsl:key name="objects" match="object" use="@id" />
<xsl:key name="values" match="value" use="concat(../@id, '|', @name)" />
<xsl:template match="/">
<xsl:apply-templates select="//object[generate-id() = generate-id(key('objects', @id)[1])]" />
</xsl:template>
<xsl:template match="object">
<xsl:variable name="id" select="@id" />
<xsl:value-of select="concat('object: ', $id, ' ')" />
<xsl:apply-templates select="//object[@id = $id]/value[generate-id() = generate-id(key('values', concat($id, '|', @name))[last()])]">
<xsl:sort select="@name" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="value">
<xsl:value-of select="concat(@name, ':', ., ' ')" />
</xsl:template>
</xsl:stylesheet>
При применении к предоставленному входному XML выводится следующий текст:
object: 1
valName1:OtherText
valName2:Text
valName3:Text
object: 2
valName1:Text