XSLT 1.0:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<!-- index Description elements by their text value -->
<xsl:key name="kDescription" match="Description" use="text()" />
<xsl:template match="/">
<output>
<!-- process all Description elements... -->
<xsl:apply-templates select="Problems/Problem/Description">
<!-- ...sorted by their own text value, ascending -->
<xsl:sort select="text()" />
<!-- pass in the File value that we want to filter for -->
<xsl:with-param name="file" select="'file1'" />
</xsl:apply-templates>
</output>
</xsl:template>
<xsl:template match="Description">
<xsl:param name="file" select="''" />
<!--
check if the current Description node is the first in its
respective group, that has a File value we care for
-->
<xsl:if test="
$file != ''
and
generate-id()
=
generate-id(key('kDescription', .)[../File = $file][1])
">
<!-- for the sake of simplicity, just make a copy here -->
<xsl:copy-of select="." />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
With this input:
<Problems>
<Problem>
<File>file1</File>
<Description>desc1</Description>
</Problem>
<Problem>
<File>file1</File>
<Description>desc2</Description>
</Problem>
<Problem>
<File>file2</File>
<Description>desc3</Description>
</Problem>
<Problem>
<File>file2</File>
<Description>desc1</Description>
</Problem>
<Problem>
<File>file1</File>
<Description>desc2</Description>
</Problem>
</Problems>
I get:
<output>
<Description>desc1</Description>
<Description>desc2</Description>
</output>
A brief explanation of the part of the stylesheet that does the heavy lifting:
$file != ''
and
generate-id()
=
generate-id(key('kDescription', .)[../File = $file][1])
The first part is obvious - it's just there to make sure that a $file
filter string was passed in.
The second part is plain Muenchian grouping with a little twist. It compares the IDs of two nodes, the current one (generate-id()
) and one from the kDescription
group, filtered by $file
value.
kDescription
indexes <Description>
elements by their text value, which means that nodes with the same text but a different accompanying <File>
will be returned by the call to key()
. We need to filter them out.
If the current node is equal to the first node of the group that has the right <File>
value, the test succeeds and something gets printed, otherwise nothing happens.