|  | elementtree and rounding questions |  | |
| | | Guest |  |
| Posted: Wed Jul 30, 2008 1:56 am Post subject: elementtree and rounding questions |  |
| |  | |
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:
| Quote: | f = '508.5' x = '%.6f' % (float(f)/72) x '7.062500' |
However, in this instance I don't want the last 2 zeroes. So would it be better to do something like this:
| Quote: | f = '508.5' x = round(float(f)/72, 6) x 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 |
| |
| | | Gabriel Genellina |  |
| Posted: Wed Jul 30, 2008 3:23 am Post subject: Re: elementtree and rounding questions |  |
| |  | |
En Wed, 30 Jul 2008 00:56:55 -0300, <jyoung79@kc.rr.com> escribi�:
| Quote: | 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:
f = '508.5' x = '%.6f' % (float(f)/72) x '7.062500'
However, in this instance I don't want the last 2 zeroes. So would it be better to do something like this:
f = '508.5' x = round(float(f)/72, 6) x 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?
|
If all you need is to *display* the value - use formatting expressions like %f, the locale variants, the Template class, or whatever.
If you want to *compute* something using the rounded value, use the round/ceil/floor functions, or perhaps consider using the Decimal class depending on your needs.
From the above, looks like you want to display the value using up to six decimal places, avoiding right zeroes. So you just want to strip '0' characters from the right side:
py> f = '508.5' py> x = '%.6f' % (float(f)/72) py> x '7.062500' py> x.rstrip('0') '7.0625'
-- Gabriel Genellina |
| |
| | | Stefan Behnel |  |
| Posted: Wed Jul 30, 2008 4:25 am Post subject: Re: elementtree and rounding questions |  |
| |  | |
jyoung79@kc.rr.com wrote:
| Quote: | ============================================================ 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).
| Quote: | 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.
| Quote: | 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 |
| |
| | | Guest |  |
| Posted: Wed Jul 30, 2008 11:10 am Post subject: Re: elementtree and rounding questions |  |
Thank you very much Gabriel and Stefan for your help! I really appreciate the excellent examples you've shared which is helping me understand how all this works. Again, thank you for taking the time to help me with this.
Jay |
| |
|
|