为啥在 XSLT 转换期间出现此错误:XSLT 转换失败?

Posted

技术标签:

【中文标题】为啥在 XSLT 转换期间出现此错误:XSLT 转换失败?【英文标题】:Why I have this Error during XSLT transformation: XSLT transformation failed?为什么在 XSLT 转换期间出现此错误:XSLT 转换失败? 【发布时间】:2020-06-13 01:58:34 【问题描述】:

我正在尝试根据烹饪内容动态创建一个附加元素 时间要素。我还按烹饪时间和食谱名称对食谱数据进行排序以显示其他元素。

如果烹饪时间超过 60 分钟,新元素应显示“Slow Burner”字样。如果烹饪时间小于或等于 60 分钟且大于或等于 30 分钟,则此新元素应显示“Medium Burner”字样。否则,新元素应显示 Quick and Easy 字样。

我收到一个错误,我不明白为什么 if 语句不起作用。

为什么?

XSL 在这里:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
    <xsl:template match="/collection">
        <html>

        </html>

【问题讨论】:

您确定可以使用 XSLT-2.0 吗?因为您似乎打算在浏览器环境中使用样式表... 是的,我确信 XSLT-2.0。谢谢 你说你遇到了一个错误,所以给我们一个线索 - 告诉我们错误是什么。我们喜欢解决难题,但没有必要通过隐瞒信息来使难题变得更加困难。 【参考方案1】:

自从我弄乱 XSL 以来已经有很长时间了,但我的猜测是您将字符串“30 分钟”视为一个数字:if cooking_time &gt;= 30。如果是这种情况,一种可能的解决方法是在 XML 的属性中包含数字持续时间:

<cooking_time duration="30" unit="minutes">30 minutes</cooking_time>

另外,这可能是复制/粘贴问题,但这看起来不对:

cooking_Time &gt; -or- > 30 &lt; 60

【讨论】:

嗯,我明白了。生病试试这个,看看是否有效。我从这个网站上找到了这个faculty.madisoncollege.edu/schmidt/xml/xmlcond.html【参考方案2】:

您可以将循环更改为以下内容。 recipe 元素的位置已更改为包含在对应的table 中(当然,如果需要,将其改回)。

<xsl:for-each select="recipe">
    <xsl:sort select="cooking_Time" />
    <xsl:variable name="time" select="number(replace(cooking_Time,'minutes',''))" />
    <tr>
        <td>
            <h4>
                <xsl:value-of select="title" />
            </h4>
        </td>
        <td>
            <recipe>
                <xsl:value-of select="if ($time > 60) then 'Slow Burner' else if ($time >= 30) then 'Medium Burner' else 'Quick and Easy'" />
            </recipe>
        </td>
        <td>
            <xsl:value-of select="description" />
        </td>
        <td>
            <xsl:value-of select="servings" />
        </td>
        <td>
            <xsl:value-of select="preparetion_Time" />
        </td>
        <td>
            <xsl:value-of select="cooking_Time" />
        </td>
        <td>
            <xsl:value-of select="passiveTime" />
        </td>
        <td>
            <xsl:value-of select="difficulty" />
        </td>
        <td>
            <xsl:for-each select="ingredients">
                <xsl:for-each select="ingredient">
                    <li>
                        <xsl:value-of select="." />
                    </li>
                </xsl:for-each>
            </xsl:for-each>
        </td>
    </tr>
</xsl:for-each>

这将按cooking_Time 对元素进行排序(您将xsl:sort 放在错误的位置;它必须立即跟随xsl:for-each)。

主要逻辑在这个表达式中:

<xsl:value-of select="if ($time > 60) then 'Slow Burner' else if ($time >= 30) then 'Medium Burner' else 'Quick and Easy'" />

它根据$time 变量的值(为简化表达式而创建)输出适当的字符串。变量中的fn:replace

<xsl:variable name="time" select="number(replace(cooking_Time,'minutes',''))" />

注意$time 变量的值始终是一个数字,并且不包含字符串“分钟”。


如果您不能使用 XSLT-2.0,您也可以使用此 XSLT-1.0 解决方案:

<xsl:for-each select="recipe">
    <xsl:sort select="normalize-space(cooking_Time)" />
    <xsl:variable name="time">
        <xsl:choose>
            <xsl:when test="contains(cooking_Time,'minutes')">
                <xsl:value-of select="number(substring-before(cooking_Time,'minutes'))" />
            </xsl:when>
            <xsl:when test="number(cooking_Time)">
                <xsl:value-of select="number(cooking_Time)" />
            </xsl:when>
            <xsl:otherwise>
                <!-- This value represents any items that don't have a 'cooking_Time' value present -->
                <xsl:value-of select="0" />
            </xsl:otherwise>                                
        </xsl:choose>
    </xsl:variable>
    <tr>
        <td>
            <h4>
                <xsl:value-of select="title" />
            </h4>
        </td>
        <td>
            <recipe>
                <xsl:choose>
                    <xsl:when test="$time &gt; 60">
                        <xsl:text>Slow Burner</xsl:text>
                    </xsl:when>
                    <xsl:when test="$time &gt;= 30 and $time &lt;= 60">
                        <xsl:text>Medium Burner</xsl:text>
                    </xsl:when>
                    <xsl:when test="$time &lt; 30">
                        <xsl:text>Quick and Easy</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>Undefined</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
            </recipe>
        </td>
        <td>
            <xsl:value-of select="description" />
        </td>
        <td>
            <xsl:value-of select="servings" />
        </td>
        <td>
            <xsl:value-of select="preparetion_Time" />
        </td>
        <td>
            <xsl:value-of select="cooking_Time" />
        </td>
        <td>
            <xsl:value-of select="passiveTime" />
        </td>
        <td>
            <xsl:value-of select="difficulty" />
        </td>
        <td>
            <xsl:for-each select="ingredients">
                <xsl:for-each select="ingredient">
                    <li>
                        <xsl:value-of select="." />
                    </li>
                </xsl:for-each>
            </xsl:for-each>
        </td>
    </tr>
</xsl:for-each>

它通过使用normalize-space(...) 改进排序并使用xsl:choose 而不是内联ifs。

【讨论】:

我明确问过您是否可以使用 XSLT-2.0,您说“可以”。在 Firefox 中运行这个样式表是不可能的,因为 Firefox 只支持 XSLT-1.0。 等待几分钟......我正在创建一个应该在 Firefox 中工作的 XSLT-1.0 解决方案。 我添加了一个应该在 Firefox 中工作的 XSLT-1.0 解决方案。 Chrome 仍然值得怀疑。 unit="minutes" 不是标准化的 XML 实体。在一个好的 XML 文件中,此属性将指示单位为 =minutes,并且该值的结尾“分钟”将被省略。因此,我做了从输入中删除“分钟”字符串(如果存在)的技巧。 编码分钟的标准方法是时间duration。您可以找到更多信息here at W3.org。

以上是关于为啥在 XSLT 转换期间出现此错误:XSLT 转换失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的标签在 XSLT 转换后展开(以及如何修复)?

xslt 转换错误:XTSE0010:元素 xsl:mode 不得直接出现在 xsl:stylesheet 中

为啥 XSLT 默认输出所有文本?

为啥 XSLT 生态系统没有与数据可视化广泛关联?

JavaEE XML XSL转换(XSLT)

为啥 XSLT 文档被认为是“样式表”?