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

XSLT中无法通过元素名获取XML子节点值的问题求助

问题原因分析

你遇到的核心问题是XML命名空间的匹配逻辑。仔细看你的XML结构:

<ns2:Data from="1960-01-01">
  <AuthorisationNr>1716H</AuthorisationNr>
  <VatNr countryCode="BE">0406316776</VatNr>
  <!-- 其他节点 -->
</ns2:Data>

这些AuthorisationNr、VatNr子节点属于默认命名空间urn:be:fgov:ehealth:samws:v2:company:submit(来自根节点的xmlns="..."声明)。而你在XSLT里虽然声明了这个命名空间,但没有给它分配前缀——在XPath规则里,不带前缀的节点名会被认为是「无命名空间」的节点,所以直接写select="AuthorisationNr"时,XSLT根本找不到对应的节点。

至于child::*[1]能工作,只是因为它匹配所有子节点(不管命名空间),刚好第一个子节点是AuthorisationNr而已,但这种依赖节点顺序的写法,一旦节点缺失或顺序变动就会彻底失效,完全不可靠。


解决方案:给默认命名空间分配前缀

解决方法很直接:给默认命名空间分配一个前缀(比如ns1),然后用这个前缀明确引用目标节点。

修改后的完整XSLT代码

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:ns1="urn:be:fgov:ehealth:samws:v2:company:submit" <!-- 新增前缀绑定 -->
                xmlns:ns2="urn:be:fgov:ehealth:samws:v2:export">
  <xsl:template match="/ns2:ExportCompanies">
    <xsl:for-each select="ns2:Company">
      <xsl:text>INSERT INTO COMPANY VALUES ('</xsl:text>
      <xsl:value-of select="@actorNr" />
      <xsl:text>','</xsl:text>
      <xsl:for-each select="ns2:Data">
        <xsl:sort select="translate(@from,'-','')" order="descending" data-type="number" />
        <xsl:if test="position() = 1">
          <xsl:value-of select="@from" />
          <xsl:text>','</xsl:text>
          <xsl:value-of select="@to" /> <!-- 注意:你的XML里无@to属性,会输出空字符串 -->
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:AuthorisationNr" /> <!-- 用前缀引用节点 -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:VatNr" /> <!-- 替换child::*[2] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:Denomination" /> <!-- 替换child::*[3] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:LegalForm" /> <!-- 替换child::*[4] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:StreetName" /> <!-- 替换child::*[6] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:StreetNum" /> <!-- 替换child::*[7] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:Postcode" /> <!-- 替换child::*[8] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:City" /> <!-- 替换child::*[9] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:CountryCode" /> <!-- 替换child::*[10] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:Phone" /> <!-- 替换child::*[11] -->
          </xsl:call-template>
          <xsl:text>','</xsl:text>
          <xsl:call-template name="escape-apos">
            <xsl:with-param name="string" select="ns1:Language" /> <!-- 替换child::*[12] -->
          </xsl:call-template>
        </xsl:if>
      </xsl:for-each>
      <xsl:text>');</xsl:text>
    </xsl:for-each>
  </xsl:template>

  <!-- 补充你之前省略的转义单引号模板 -->
  <xsl:template name="escape-apos">
    <xsl:param name="string" />
    <xsl:choose>
      <xsl:when test="contains($string, '&apos;')">
        <xsl:value-of select="substring-before($string, '&apos;')" />
        <xsl:text>&apos;&apos;</xsl:text>
        <xsl:call-template name="escape-apos">
          <xsl:with-param name="string" select="substring-after($string, '&apos;')" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$string" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

关键修改说明

  1. 命名空间前缀绑定:在xsl:stylesheet标签中新增xmlns:ns1="urn:be:fgov:ehealth:samws:v2:company:submit",给默认命名空间分配了前缀ns1。
  2. 替换节点选择器:把所有依赖child::*[n]的选择器,替换成明确的ns1:节点名,比如ns1:AuthorisationNr,这样即使节点缺失或顺序变化,也能精准匹配目标节点。
  3. 补充转义模板:你原代码里省略了escape-apos模板,这也是原逻辑可能失效的原因之一,这里补全了该模板,确保单引号能正确转义。

运行结果

用修改后的XSLT处理你的XML,会生成如下SQL语句:

INSERT INTO COMPANY VALUES ('01716','1960-01-01','','1716H','0406316776','Schenker','NV','Noorderlaan','147','2030','ANTWERPEN','BE','03/5436373','NL');

注:你的XML里ns2:Data节点没有@to属性,所以对应位置是空字符串,你可以根据业务需求补充默认值处理逻辑。

内容的提问来源于stack exchange,提问作者Nan0

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 21:32:57