elementtree and rounding questions

G

Guest

Hi,

Hoping that some of you won't mind taking a peek at my code and sharing your
thoughts. I just started using the elementtree module yesterday to work
with xml files. Here's an example of some xml code I might be parsing:

============================================================
<data>
<fonts>
<fontData embed="true" name="Times" />
<fontData embed="true" name="Arial" />
</fonts>
<color>
</color>
<template>
<fonts>
<fontData>
<fontData embed="true" name="Courier">text</fontData>
</fontData>
<fontData embed="true" name="Helvetica" />
</fonts>
<width>
</width>
</template>
</data>
============================================================

What I'd like to do is get the attribute 'name' from the 2nd set 'fontData' tags. So what I'd end up with is ['Courier', 'Helvetica']. Here's the first lines of code I tested:

============================================================
from xml.etree import ElementTree as ET

tree = ET.parse('/Users/jay/Desktop/test.txt')

root = tree.getroot()

fntList = []
f = root.getiterator('fonts')
n = f[-1].getiterator('fontData')
for i in n:
i = i.get('name')
if i != None: fntList.append(i)

print fntList
============================================================

This gives me ['Courier', 'Helvetica'] which is what I'm wanting. If I'm understanding this correctly, it seems getiterator('fonts') will get both of the 2 sections of <fonts> tags. Since I only want the second section, which is the last, I look at f[-1] and use the getiterator('fontData') in order to search through all the appropriate tags. Looks like getiterator also finds all nested tags as seen above when it grabbed both font names I was wanting.

So I continued to experiment a bit and came up with this next:

============================================================
from xml.etree import ElementTree as ET

tree = ET.parse('/Users/jay/Desktop/test.txt')

root = tree.getroot()

fntList = []
f = root.getiterator('fonts')
n = f[-1].find('fontData')
for i in n:
fntList.append(i.get('name'))

print fntList
============================================================

This code just gave me ['Courier']. Now if I change 'find' to 'findall' then I'll get [None, 'Helvetica']. Not exactly sure what exactly that's doing. Seems the 'findall' searches through the tags that aren't nested, but then just using 'find' found the first nested 'name'.

Anyway, I'm hoping someone might tell me if the first example of code above is a decent way to parse xml files. I'm still new to Python and am looking for good code structure as well as accurate examples.

--

One other question I had was about rounding floats. I was first looking at this syntax to round out to 6 decimal places if needed:
'7.062500'

However, in this instance I don't want the last 2 zeroes. So would it be better to do something like this:
7.0625

I've been reading a bit about some rounding bugs, but am really not that knowledgeable about the subject. Does anyone have a preference of how they like to round as well as the result they see?

Thanks for looking at my questions.

Jay
 
S

Stefan Behnel

============================================================
<data>
<fonts>
<fontData embed="true" name="Times" />
<fontData embed="true" name="Arial" />
</fonts>
<color>
</color>
<template>
<fonts>
<fontData>
<fontData embed="true" name="Courier">text</fontData>
</fontData>
<fontData embed="true" name="Helvetica" />
</fonts>
<width>
</width>
</template>
</data>
============================================================

You can exploit the structure: the Elements you are looking for do not have
children, but they do have a "name" attribute.

declarations = [ fontData for fontData in root.getiterator('fontData')
if fontData.get("name") ]

This gives you a list of all "fontData" Elements that declare a font name. The
one you want is the last one, i.e. declarations[-1].

You can also do

font_names = [ fontData.get("name")
for fontData in root.getiterator('fontData')
if fontData.get("name") ]

or something like that. And if you only want the fontData Elements that appear
in the template Elements, try findall instead of getiterator:

tree.findall("//template//fontData")

("//" means: descend into the subtree, while "/" would mean: look only at the
direct children).

f = root.getiterator('fonts')
n = f[-1].getiterator('fontData')

You should not rely on ET returning a list from ".getiterator()", so avoid
using f[-1] here.

fntList = []
f = root.getiterator('fonts')
n = f[-1].find('fontData')
for i in n:
fntList.append(i.get('name'))

print fntList
============================================================

This code just gave me ['Courier']. Now if I change 'find' to 'findall' then I'll get [None, 'Helvetica']. Not exactly sure what exactly that's doing.

The first value (None) comes from the "fontData" Element that does not have a
"name" attibute. The path expression "fontData" means: find all children that
are named "fontData". As above, what you want is ".//fontData".

Stefan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top