XSLT для каждого цикла для сбора элементов - PullRequest
3 голосов
/ 06 мая 2010

Можно ли сделать цикл для каждого в XSLT не для набора узлов, а для моей собственной коллекции элементов? Например, я разбил некоторую строку и в результате получил коллекцию строк. И мне нужно создать узел для каждого элемента в коллекции. Я знаю, что эту проблему можно решить с помощью рекурсивного шаблона, но я хочу знать, возможно ли избежать рекурсии.

Ответы [ 3 ]

1 голос
/ 06 мая 2010

Существует два очевидных, простых решения, одно из которых поддерживается только в XSLT 2.0:

I. Общее решение

Это работает как с XSLT 1.0, так и с XSLT 2.0.

Определите свое собственное пространство имен и поместите свой набор узлов в качестве дочерних элементов элемента в этом пространстве имен, причем этот элемент глобально помещен в таблицу стилей (дочерний элемент инструкции <xsl:stylesheet>.)

Вот пример:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" exclude-result-prefixes="my"
 >
 <xsl:output method="text"/>

 <my:nodes>
   <string>Hello </string>
   <string>World</string>
 </my:nodes>

 <xsl:variable name="vLookup"
    select="document('')/*/my:nodes/*"/>

 <xsl:param name="pSearchWord" select="'World'"/>

 <xsl:template match="/">
   <xsl:if test="$pSearchWord = $vLookup">
     <xsl:value-of select=
       "concat('Found the word ', $pSearchWord)"/>
   </xsl:if>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к любому документу XML (не используется), результат будет :

Found the word World

Обратите внимание , что нам вообще не нужна функция расширения xxx:node-set().

II. Решение XSLT 2.0 / XPath 2.0

В XSLT 2.0 / XPath 2.0 всегда можно использовать тип sequence . Например, можно просто определить переменную, которая будет содержать последовательность строк, следующим образом:

 <xsl:variable name="vLookup" as="xs:string*"
    select="'Hello', 'World'"/>

и используйте его как в следующем преобразовании:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 >
 <xsl:output method="text"/>

 <xsl:variable name="vLookup" as="xs:string*"
    select="'Hello', 'World'"/>

 <xsl:param name="pSearchWord" select="'World'"/>

 <xsl:template match="/">
   <xsl:if test="$pSearchWord = $vLookup">
     <xsl:value-of select=
       "concat('Found the word ', $pSearchWord)"/>
   </xsl:if>
 </xsl:template>
</xsl:stylesheet>
1 голос
/ 06 мая 2010

Это можно сделать с помощью функции расширения XPath node-set(). Эта функция поддерживается, например, расширениями msxsl и exslt .

MSDN приводит пример использования функции msxsl:node-set() с xsl:for-each:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:user="http://www.contoso.com"
                version="1.0">
    <xsl:variable name="books">
        <book author="Michael Howard">Writing Secure Code</book>
        <book author="Michael Kay">XSLT Reference</book>
    </xsl:variable>

    <xsl:template match="/">
        <authors>
            <xsl:for-each select="msxsl:node-set($books)/book"> 
                <author><xsl:value-of select="@author"/)</author>
            </xsl:for-each>
        </authors>
    </xsl:template>
</xsl:stylesheet>
0 голосов
/ 06 мая 2010

Какую платформу вы используете, какой процессор XSLT вы точно используете? Вам нужно будет предоставить свою коллекцию строк в виде типа данных, поддерживаемых вашим процессором XSLT. Какой именно это зависит полностью от API, поддерживаемого вашим процессором XSLT. Например, для .NET XslCompiledTransform вам потребуется обеспечить XPathNodeIteratator.

...