XSLT中用变量定义命名空间遇问题:xmlns:s="{$service-uri}"未生效
我懂你遇到的问题了——你尝试用属性值模板来定义命名空间声明,但这根本达不到你想要的效果,XML的命名空间规则和XSLT的动态处理逻辑在这里有冲突。让我给你拆解问题,再提供可行的解决方案。
首先先把你的问题代码贴出来:
<xsl:variable name="service-uri" select="'http://something/'"/> ... <xsl:template match="cxf:cxfEndpoint[last()]"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> <cxf:cxfEndpoint xmlns:s="{$service-uri}" endpointName="s:{$service-name}Port" id="{$service-name}_RemoteEndpoint" serviceName="s:{$service-name}" wsdlURL="wsdl/remote/{$service-name}.wsdl"> <cxf:properties>...
为什么xmlns:s="{$service-uri}"不生效?
核心原因是:XML的命名空间声明属于XML语法的静态部分,XML处理器在解析文档的最早期就会处理命名空间,而XSLT的属性值模板(就是{$变量名}这种写法)是在后续的动态处理阶段才会替换变量值。所以你的代码里,xmlns:s="{$service-uri}"会被当作字面量处理——XML解析器会把{$service-uri}直接当成命名空间的URI,而不是去解析变量$service-uri的值。
解决方案
根据你使用的XSLT版本,有两种可靠的解决方式:
方案1:XSLT 2.0及以上版本(推荐)
XSLT 2.0引入了<xsl:namespace>元素,可以帮你动态声明命名空间。修改后的代码如下:
<xsl:variable name="service-uri" select="'http://something/'"/> <!-- 假设你已经定义了$service-name变量,比如: --> <xsl:variable name="service-name" select="'UserService'"/> <xsl:template match="cxf:cxfEndpoint[last()]"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> <cxf:cxfEndpoint id="{$service-name}_RemoteEndpoint" wsdlURL="wsdl/remote/{$service-name}.wsdl"> <!-- 动态声明命名空间前缀s对应的URI --> <xsl:namespace name="s" select="$service-uri"/> <!-- 用concat拼接出带命名空间前缀的属性值 --> <xsl:attribute name="endpointName" select="concat('s:', $service-name, 'Port')"/> <xsl:attribute name="serviceName" select="concat('s:', $service-name)"/> <cxf:properties> <!-- 保留你原来的properties内容 --> </cxf:properties> </cxf:cxfEndpoint> </xsl:template>
这样处理后,输出的<cxf:cxfEndpoint>元素会自动带上正确的xmlns:s="http://something/"声明,同时endpointName和serviceName属性也会正确关联这个命名空间。
方案2:XSLT 1.0兼容方案
如果你只能用XSLT 1.0(没有<xsl:namespace>元素),可以通过<xsl:attribute>来手动生成命名空间声明和属性:
<xsl:variable name="service-uri" select="'http://something/'"/> <xsl:variable name="service-name" select="'UserService'"/> <xsl:template match="cxf:cxfEndpoint[last()]"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> <cxf:cxfEndpoint id="{$service-name}_RemoteEndpoint" wsdlURL="wsdl/remote/{$service-name}.wsdl"> <!-- 手动生成命名空间声明属性 --> <xsl:attribute name="xmlns:s"> <xsl:value-of select="$service-uri"/> </xsl:attribute> <!-- 拼接生成带前缀的属性值 --> <xsl:attribute name="endpointName"> <xsl:value-of select="concat('s:', $service-name, 'Port')"/> </xsl:attribute> <xsl:attribute name="serviceName"> <xsl:value-of select="concat('s:', $service-name)"/> </xsl:attribute> <cxf:properties> <!-- 保留原内容 --> </cxf:properties> </cxf:cxfEndpoint> </xsl:template>
这种方式虽然不如XSLT 2.0优雅,但在1.0环境下是有效的,主流的XSLT处理器(比如Xalan、Saxon)都支持这种写法。
内容的提问来源于stack exchange,提问作者zamek 42
相关产品推荐
相关产品推荐

