Создать переменную набора узлов из фрагмента дерева результатов, используя <xsl: choose>

Можно ли создать переменную набора узлов из RTF, используя xsl:choose (для использования в движке MSXML)?

У меня есть следующая конструкция:

<xsl:choose>
    <xsl:when test="function-available('msxsl:node-set')">
        <xsl:variable name="colorList" select="msxsl:node-set($std:colorList)"/>
        <xsl:for-each select="$colorList/color">
             tr.testid<xsl:value-of select="@testid"/> {
                color:<xsl:value-of select="."/>;
            }
       </xsl:for-each>
    </xsl:when>
    <xsl:otherwise>
        <xsl:variable name="colorList" select="$std:colorList"/>
        <xsl:for-each select="$colorList/color">
             tr.testid<xsl:value-of select="@testid"/> {
                color:<xsl:value-of select="."/>;
            }
       </xsl:for-each>
    </xsl:otherwise>
</xsl:choose>

std:colorList будучи фрагментом дерева, конечно. Вышеприведенное работает отлично, и это нормально, потому что код одинаков для двух альтернатив, но не такой большой.
Но для больших фрагментов кода мне интересно, можно ли избежать дублирования кода, сначала объявив переменную на основе rtf, а затем выполнив код; что-то вроде

<xsl:variable name="colorList">
    <xsl:choose>
        <xsl:when test="function-available('msxsl:node-set')">
            <xsl:copy-of select="msxsl:node-set($std:colorList)"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="$std:colorList"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

<xsl:for-each select="$colorList/color">
     tr.testid<xsl:value-of select="@testid"/> {
        color:<xsl:value-of select="."/>;
    }
</xsl:for-each>

Но это не работает должным образом: MSXML жалуется на colorList не является набором узлов, поэтому его нельзя использовать в xsl:for-each,

XSL transformation failed due to following error:
Expression must evaluate to a node-set.
-->$colorList<--/color

Обратите внимание, что в рабочем примере эта ошибка не возникла из-за "копирования" std:colorList в colorList переменная. Очевидно, это ошибка разбора xsl, а не ошибка времени выполнения.
Должен ли я использовать что-то еще, чем xsl:copy-of? Или есть другой способ добиться того же?

Если вам интересно, std:colorList Содержание выглядит следующим образом:

<std:colorList>
    <color testid="111">#FF0000</color>
    <color testid="999">#FFFF00</color>
</std:colorList>

2 ответа

Решение

К сожалению, в XSLT 1.0, когда xsl:variable содержит инструкции, а не атрибут select, результатом всегда является RTF. Так что ваши осторожные попытки конвертировать RTF в набор узлов ни к чему не приводят, потому что он снова конвертируется.

Боюсь, что нет чистого обходного пути (кроме перехода на XSLT 2.0, конечно). Я бы предложил структурировать код следующим образом:

<xsl:choose>
    <xsl:when test="function-available('msxsl:node-set')">
        <xsl:apply-templates select="msxsl:node-set($std:colorList)/color" mode="z"/>
    </xsl:when>
    <xsl:otherwise>
        <xsl:apply-templates select="$std:colorList/color" mode="z"/>
    </xsl:otherwise>
</xsl:choose>

<xsl:template match="color" mode="z">
     tr.testid<xsl:value-of select="@testid"/> {
                color:<xsl:value-of select="."/>;
            }
</xsl:template>

Просто для протокола, я добавляю окончательное решение ниже. Это немного отличается от того, что предложил Майкл, добавив копию RTF в переменную перед применением шаблона.
Это связано с тем, что в противном случае MSXML все еще выдает ошибки во время синтаксического анализа xsl (очевидно, он проверяет значение select apply-templates и приходит к выводу, что это неверно, если это RTF вместо набора узлов. И, как сказал Майкл, атрибут xsl:variable select только это: преобразование RTF в набор узлов.

<xsl:choose>
        <xsl:when test="function-available('msxsl:node-set')">
        <xsl:apply-templates select="msxsl:node-set($std:colorList)/color" mode="addTRclassToCSS"/>
    </xsl:when>
    <xsl:otherwise>
        <xsl:variable name="colorList" select="$std:colorList"/>
        <xsl:apply-templates select="$colorList" mode="addTRclassToCSS"/>
    </xsl:otherwise>
</xsl:choose>


<xsl:template match="color" mode="addTRclassToCSS">
                tr.testid<xsl:value-of select="@testid"/> {
                color:<xsl:value-of select="."/>;
                }
</xsl:template>
Другие вопросы по тегам