создать переменную набора узлов из фрагмента дерева результатов, используя - PullRequest
1 голос
/ 23 марта 2012

Можно ли создать переменную набора узлов из 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 ]

3 голосов
/ 23 марта 2012

К сожалению, в 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>
0 голосов
/ 23 марта 2012

Просто для справки, я добавляю окончательное решение ниже.Это немного отличается от того, что предложил Майкл, добавив копию 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>
...