XSLT中属性选择为何无返回值?字典匹配问题排查
问题:XSLT中字典匹配无返回值的原因及解决办法
给定输入XML:
<Root> <Entry> <Number>123456</Number> <Key>1</Key> </Entry> </Root>
应用以下XSLT 2.0转换:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" byte-order-mark="yes" omit-xml-declaration="yes"/> <xsl:variable name="myDictionary" as="element()"> <dictionary> <entry key="1">A</entry> <entry key="2">B</entry> <entry key="3">C</entry> <entry key="4">D</entry> <entry key="5">E</entry> <entry key="6">F</entry> <entry key="7">G</entry> <entry key="8">H</entry> <entry key="9">I</entry> <entry key="10">J</entry> <entry key="11">K</entry> <entry key="12">L</entry> <entry key="13">M</entry> <entry key="14">N</entry> <entry key="15">O</entry> </dictionary> </xsl:variable> <xsl:template match="/"> <xsl:apply-templates select="Root/Entry"/> </xsl:template> <xsl:template match="Entry"> <!-- Employee Identifier --> <xsl:value-of select="Number"/> <xsl:text> : </xsl:text> <xsl:value-of select="Key"/> <xsl:text> : </xsl:text> <xsl:value-of select="$myDictionary/entry[@key=Key]"/> <xsl:text> : </xsl:text> <xsl:value-of select="$myDictionary/entry[@key='1']"/> </xsl:template> </xsl:stylesheet>
预期输出:
123456 : 1 : A : A
实际输出:
123456 : 1 : : A
可见硬编码@key='1'能正确匹配到值,但@key=Key的筛选逻辑无返回值,需要排查原因并解决,同时了解key()函数的正确用法。
原因分析
问题出在XPath的上下文节点上:当执行$myDictionary/entry[@key=Key]时,筛选条件里的Key是相对于当前遍历的字典entry节点的,而字典中的entry元素并没有名为Key的子节点,所以匹配结果为空。此时你需要的是原XML中Entry节点下的Key值,而非字典entry的子节点。
解决办法
有两种简单的修复方式:
方式1:提前存储当前Key值到变量
把原XML的Key值存入变量,在筛选时直接引用变量,避免上下文混淆:
<xsl:template match="Entry"> <!-- 先把当前Entry的Key值存到变量 --> <xsl:variable name="currentEntryKey" select="Key"/> <xsl:value-of select="Number"/> <xsl:text> : </xsl:text> <xsl:value-of select="Key"/> <xsl:text> : </xsl:text> <!-- 引用变量匹配字典 --> <xsl:value-of select="$myDictionary/entry[@key=$currentEntryKey]"/> <xsl:text> : </xsl:text> <xsl:value-of select="$myDictionary/entry[@key='1']"/> </xsl:template>
方式2:使用current()函数明确上下文
current()函数可以直接引用当前模板匹配的节点(也就是原XML的Entry节点),通过它来获取Key值:
<xsl:template match="Entry"> <xsl:value-of select="Number"/> <xsl:text> : </xsl:text> <xsl:value-of select="Key"/> <xsl:text> : </xsl:text> <!-- 用current()明确指向当前Entry节点的Key --> <xsl:value-of select="$myDictionary/entry[@key=current()/Key]"/> <xsl:text> : </xsl:text> <xsl:value-of select="$myDictionary/entry[@key='1']"/> </xsl:template>
两种方式都能让筛选逻辑正确匹配到字典中的对应值,输出符合预期。
关于key()函数的补充用法
如果字典条目较多,使用key()函数可以通过索引提升查找效率,具体步骤如下:
- 在样式表中定义key:
<!-- 定义key,匹配字典的entry元素,用@key作为索引键 --> <xsl:key name="dictionaryKey" match="entry" use="@key"/>
- 在模板中调用key函数,需要指定字典节点作为上下文(有两种方式):
<xsl:template match="Entry"> <xsl:value-of select="Number"/> <xsl:text> : </xsl:text> <xsl:value-of select="Key"/> <xsl:text> : </xsl:text> <!-- 方式1:通过xsl:for-each切换上下文到字典节点 --> <xsl:for-each select="$myDictionary"> <xsl:value-of select="key('dictionaryKey', current()/Key)"/> </xsl:for-each> <!-- 方式2:使用key()的第三个参数指定上下文节点(XSLT 2.0及以上支持) --> <!-- <xsl:value-of select="key('dictionaryKey', Key, $myDictionary)"/> --> <xsl:text> : </xsl:text> <xsl:value-of select="$myDictionary/entry[@key='1']"/> </xsl:template>
这样就能利用key的索引机制快速定位到对应条目,适合大规模字典的场景。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

