xslt соответствует первым x элементам отфильтрованного результирующего набора - PullRequest
3 голосов
/ 21 февраля 2011

Совершенно новый для xslt, так что простите меня, если это основной вопрос - я не могу найти ответ ни в SO, ни в поиске в Google.

Я пытаюсь вернуть отфильтрованный набор узлов, а затем сопоставить шаблон с первыми 1 или 2 элементами в этом наборе, а другой шаблон с остальным. Однако мне кажется, что я не могу сделать это без цикла <xsl:for-each /> (что крайне нежелательно, поскольку я могу сопоставлять 3000 узлов и обрабатывать только 1 по-разному).

Использование position() не работает, так как это не зависит от фильтрации. Я попытался отсортировать набор результатов, но, похоже, он не вступает в силу достаточно рано, чтобы повлиять на соответствие шаблона. <xsl:number /> выводит правильные числа, но я не могу использовать их в выражении соответствия.

Я поместил пример кода ниже. Я использую неподходящий метод position() ниже для иллюстрации проблемы.

Заранее спасибо!

XML:

<?xml version="1.0" encoding="utf-8"?>
<news>
    <newsItem id="1">
        <title>Title 1</title>
    </newsItem>
    <newsItem id="2">
        <title>Title 2</title>
    </newsItem>
    <newsItem id="3">
        <title></title>
    </newsItem>
    <newsItem id="4">
        <title></title>
    </newsItem>
    <newsItem id="5">
        <title>Title 5</title>
    </newsItem>
</news>

XSL:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <ol>
            <xsl:apply-templates select="/news/newsItem [string(title)]" />
        </ol>
    </xsl:template>

    <xsl:template match="newsItem [position() &lt; 4]">
        <li>
            <xsl:value-of select="title"/>
        </li>
    </xsl:template>

    <xsl:template match="*" />
</xsl:stylesheet>

Желаемый результат:

  1. Заголовок 1
  2. Заголовок 2
  3. Заголовок 5

1 Ответ

6 голосов
/ 21 февраля 2011

Это на самом деле проще, чем вы думаете. Есть:

 <xsl:template match="newsItem[string(title)][position() &lt; 4]">

И удалите предикат [string (title)] из вашего <xsl:apply-templates выбора.

Как это:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <ol>
            <xsl:apply-templates select="/news/newsItem" />
        </ol>
    </xsl:template>

    <xsl:template match="newsItem[string(title)][position() &lt; 4]">
        <li><xsl:value-of select="position()" />
            <xsl:value-of select="title"/>
        </li>
    </xsl:template>

    <xsl:template match="*" />
</xsl:stylesheet>

Здесь вы эффективно применяете второй фильтр ([position() &lt; 4]) после фильтра [string(title)], в результате чего position() применяется к фильтрованному списку.

...