如何在XSLT中引用含嵌套XML变量内的深层元素?
XSLT 1.0中访问变量内嵌套XML元素的解决方案
问题根源
XSLT 1.0中,通过<xsl:variable>直接嵌套XML定义的变量属于结果树片段(RTF),而非可直接用XPath路径访问的节点集。这就是你只能引用整个变量内容,却无法通过$descriptions/annotations/annotation这类路径选择子节点的核心原因。
解决方案:将结果树片段转为节点集
需要借助扩展函数将RTF转换为节点集,之后就能用常规XPath路径访问内部元素。不同XSLT处理器支持的扩展函数略有不同,以下是两种常见实现:
方案1:使用EXSLT扩展(兼容性更广)
在样式表根元素引入EXSLT命名空间,并用exsl:node-set()转换变量:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl" version="1.0"> <xsl:variable name="descriptions"> <annotations> <annotation element="Element1">Description for Element1</annotation> <annotation element="Element2">Description for Element2</annotation> <annotation element="Element3">Description for Element3</annotation> </annotations> </xsl:variable> <xsl:template match="xs:element"> <xsl:copy> <xsl:apply-templates select="@*"/> <!-- 转换RTF为节点集,匹配当前元素对应的注释 --> <xsl:variable name="currentName" select="@name"/> <xsl:variable name="matchedDesc" select="exsl:node-set($descriptions)/annotations/annotation[@element = $currentName]"/> <!-- 示例:将注释添加到XSD的annotation节点中 --> <xs:annotation> <xs:documentation> <xsl:value-of select="$matchedDesc"/> </xs:documentation> </xs:annotation> <xsl:apply-templates select="node()"/> </xsl:copy> </xsl:template> <!-- 保留默认模板,确保所有节点正常复制 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
方案2:使用MSXML扩展(针对微软处理器)
如果你的XSLT处理器是MSXML(如IE、.NET旧版本),改用微软的扩展函数:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0"> <!-- 变量定义不变 --> <xsl:variable name="descriptions"> <annotations> <annotation element="Element1">Description for Element1</annotation> <annotation element="Element2">Description for Element2</annotation> <annotation element="Element3">Description for Element3</annotation> </annotations> </xsl:variable> <xsl:template match="xs:element"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:variable name="currentName" select="@name"/> <!-- 使用msxsl:node-set转换 --> <xsl:variable name="matchedDesc" select="msxsl:node-set($descriptions)/annotations/annotation[@element = $currentName]"/> <!-- 输出注释 --> <xs:annotation> <xs:documentation> <xsl:value-of select="$matchedDesc"/> </xs:documentation> </xs:annotation> <xsl:apply-templates select="node()"/> </xsl:copy> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
额外建议
如果可以升级到XSLT 2.0及以上版本(比如使用Saxon处理器),就不需要依赖扩展函数——XSLT 2.0已统一了结果树片段和节点集的概念,直接用$descriptions/annotations/annotation[@element = @name]这类路径就能访问变量内的元素。
内容的提问来源于stack exchange,提问作者Joost van de Ven
相关产品推荐
相关产品推荐

