You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:04:11