XSLT使用xsltproc处理多文件时提取唯一元素异常问题求助
问题原因
- 命名空间匹配错误:你的cooking.xml、menu.xml都声明了默认命名空间
https://cooking.com/2022/cooking,但XSLT中定义的cook前缀并没有用到节点匹配、路径查询、key定义的规则中,导致key('rcp', $menu)匹配不到任何节点,这是你当前输出为空的直接原因。 - preceding-sibling轴作用域限制:
preceding-sibling仅能查询和当前节点属于同一个父节点的前置兄弟节点。你执行cooking/recipe[@name = $menu]/ingredients查询得到的是分属不同recipe节点的ingredient集合,每个ingredient仅能感知到自己所属recipe下的兄弟节点,自然返回多个独立的食材集合,无法实现跨recipe去重。
修复方案
你可以使用XSLT 1.0标准的Muenchian分组法实现去重,无需依赖EXSLT扩展,修正后的完整样式表如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cook="https://cooking.com/2022/cooking" exclude-result-prefixes="cook"> <xsl:output method="xml" encoding="UTF-8" indent="yes"/> <!-- 定义食材去重用的key,匹配规则加上命名空间前缀 --> <xsl:key name="ingredient" match="cook:ingredient" use="@name" /> <xsl:template match="cook:cooking"> <cooking xmlns="https://cooking.com/2022/cooking"> <xsl:variable name="menu" select="cook:recipe/@name" /> <!-- 切换上下文到cooking.xml使用key --> <xsl:for-each select="document('cooking.xml')"> <!-- 选中菜单对应食谱的食材,Muenchian法去重 --> <xsl:for-each select="cook:cooking/cook:recipe[@name = $menu]/cook:ingredient[count(. | key('ingredient', @name)[1]) = 1]"> <ingredient name="{@name}"/> </xsl:for-each> </xsl:for-each> </cooking> </xsl:template> </xsl:stylesheet>
执行原命令xsltproc shop.xsl menu.xml > ingredients.xml即可得到你期望的输出结果。
如果你希望继续使用EXSLT的set:distinct方法,只需要将原有样式表中所有节点匹配、路径查询的规则都加上cook前缀即可正常工作。
内容的提问来源于stack exchange,提问作者Jon Smirl
相关产品推荐
相关产品推荐

