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

调用lxml.etree.canonicalize触发命名空间未声明ValueError问题

解决lxml canonicalize处理Envelope子元素Header时的命名空间错误

调用lxml.etree.canonicalize()处理作为Envelope子元素的Header节点时,会抛出如下ValueError异常:

ValueError: Namespace "http://schemas.xmlsoap.org/soap/envelope/" of name "Header" is not declared in scope

现象对比

  • 单独创建Header节点时正常:直接构建Header节点并调用canonicalize能返回预期结果:

    from lxml import etree as ET
    
    url_soap_envelope =  "http://schemas.xmlsoap.org/soap/envelope/"
    
    # 单独创建Header节点
    nsmap_Header = {
        's': url_soap_envelope,
    }
    qname_s_Header = ET.QName(url_soap_envelope, "Header")
    node_header = ET.Element(qname_s_Header, nsmap=nsmap_Header)
    
    ET.canonicalize(node_header)
    # 返回结果: '<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"></s:Header>'
    
  • 作为Envelope子元素时报错:当Header是以下XML模板中Envelope的子元素时,调用ET.canonicalize(node_header)触发错误,预期结果应为'<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"></s:Header>':

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <s:Header>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
          <u:Timestamp u:Id="_0">
            <u:Created>{created}
            </u:Created>
            <u:Expires>{expires}
            </u:Expires>
          </u:Timestamp>
          <o:BinarySecurityToken u:Id="{uuid}" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">{b64certificate}
          </o:BinarySecurityToken>
          <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
              <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
              <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
              <Reference URI="#_0">
                <Transforms>
                  <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </Transforms>
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <DigestValue>{digest_value}
                </DigestValue>
              </Reference>
            </SignedInfo>
            <SignatureValue>{b64signature}
            </SignatureValue>
            <KeyInfo>
              <o:SecurityTokenReference>
                <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#{uuid}"/>
              </o:SecurityTokenReference>
            </KeyInfo>
          </Signature>
        </o:Security>
      </s:Header>
      <s:Body>
        <Autentica xmlns="http://DescargaMasivaTerceros.gob.mx"/>
      </s:Body>
    </s:Envelope>
    

问题原因

Header作为Envelope的子元素时,其命名空间声明是继承自父节点的。单独抽取Header节点进行canonicalize时,lxml无法自动携带父节点的命名空间上下文,导致节点自身没有显式的命名空间声明,触发作用域未声明的错误。

解决方案

方案1:显式为Header节点添加命名空间声明

获取Header节点后,手动为其添加s前缀的命名空间声明,确保节点自身包含完整的命名空间信息:

# 假设已构建好Envelope节点envelope
node_header = envelope.find('{http://schemas.xmlsoap.org/soap/envelope/}Header')
# 显式添加命名空间声明
node_header.set('xmlns:s', 'http://schemas.xmlsoap.org/soap/envelope/')
# 调用canonicalize即可正常执行
result = ET.canonicalize(node_header)

方案2:保留根节点上下文进行canonicalize

通过获取Header节点的根树来保留完整的命名空间作用域,再进行canonicalize操作:

# 获取Header节点所属的根树
root_tree = node_header.getroottree()
# 对根树执行canonicalize,若仅需Header部分可后续提取
result = ET.canonicalize(root_tree)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 20:47:33