如何通过XSLT遍历两个变量并生成不含重复ID的新变量?
问题:筛选$A中未在$B出现的asset节点
我有两个XSLT变量:
<xsl:variable name="A"> <asset id="111">[...]</asset> <asset id="222">[...]</asset> </xsl:variable> <xsl:variable name="B"> <asset id="333">[...]</asset> <asset id="444">[...]</asset> <asset id="111">[...]</asset> <asset id="555">[...]</asset> <asset id="999">[...]</asset> </xsl:variable>
需求:取出$A中每个asset节点的id值,检查该id是否未在$B的asset节点中出现。若未出现,则将$A中的当前asset节点复制到新变量$Final中。正确结果应该是$Final仅包含id为222的asset节点。
我尝试了以下代码,无法实现需求:
<xsl:variable name="Final"> <xsl:for-each select="$A/asset"> <xsl:variable name="presentXML"> <xsl:copy-of select="."/> </xsl:variable> <xsl:variable name="presentID"> <xsl:value-of select="./@id"/> </xsl:variable> <xsl:for-each select="$B/asset"> <xsl:variable name="pastID"> <xsl:value-of select="./@id"/> </xsl:variable> <xsl:choose> <xsl:when test="$presentID != $pastID"> <xsl:copy-of select="$presentXML"/> </xsl:when> <xsl:otherwise> </xsl:otherwise > </xsl:choose> </xsl:for-each> </xsl:for-each> </xsl:variable>
问题分析
你的代码逻辑错误在于:遍历$B的每个asset时,只要当前$A的asset id和单个$B的asset id不等就执行复制。这会导致同一个$A的asset被多次复制(比如id=111的asset,会和$B中id为333、444、555、999的asset都触发不等判断,从而被复制4次),而我们需要的是当$A的asset id在$B中完全不存在时才复制该节点。
正确实现方法
方法1:XSLT 1.0兼容写法
XSLT 1.0不支持直接的节点序列比较,可通过判断$B中是否存在匹配id的asset节点来实现:
<xsl:variable name="Final"> <!-- 遍历$A中的每个asset --> <xsl:for-each select="$A/asset"> <!-- 保存当前asset的id,避免多次查询 --> <xsl:variable name="currentId" select="@id"/> <!-- 判断$B中是否没有id等于$currentId的asset --> <xsl:if test="not($B/asset[@id = $currentId])"> <!-- 复制当前asset节点到$Final --> <xsl:copy-of select="."/> </xsl:if> </xsl:for-each> </xsl:variable>
方法2:XSLT 2.0+简洁写法
XSLT 2.0及以上版本支持节点序列的直接比较,写法更简洁:
<xsl:variable name="Final"> <!-- 直接筛选$A中id不在$B的asset id序列中的节点 --> <xsl:copy-of select="$A/asset[not(@id = $B/asset/@id)]"/> </xsl:variable>
两种方法最终都会生成仅包含id为222的asset节点的$Final变量。
内容的提问来源于stack exchange,提问作者RFA
相关产品推荐
相关产品推荐

