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>
С этим входом:
<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>
Я получаю:
<output>
<Description>desc1</Description>
<Description>desc2</Description>
</output>
Краткое объяснение части таблицы стилей, которая выполняет тяжелую работу:
$file != ''
and
generate-id()
=
generate-id(key('kDescription', .)[../File = $file][1])
Первая часть очевидна - она просто для того, чтобы убедиться, что $file
строка фильтра была передана.
Вторая часть - простая мюнхенская группировка с небольшим поворотом. Он сравнивает идентификаторы двух узлов: текущего (generate-id()
) и одного из группы kDescription
, отфильтрованных по значению $file
.
kDescription
индексирует <Description>
элементы по их текстовому значению, что означает, что узлы с тем же текстом, но с другим сопровождающим <File>
будут возвращены при вызове key()
. Нам нужно отфильтровать их.
Если текущий узел равен первому узлу группы, который имеет правильное значение <File>
, тест завершается успешно и что-то печатается, в противном случае ничего не происходит.