如何修正XSLT代码以输出符合预期的每周菜单结果
问题根因
你的代码无法输出菜品,核心是3个XSLT 1.0的基础语法问题:
- 结果树片段(RTF)无法直接查询:XSLT 1.0中,用
<xsl:variable>包裹模板输出生成的是结果树片段,标准语法不支持直接用XPath选取RTF内的节点,所以你写的$menu/dish匹配不到任何菜品,循环不会执行。 - 缺少换行控制符:XSLT输出文本时,标签之间的空白默认会被压缩忽略,你没有手动加换行符(

),就算能输出菜品也会全部挤在同一行。 - 周数参数与预期不匹配:你给出的预期输出对应
week参数值为4,不是代码里写的2,原位置公式是标准的循环选菜逻辑(到分类最后一个菜品后回到第一个循环),如果需要停在最后一个不循环可以自行调整判断逻辑。
最简单的修改方案(适合初学者)
完全放弃用变量存储中间菜单的写法,直接在根模板里计算每个分类要选的菜品、输出内容,彻底避开RTF限制,逻辑更直观:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="utf-8"/> <!-- 预期输出对应week值为4,可自行修改 --> <xsl:param name="week" select="4"/> <!-- 封装计算菜品位置的逻辑,标准循环规则:到最后一个后回到第一个 --> <xsl:template name="get-position"> <xsl:param name="total"/> <xsl:variable name="mod-result" select="($week - 1) mod $total"/> <xsl:value-of select="$mod-result + 1"/> </xsl:template> <xsl:template match="/"> <!-- 输出标题加换行 --> <xsl:text>This week's menu:
</xsl:text> <!-- 选开胃菜 --> <xsl:variable name="appetizer-total" select="count(/menu/appetizers/dish)"/> <xsl:variable name="appetizer-pos"> <xsl:call-template name="get-position"> <xsl:with-param name="total" select="$appetizer-total"/> </xsl:call-template> </xsl:variable> <xsl:variable name="appetizer" select="/menu/appetizers/dish[position() = $appetizer-pos]"/> <xsl:text>- </xsl:text><xsl:value-of select="$appetizer"/> <xsl:text> $</xsl:text><xsl:value-of select="$appetizer/@price"/> <xsl:text>
</xsl:text> <!-- 选主菜 --> <xsl:variable name="entree-total" select="count(/menu/entrees/dish)"/> <xsl:variable name="entree-pos"> <xsl:call-template name="get-position"> <xsl:with-param name="total" select="$entree-total"/> </xsl:call-template> </xsl:variable> <xsl:variable name="entree" select="/menu/entrees/dish[position() = $entree-pos]"/> <xsl:text>- </xsl:text><xsl:value-of select="$entree"/> <xsl:text> $</xsl:text><xsl:value-of select="$entree/@price"/> <xsl:text>
</xsl:text> <!-- 选甜点,如需week=4时固定选最后一个,可在此处修改位置判断逻辑 --> <xsl:variable name="dessert-total" select="count(/menu/desserts/dish)"/> <xsl:variable name="dessert-pos"> <xsl:call-template name="get-position"> <xsl:with-param name="total" select="$dessert-total"/> </xsl:call-template> </xsl:variable> <xsl:variable name="dessert" select="/menu/desserts/dish[position() = $dessert-pos]"/> <xsl:text>- </xsl:text><xsl:value-of select="$dessert"/> <xsl:text> $</xsl:text><xsl:value-of select="$dessert/@price"/> <xsl:text>
</xsl:text> </xsl:template> </xsl:stylesheet>
初学者提示
- XSLT 1.0的RTF限制是最常见的新手坑,如果你一定要保留中间变量存节点的写法,需要引入处理器支持的
node-set扩展函数(比如EXSLT的exsl:node-set),把RTF转成可查询的节点集后再做遍历,但这种写法依赖处理器兼容性,不如直接输出逻辑简单。 - 输出纯文本时,所有换行、空格、前缀符号都要用
<xsl:text>明确包裹,否则XSLT默认会压缩忽略无意义的空白。 - 做循环索引计算时,一定要注意XPath的序列是从1开始计数的,可以根据自己的业务需求调整位置判断规则,比如需要到最后一个菜品后停止循环,就在
mod结果为0且week不等于1时返回总数量即可。
内容的提问来源于stack exchange,提问作者Alexandru
相关产品推荐
相关产品推荐

