Home > Net >  Inserting Subelement to existing XML both generated using Python ElementTree Generated XML
Inserting Subelement to existing XML both generated using Python ElementTree Generated XML

Time:09-22

I am writing a function to generate an xml header for a number of various requests using ElementTree and Python 3.x:

import xml.etree.ElementTree as ET
def xml():
    Message = ET.Element('Message')
    Header = ET.SubElement(Message, 'Header')
    Endpoint = ET.SubElement(Header, 'Endpoint')
    endpoint_id = ET.SubElement(Endpoint, 'ID', value='APP')
    Context = ET.SubElement(Header, 'Context', id='request')
    Itinerary = ET.SubElement(Header, 'Itinerary')
    endpoint_uri = ET.SubElement(Itinerary, 'Endpoint' uri='/blah/blah/common/xml')
    header = ET.tostring(Message)

Which generates the following output (formatted to make it easier to read):

<Message>
 <Header>
  <Endpoint>
   <ID value="APP"/>
  </Endpoint>
  <Context id="request"/>
  <Itinerary>
   <Endpoint uri="/blah/blah/common/xml"/>
  </Itinerary>
 </Header>
</Message>

I am trying to insert the following XML into it above the "Message" Element:

header = xml()

Body = ET.Element('Body')
Account = ET.SubElement(Body, 'Account', operation='query')
id_value = ET.SubElement(Account, 'ID', ns='FOO', value='123456789')
body = ET.tostring(Body)

header.insert(body,'Message')

So it will end up like this:

<Message>
 <Header>
  <Endpoint>
   <ID value="APP"/>
  </Endpoint>
  <Context id="request"/>
  <Itinerary>
   <Endpoint uri="/blah/blah/common/xml"/>
  </Itinerary>
 </Header>
 <Body>
  <Account operation="query">
   <ID ns="FOO" value="123456789"/>
  </Account>
 </Body>
</Message>

Everything I have come across to do this using .insert() uses an example of XML from a file, which won't work as the XML doc is clearly being generated as part of the script. The script fails

AttributeError: 'NoneType' object has no attribute 'insert'

And attempts to run getroot() on the header value fail because it is expecting a text file and not generated XML.

CodePudding user response:

Figured it out:

import xml.etree.ElementTree as ET
import xml.dom.minidom

def xml():
    Message = ET.Element('Message')
    Header = ET.SubElement(Message, 'Header')
    Endpoint = ET.SubElement(Header, 'Endpoint')
    endpoint_id = ET.SubElement(Endpoint, 'ID', value='APP')
    Context = ET.SubElement(Header, 'Context', id='request')
    Itinerary = ET.SubElement(Header, 'Itinerary')
    endpoint_uri = ET.SubElement(Itinerary, 'Endpoint' uri='/blah/blah/common/xml')
    return Message

header = xml()

Body = ET.Element('Body')
Account = ET.SubElement(Body, 'Account', operation='query')
id_value = ET.SubElement(Account, 'ID', ns='FOO', value='123456789')

header.insert(1,Body)
header = ET.tostring(header)
doc = xml.dom.minidom.parseString(header).toprettyxml(indent=" ")
print(doc)

Which produces:

<Message>
 <Header>
  <Endpoint>
   <ID value="APP"/>
  </Endpoint>
  <Context id="request"/>
  <Itinerary>
   <Endpoint uri="/blah/blah/common/xml"/>
  </Itinerary>
 </Header>
 <Body>
  <Account operation="query">
   <ID ns="FOO" value="123456789"/>
  </Account>
 </Body>
</Message>

H/T to Jack Fleeting for the insert method catch.

CodePudding user response:

Try changing

header.insert(body,'Message')

to

Message.insert(1,Body)

and see if it works.

  • Related