1

I have the following XML that I am trying to recreate with the lxml.objectify package

<file>
  <customers>
    <customer>
        <phone>
            <type>home</type>
            <number>555-555-5555</number>
        </phone>
        <phone>
            <type>cell</type>
            <number>999-999-9999</number>
        </phone>
        <phone>
            <type>home</type>
            <number>111-111-1111</number>
        </phone>
    </customer>
   </customers>
</file>

I can't figure out how to create the phone element multiple times. Basically, I have the following non-working code:

    # create phone element 1
    root.customers.customer.phone = ""
    root.customers.customer.phone.type = data_dict['PRIMARY PHONE1']
    root.customers.customer.phone.number = data_dict['PRIMARY PHONE TYPE 1']

    # create phone element 2
    root.customers.customer.phone = ""
    root.customers.customer.phone.type = data_dict['PRIMARY PHONE2']
    root.customers.customer.phone.number = data_dict['PRIMARY PHONE TYPE 2']

    # create phone element 3
    root.customers.customer.phone = ""
    root.customers.customer.phone.type = data_dict['PRIMARY PHONE3']
    root.customers.customer.phone.number = data_dict['PRIMARY PHONE TYPE 3']

Which of course only outputs one section of phone information in the resulting XML. Does anyone have any ideas?

2 Answers 2

2

You should create objectify.Element objects, and add them as children of root.customers.

For example, inserting two phone numbers can be done like this:

phone = objectify.Element('phone')
phone.type = data_dict['PRIMARY PHONE1']
phone.number = data_dict['PRIMARY PHONE TYPE 1']
root.customers.customer.append(phone)

phone = objectify.Element('phone')
phone.type = data_dict['PRIMARY PHONE2']
phone.number = data_dict['PRIMARY PHONE TYPE 2']
root.customers.customer.append(phone)

If you get unnecessary attributes on these elements when transforming the xml back to a string, use objectify.deannotate(root, xsi_nil=True, cleanup_namespaces=True). See lxml's objectify documentation for exact parameters of objectify.deannotate.

(If you're using an older version of lxml, which doesn't include the cleanup_namespaces keyword argument, do this instead:

from lxml import etree
# ...
objectify.deannotate(root, xsi_nil=True)
etree.cleanup_namespaces(root)

)

Sign up to request clarification or add additional context in comments.

2 Comments

Actually, I need to add the 3 phone numbers to one customer, but thanks for the info about the Element object.
Oops! I've changed my answer accordingly ;)
1

Here's some sample code that constructs XML with the objectify E-Factory:

from lxml import etree
from lxml import objectify

E = objectify.E

fileElem = E.file(
    E.customers(
        E.customer(
            E.phone(
                E.type('home'),
                E.number('555-555-5555')
            ),
            E.phone(
                E.type('cell'),
                E.number('999-999-9999')
            ),
            E.phone(
                E.type('home'),
                E.number('111-111-1111')
            )
        )
    )
)

print(etree.tostring(fileElem, pretty_print=True))

I've hardcoded it here but you can convert to a loop over your data. Does that work for your purposes?

1 Comment

I think this would work, but I'd have to re-engineer my code. I may use it for something else though. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.