Umbraco - 创建节点变量 - 如何检查缺失值

时间:2015-08-26 08:25:30

标签: xslt xslt-1.0 umbraco xslt-2.0

我正在使用Umbraco 4.5(是的,我知道我现在应该升级到7!)

我有一个XSLT转换,它构建了一个与用户过滤器匹配的产品列表。

我正在制作一个XSL:变量,它是CMS数据库中产品的集合。

每个产品都有几个是/否属性(单选按钮)。但其中一些尚未填充。

因此,如果数据集包含没有填充答案的选项之一的产品,则以下代码会偶尔中断。

转换XSLT时得到的错误是“对于Int32,值太大或太小”。我假设这是传递给GetPreValueAsString方法的值。

如何检查./option1是否为空,如果是,请使用特定的整数,否则请使用./option1

<xsl:variable name="nodes" 
    select="umbraco.library:GetXmlNodeById(1098)/* 
    [@isDoc and string(umbracoNaviHide) != '1' and 
    ($option1= '' or $option1=umbraco.library:GetPreValueAsString(./option1)) and
    ($option2= '' or $option2=umbraco.library:GetPreValueAsString(./option2)) and
    ($option3= '' or $option3=umbraco.library:GetPreValueAsString(./option3)) and
    ($option4= '' or $option4=umbraco.library:GetPreValueAsString(./option4)) 
    ]" />

1 个答案:

答案 0 :(得分:1)

注意:您将问题标记为XSLT 2.0,但Umbraco不使用XSLT 2.0,它(目前)仍然使用XSLT 1.0。

$option1= '' or $option1=umbraco.library:GetPreValueAsString(./option1)

您的错误可能有多种原因。处理器不需要从左到右或从右到左处理or表达式,甚至允许总是评估两个表达式,即使第一个表达式为真(这与逐位运算符相当(其他语言中的无序),而这些语言中的布尔运算符(有序)通常使用早期突破)。

另一个错误可能是您的上下文节点中的选项值不为空且不是整数或空,在这种情况下,您的代码将始终返回错误。

您可以通过测试./optionX来扩展您的表达式,但是您仍然存在评估顺序的问题。

那说,你怎么解决它并防止错误产生?在XSLT 1.0中,这有点笨拙(即,你不能定义函数而不能使用序列),但这是一种方法:

<xsl:variable name="pre-default-option">
    <default>1</default>
    <default>2</default>
    <default>3</default>
    <default>4</default>
</xsl:variable>

<xsl:variable name="default-option"
    select="exslt:node-set($pre-default-option)" />

<xsl:variable name="pre-selected-option">
    <option><xsl:value-of select="$option1" /></option>
    <option><xsl:value-of select="$option2" /></option>
    <option><xsl:value-of select="$option3" /></option>
    <option><xsl:value-of select="$option4" /></option>
</xsl:variable>

<xsl:variable name="selected-option" select="exslt:node-set($pre-selected-option)" />

<xsl:variable name="pre-process-nodes">
    <xsl:variable name="selection">
        <xsl:apply-templates 
            select="umbraco.library:GetXmlNodeById(1098)/*"
            mode="pre">
            <xsl:with-param name="opt-no" select="1" />
        </xsl:apply-templates>
    </xsl:variable>

    <!-- your original code uses 'and', so is only true if all 
         conditions are met, hence there must be four found nodes, 
         otherwise it is false (i.e., this node set will be empty) -->
    <xsl:if test="count($selection) = 4">
         <xsl:copy-of select="$selection" />
    </xsl:if>
</xsl:variable>

<!-- your original variable, should now contain correct set, no errors -->
<xsl:variable name="nodes" select="exslt:node-set($pre-process-nodes)"/>

<xsl:template match="*[@isDoc and string(umbracoNaviHide) != '1']" mode="pre">
    <xsl:param name="opt-no" />

    <xsl:variable name="option"
        select="$selected-option[. = string($opt-no)]" />

    <!-- gets the child node 'option1', 'option2' etc -->
    <xsl:variable 
        name="pre-ctx-option" 
        select="*[local-name() = concat('option', $opt-no)]" />

    <xsl:variable name="ctx-option">
        <xsl:choose>

            <!-- empty option param always allowed -->
            <xsl:when test="$option = ''">
                <xsl:value-of select="$option"/>
            </xsl:when>

            <!-- if NaN or 0, this will return false -->
            <xsl:when test="number($pre-ctx-option)">
                <xsl:value-of select="$default-option[$opt-no]"/>
            </xsl:when>

            <!-- valid number (though you could add a range check as well) -->
            <xsl:otherwise>
                <xsl:value-of select="umbraco.library:GetPreValueAsString($pre-ctx-option)"/>
            </xsl:otherwise>
         </xsl:choose>
    </xsl:variable>

    <!-- prevent eternal recursion -->
    <xsl:if test="4 >= $opt-no">
        <xsl:apply-templates select="self::*" mode="pre">
            <xsl:with-param name="opt-no" select="$opt-no + 1" />
        </xsl:apply-templates>
        <!-- the predicate is now ctx-independent and just true/false
             this copies nothing if the conditions are not met -->
        <xsl:copy-of select="self::*[$option = $ctx-option]" />
    </xsl:if>
</xsl:template>

<xsl:template match="*" mode="pre" />

注意(1):我手写了上面的代码,只测试了语法错误,我无法测试它,因为你没有提供输入文档来测试它。如果您发现错误,请务必编辑我的回复以使其正确无误。

注意(2):上面的代码概括了使用编号参数。通过概括,代码变得有点复杂,但是它变得更容易维护和扩展,并且更容易出现复制/粘贴错误。