0

When calling lxml.etree.canonicalize(node) a ValueError exception is raised: Namespace "{<uri>}" of name "<name>" is not declared in scope.

In this particular case the message is ValueError: Namespace "http://schemas.xmlsoap.org/soap/envelope/" of name "Header" is not declared in scope

The following code works exactly as expected:

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>'

However, if node_header is a subelement of another node, it breaks:

from lxml import etree as ET

url_wss_u = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
url_soap_envelope =  "http://schemas.xmlsoap.org/soap/envelope/"

# Envelope
nsmap_Envelope = {
    's': url_soap_envelope,
    'u': url_wss_u,
}
qname_s_Envelope = ET.QName(url_soap_envelope, "Envelope")
node_envelope = ET.Element(qname_s_Envelope, {}, nsmap=nsmap_Envelope)

# Envelope / Header
nsmap_Header = {
    's': url_soap_envelope,
}
qname_s_Header = ET.QName(url_soap_envelope, "Header")
node_header = ET.SubElement(node_envelope, qname_s_Header, nsmap=nsmap_Header)

ET.canonicalize(node_envelope)
# '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header></s:Header></s:Envelope>'

ET.canonicalize(node_header)

Error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "src/lxml/serializer.pxi", line 918, in  lxml.etree.canonicalize
  File "src/lxml/serializer.pxi", line 943, in lxml.etree._tree_to_target
  File "src/lxml/serializer.pxi", line 1128, in lxml.etree.C14NWriterTarget.start
  File "src/lxml/serializer.pxi", line 1155, in lxml.etree.C14NWriterTarget._start
  File "src/lxml/serializer.pxi", line 1085, in lxml.etree.C14NWriterTarget._qname
ValueError: Namespace "http://schemas.xmlsoap.org/soap/envelope/" of name "Header" is not declared in scope

The expected result when calling ET.canonicalize(node_header) is '<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"></s:Header>'

The XML I'm trying to build has the following template:

<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>
Adan Cortes
  • 1,058
  • 8
  • 13
  • Of course, the turn around is to create `node_header` using `ET.Element`, canonicalize it and then call `node_envelope.append(node_header)` but that's not the answer I'm looking for. – Adan Cortes Mar 03 '23 at 01:59
  • Could you share the Xml structure,please. – Hermann12 Mar 03 '23 at 16:17
  • @Hermann12, Thanks for you taking a look to this. There is no XML just yet but I added the template of the XML I'm trying to build. – Adan Cortes Mar 03 '23 at 16:55
  • You already have an XML document with placeholders, such as `{created}` and `{expires}`. Why not simply fill those placeholders with actual data? Why do you need to create elements using `etree.Element()` and `etree.SubElement()`? – mzjn Mar 11 '23 at 09:25
  • @mzjn, thanks for your interest! Because both `{digest_value}` and `{b64_signature}` depend on canonicalizations of a subelement. With this question I'm trying to figure out if there is an issue with the way lxml implements the `canonicalize` method. The specific programming problem was already solved as I said in the first comment. – Adan Cortes Mar 12 '23 at 20:48

0 Answers0