Извлечение одного элемента и фильтрация другим - PullRequest
1 голос
/ 23 октября 2009

Попытался и не смог изменить XSL отсюда: Отдельные элементы и группировки

Я пишу здесь, чтобы спросить, может ли кто-нибудь помочь, пожалуйста. Я в основном получил ту же структуру данных (моя на самом деле RSS-лента продуктов), что и в предыдущем посте, но я хочу перечислить элементы Description уникально, в отсортированном порядке, где элемент File содержит определенное значение.

Я полагаю, что XPath для выбора файла будет:

*/File[text()='file1']

например, чтобы взять только элементы File, содержащие текст "file1".

Я не могу понять, как получить: «отсортированы все отдельные элементы Description, у которых есть одноуровневый элемент File со значением 'file1'".

Любая помощь будет очень, очень ценится!

Спасибо

Мт.

1 Ответ

1 голос
/ 23 октября 2009

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>, тест завершается успешно и что-то печатается, в противном случае ничего не происходит.

...