Search code examples
pythonxmlweb-serviceslxmlxml-namespaces

How can I change the namespace of an attribute in xml with python?


In my case i have the following code:

from lxml import etree as et
from lxml.builder import ElementMaker

WSS_SCHEMA = "http://schemas.xmlsoap.org/ws/2002/12/secext"
ACTOR_SCHEMA = "http://xpto"
VERSION_SCHEMA = "2"

NSMAP = {
    'wss': WSS_SCHEMA,
    'S': ACTOR_SCHEMA,
    'at': VERSION_SCHEMA,
}

WSS = ElementMaker(namespace=WSS_SCHEMA, nsmap=NSMAP)

security = WSS.Security()

security.set("{%s}actor" % ACTOR_SCHEMA, ACTOR_SCHEMA)
security.set("{%s}Version" % VERSION_SCHEMA, VERSION_SCHEMA)

print(et.tostring(security, encoding="unicode"))

And I am getting this in the output:

<wss:Security xmlns:wss="http://schemas.xmlsoap.org/ws/2002/12/secext" xmlns:S="http://xpto" xmlns:at="2" S:actor="http://xpto" at:Version="2"/>

My desired output is this:

<wss:Security xmlns:wss="http://schemas.xmlsoap.org/ws/2002/12/secext" S:actor="http://xpto" at:Version="2"/>

Does anyone have any suggestions on how I can remove these two attributes, or how I can add only the desired attributes with their respective namespaces?


Solution

  • Namespaces must be defined somewhere in the doc before using them.

    from lxml import etree as et
    from lxml.builder import ElementMaker
    
    WSS_SCHEMA = "http://schemas.xmlsoap.org/ws/2002/12/secext"
    ACTOR_SCHEMA = "http://xpto"
    VERSION_SCHEMA = "example.com"
    
    RNSMAP = {
        'S': ACTOR_SCHEMA,
        'at': VERSION_SCHEMA,
    }
    
    NSMAP = {
        'wss': WSS_SCHEMA
    }
    
    
    WSS = ElementMaker(namespace=WSS_SCHEMA, nsmap=NSMAP)
    
    security = WSS.Security()
    
    security.set("{%s}actor" % ACTOR_SCHEMA, ACTOR_SCHEMA)
    security.set("{%s}Version" % VERSION_SCHEMA, "2")
    
    wrapper = ElementMaker(namespace=ACTOR_SCHEMA, nsmap=RNSMAP)
    
    root = wrapper.Wrapper(security)
    
    print(et.tostring(root, encoding="unicode"))
    

    Result

    <S:Wrapper xmlns:S="http://xpto" xmlns:at="example.com">
        <wss:Security xmlns:wss="http://schemas.xmlsoap.org/ws/2002/12/secext" 
            S:actor="http://xpto" at:Version="2"/>
    </S:Wrapper>
    

    If a single element is required then all namespaces must be defined there

    WSS_SCHEMA = "http://schemas.xmlsoap.org/ws/2002/12/secext"
    ACTOR_SCHEMA = "http://xpto"
    VERSION_SCHEMA = "example.com"
    NSMAP = {
        'wss': WSS_SCHEMA,
        'S': ACTOR_SCHEMA,
        'at': VERSION_SCHEMA,
    }
    WSS = ElementMaker(namespace=WSS_SCHEMA, nsmap=NSMAP)
    
    security = WSS.Security()
    
    security.set("{%s}actor" % ACTOR_SCHEMA, ACTOR_SCHEMA)
    security.set("{%s}Version" % VERSION_SCHEMA, "2")
    
    print(et.tostring(security, encoding="unicode"))
    

    Result (manually indented)

    <wss:Security 
         xmlns:S="http://xpto"
         xmlns:at="example.com" 
         xmlns:wss="http://schemas.xmlsoap.org/ws/2002/12/secext"
         S:actor="http://xpto"
         at:Version="2"/>