XML 元素树 - 使用 ET.SubElement() 附加到现有元素和属性?

XML Element Tree - appending to existing elements and attributes with 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')

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

让我们从坏消息开始:创建 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 字典还包含其他命名空间,它们将是 稍后需要,a.o。 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>