首页 > 解决方案 > XML 元素树 - 使用 ET.SubElement() 附加到现有元素和属性?

问题描述

我有以下功能,它建立了一个可重用的 XML SOAP 信封:

def get_xml_soap_envelope():
    """
    Returns a generically re-usable SOAP envelope in the following format:
    <soapenv:Envelope>
        <soapenv:Header/>
        <soapenv:Body />
    </soapenv:Envelope>
    """
    soapenvEnvelope = ET.Element('soapenv:Envelope')

    soapenvHeader = ET.SubElement(soapenvEnvelope, 'soapenv:Header')

    soapenvBody = ET.SubElement(soapenvEnvelope, 'soapenv:Body')

    return soapenvEnvelope

到目前为止相当简单的东西。

我现在想知道,是否可以将属性(例如xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance")附加到soapenv:Envelope元素?

如果我还想附加以下 XML:

<urn:{AAction} soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <AUserName>{AUserName}</AUserName>
    <APassword>{APassword}</APassword>
</urn:{AAction}>

soapenv:Body这样我就会有这样的事情:

if __name__ == "__main__":
    soapenvEnvelope = get_xml_soap_envelope()

    actions = {
        'AAction': 'UserLogin',
    }

    soapAAction = ET.Element('urn:{AAction}'.format(**actions))

    soapenvEnvelope.AppendElement(soapAAction, 'soapenv:Body')

那么,我可以指定一个目标节点和要附加到的元素吗?

标签: python-3.xxmlelementtree

解决方案


让我们从坏消息开始:您创建 SOAP 信封 ( get_xml_soap_envelope ) 的函数是错误的,因为它没有指定至少 xmlns:soapenv="..."。实际上,所有其他要使用的命名空间也应在此处指定。

创建 SOAP 信封的正确函数应该是这样的:

def get_xml_soap_env():
    """
    Returns a generically re-usable SOAP envelope in the following format:
    <soapenv:Envelope xmlns:soapenv="...", ...>
        <soapenv:Header/>
        <soapenv:Body />
    </soapenv:Envelope>
    """
    ns = {'xmlns:soapenv': 'http://schemas.xmlsoap.org/soap/envelope/',
         'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
         'xmlns:urn': 'http://dummy.urn'}
    env = ET.Element('soapenv:Envelope', ns)
    ET.SubElement(env, 'soapenv:Header')
    ET.SubElement(env, 'soapenv:Body')
    return env

注意ns字典还包含其他命名空间,稍后会用到,ao xsi命名空间。

一种可能的替代方法是在此函数之外定义ns并将其作为参数传递(您的选择)。

当我跑的时候:

env = get_xml_soap_env()
print(ET.tostring(env, encoding='unicode', short_empty_elements=True))

打印输出(由我重新格式化以提高可读性)是:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:urn="http://dummy.urn"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Header />
  <soapenv:Body />
</soapenv:Envelope>

请注意,这次包括了正确的命名空间。

然后,要添加Action元素及其子元素,请定义以下函数:

def addAction(env, action, subelems):
    body = env.find('soapenv:Body')
    actn = ET.SubElement(body, f'soapenv:{action}')
    for k, v in subelems.items():
        child = ET.SubElement(actn, k)
        child.text = v

当我跑的时候:

subelems = {'AUserName': 'Mark', 'APassword': 'Secret!'}
addAction(env, 'UserLogin', subelems)

并再次打印整个 XML 树,结果是:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:urn="http://dummy.urn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Header />
  <soapenv:Body>
    <soapenv:UserLogin>
      <AUserName>Mark</AUserName>
      <APassword>Secret!</APassword>
    </soapenv:UserLogin>
  </soapenv:Body>
</soapenv:Envelope>

推荐阅读