如何在XSLT中使用带有两个匹配条件的键?
如何在XSLT中使用带有两个匹配条件的键?
看起来你想要把XML里相同RecordId的<object>元素分组,然后在每个组里获取特定AttributeName(比如MBRSH、Label)对应的AttributeValue对吧?你的Muenchian方法尝试方向是对的,但问题出在键的定义没有把RecordId和AttributeName关联起来,导致每次拿到的都是全局的匹配结果,而不是对应RecordId组内的结果。
我来给你调整一下思路和代码:
首先,我们可以通过两种方式实现需求:一种是用组合键精准定位,另一种是先分组再组内查找,两种方式都能解决你遇到的问题。
方法一:用组合键精准匹配
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 键1:按RecordId分组所有object --> <xsl:key name="objects-by-recordid" match="array/object" use="property[@name='RecordId']/literal" /> <!-- 键2:用RecordId+AttributeName的组合值作为键,定位对应AttributeValue --> <xsl:key name="attr-by-name-and-id" match="array/object/property[@name='AttributeValue']/literal" use="concat(../../property[@name='RecordId']/literal, '|', ../property[@name='AttributeName']/literal)" /> <xsl:template match="/"> <!-- 遍历所有唯一的RecordId分组(自动去重) --> <xsl:for-each select="array/object[count(. | key('objects-by-recordid', property[@name='RecordId']/literal)[1]) = 1]"> <xsl:variable name="current-recordid" select="property[@name='RecordId']/literal" /> <!-- 获取当前RecordId下各个属性对应的值 --> <xsl:variable name="mbrsh-value" select="key('attr-by-name-and-id', concat($current-recordid, '|', 'MBRSH'))" /> <xsl:variable name="label-value" select="key('attr-by-name-and-id', concat($current-recordid, '|', 'Label'))" /> <xsl:variable name="is-active-value" select="key('attr-by-name-and-id', concat($current-recordid, '|', 'Is_Active'))" /> <!-- 这里可以输出你需要的结构,示例如下 --> <record> <id><xsl:value-of select="$current-recordid" /></id> <membership><xsl:value-of select="$mbrsh-value" /></membership> <category><xsl:value-of select="$label-value" /></category> <active-status><xsl:value-of select="$is-active-value" /></active-status> </record> </xsl:for-each> </xsl:template> </xsl:stylesheet>
代码说明
objects-by-recordid键:负责把所有<object>按RecordId分组,确保我们只遍历每个RecordId一次,避免重复处理。attr-by-name-and-id键:用RecordId+分隔符+AttributeName的组合值作为键,这样就能精准定位到某个RecordId下特定属性的值,不会和其他RecordId的结果混淆。
方法二:先分组再组内查找(更直观)
如果你觉得组合键有点绕,也可以先拿到当前RecordId的所有对象组,再直接在组内过滤属性:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:key name="objects-by-recordid" match="array/object" use="property[@name='RecordId']/literal" /> <xsl:template match="/"> <xsl:for-each select="array/object[count(. | key('objects-by-recordid', property[@name='RecordId']/literal)[1]) = 1]"> <xsl:variable name="current-group" select="key('objects-by-recordid', property[@name='RecordId']/literal)" /> <xsl:variable name="current-recordid" select="property[@name='RecordId']/literal" /> <record> <id><xsl:value-of select="$current-recordid" /></id> <membership><xsl:value-of select="$current-group[property[@name='AttributeName']/literal='MBRSH']/property[@name='AttributeValue']/literal" /></membership> <category><xsl:value-of select="$current-group[property[@name='AttributeName']/literal='Label']/property[@name='AttributeValue']/literal" /></category> <active-status><xsl:value-of select="$current-group[property[@name='AttributeName']/literal='Is_Active']/property[@name='AttributeValue']/literal" /></active-status> </record> </xsl:for-each> </xsl:template> </xsl:stylesheet>
代码说明
- 先通过
objects-by-recordid键拿到当前RecordId对应的所有对象组current-group,然后直接在组内筛选出AttributeName符合要求的对象,再提取它的AttributeValue,逻辑更直白,适合简单场景。
你之前的问题核心就是没有把RecordId和AttributeName做关联,导致查找时没有限定在当前RecordId的组内,现在用上面两种方法调整后,应该就能得到你想要的结果了。
备注:内容来源于stack exchange,提问作者Ndilokelwa Luis
相关产品推荐
相关产品推荐

