0

I have an XML document as a str. Now, in the XSD <foo> is unbounded, and while most of the time there is only 1, there COULD be more. I'm trying to use ElementTree, but am running into an issue:

>>> from xml.etree.ElementTree import fromstring
>>> 
>>> xml_str = """<?xml version="1.0"?>
... <foo>
...     <bar>
...         <baz>Spam</baz>
...         <qux>Eggs</qux>
...     </bar>
... </foo>"""
>>> # Try to get the document
>>> el = fromstring(xml_str)
>>> el.findall('foo')
[]
>>> el.findall('bar')
[<Element 'bar' at 0x1004acb90>]

Clearly, I need to loop through the <foo>s, but because <foo> is at the root, I can't. Obviously, I could create an element called <root> and put el inside of it, but is there a more correct way of doing this?

1
  • Can someone give this question a more descriptive title? Commented May 31, 2018 at 15:25

2 Answers 2

3

Each XML document is supposed to have exactly one root element. You will need to adjust your XML if you want to support multiple foo elements.

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

1 Comment

@orokusaki: as I understood your problem, you didn't have multiple root elements, but rather wanted to find all foo elements, whether they occurred as root element or elsewhere in the tree. If you actually had multiple root elements (which seems likely because you accepted this answer) you might consider rephrasing the question for clarity.
2

Alas, wrapping the element in an ElementTree with tree = ElementTree(el) and trying tree.findall('//foo') doesn't seem to work either (it seems you can only search "beneath" an element, and even if the search is done from the full tree, it searches "beneath" the root). As ElementTree doesn't claim to really implement xpath, it's difficult to say whether this is intended or a bug.

Solution: without using lxml with full xpath support (el.xpath('//foo') for example), the easiest solution would be to use the Element.iter() method.

for foo in el.iter(tag='foo'):
    print foo

or if you want the results in a list:

list(el.iter(tag='foo'))

Note that you can't use complex paths in this way, just find all elements with a certain tagname, starting from (and including) the element.

1 Comment

ha, that tree = ElementTree(el) bit was my exact first thing I tried when I ran into the issue (without luck, of course). Thanks for the new approach, though (the el.iter bit).

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.