XSLT多序列合并及XML属性值聚合问题排查与解决
解决XSLT 2.0中合并元素并处理缺失值的问题
嗨,我看了你遇到的两个问题,其实核心都是上下文节点混淆和变量引用的上下文问题,咱们一步步来搞定:
你的问题根源
- 找不到part元素:在
$allTheProps/prop的循环里,当前上下文节点是你变量里的prop元素,不是正在处理的something节点,所以直接写select="part"自然找不到目标元素。 - 变量判断失效:其实XSLT 2.0完全支持在路径里用变量做判断,问题还是出在上下文不对——你在错误的节点上下文里找
prop,自然匹配不到。
修正后的完整XSLT代码
我帮你调整了代码,同时把静态的prop类型改成了动态获取(更符合你的需求):
<?xml version="1.0" encoding="UTF-8" ?> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output method="xml" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" /> <!-- 动态提取文档中所有唯一的prop类型 --> <xsl:variable name="allPropTypes" select="distinct-values(//prop/@type)" /> <xsl:template match="something"> <xsl:copy> <!-- 遍历所有唯一的prop类型 --> <xsl:for-each select="$allPropTypes"> <xsl:variable name="currentType" select="." /> <!-- 用属性值模板简化属性写法 --> <props type="{$currentType}"> <!-- 明确指定上下文:当前something下的所有part --> <xsl:for-each select="current()/part"> <xsl:choose> <xsl:when test="prop[@type=$currentType]"> <xsl:value-of select="prop[@type=$currentType]" /> </xsl:when> <xsl:otherwise>?</xsl:otherwise> </xsl:choose> </xsl:for-each> </props> </xsl:for-each> </xsl:copy> </xsl:template> <!-- 匹配根节点,触发所有something的处理 --> <xsl:template match="/"> <xsl:apply-templates select="//something" /> </xsl:template> </xsl:transform>
关键修改说明
- 明确上下文节点:用
current()/part代替select="part",current()会指向当前正在匹配的something节点,这样就能正确找到它下面的所有part了。 - 动态获取prop类型:
distinct-values(//prop/@type)会自动从整个文档中提取所有不重复的prop/@type值,不用手动维护静态变量,更灵活。 - 简化属性写法:用
type="{$currentType}"这种属性值模板替代原来的xsl:attribute,代码更简洁。 - 修正输出格式:把
output method="html"改成method="xml",确保输出符合你期望的XML结构,避免HTML模式的自动标签闭合等问题。
如果你想保留静态变量的写法
要是你因为特殊需求必须用原来的$allTheProps静态变量,那只要提前保存当前something的上下文即可:
<xsl:template match="something"> <xsl:copy> <!-- 先把当前something节点保存到变量 --> <xsl:variable name="currentSomething" select="." /> <xsl:for-each select="$allTheProps/prop"> <xsl:variable name="nodeType" select="@type"/> <props type="{$nodeType}"> <!-- 通过变量指定上下文,找到正确的part --> <xsl:for-each select="$currentSomething/part"> <xsl:value-of select="prop[@type=$nodeType]"/> <xsl:if test="not(prop[@type=$nodeType])">?</xsl:if> </xsl:for-each> </props> </xsl:for-each> </xsl:copy> </xsl:template>
这样也能完美解决你遇到的两个问题,输出结果完全符合你的预期。
内容的提问来源于stack exchange,提问作者Moss
相关产品推荐
相关产品推荐

