I'm parsing an XML document, and I need the book title & number value under Score and place them on a 2d list. My current code, can retrieve that data and place it on a list, but the problem is there's some sections in the XML file where the score is not present, and I need to be able to leave an indicator (ex. N/A) on the list to indicate that value is empty for that particular book title.
This is a sample, simplified version of the xml file. Please note, that this problem repeats throughout the much longer version of the xml file. So no code can use, 1 as an index to get past this problem.
<bookstore>
<book>[A-23] Everyday Italian</book>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
<field></field>
<key id="6408">[A-23]Everyday Italian</key>
<brief>Everyday Italian</brief>
<success></success>
<province> id="256" key=".com.place.fieldtypes:float">
<name>Post</name>
<numbers>
<number></number>
</numbers>
</province>
<province> id="490" key=".com.ave.fieldtypes:float">
<name>Score</name>
<numbers>
<number>4.0</number>
</numbers>
</province>
<province> id="531" key=".com.spot.fieldtypes:float">
<name>Doc</name>
<numbers>
<number></number>
</numbers>
</province>
</bookstore>
<bookstore>
<book>[A-42] Pottery</book>
<author>Leo Di Plos</author>
<year>2012</year>
<price>25.00</price>
<field></field>
<key id="4502">[A-42] Pottery</key>
<brief>Pottery</brief>
<success></success>
<province> id="627" key=".com.tri.fieldtypes:float">
<name>Post</name>
<numbers>
<number></number>
</numbers>
</province>
<province> id="124" key=".com.doct.fieldtypes:float">
<name>Doc</name>
<numbers>
<number></number>
</numbers>
</province>
</bookstore>
<bookstore>
<book>[A-12] Skipping the Line</book>
<author>Gloria Gasol</author>
<year>1999</year>
<price>22.00</price>
<field></field>
<key id="1468">[A-23]Skipping the Line</key>
<brief>Skipping the Line</brief>
<success></success>
<province> id="754" key=".com.cit.fieldtypes:float">
<name>Post</name>
<numbers>
<number></number>
</numbers>
</province>
<province> id="211" key=".com.soct.fieldtypes:float">
<name>Score</name>
<numbers>
<number>12.0</number>
</numbers>
</province>
<province> id="458" key=".com.lot.fieldtypes:float">
<name>Doc</name>
<numbers>
<number></number>
</numbers>
</province>
</bookstore>
This is my current code:
book = []
for book in root.iter('book'):
item1 = book.text
title.append(item1)
score = []
for province in root.iter('province'):
for child in province:
for grandchild in child:
if re.match('^[ -]?\d*?\.\d $', grandchild.text) != None:
item2 = float(grandchild.text)
score.append(item2)
print(book, score)
The expected output is:
([A-23] Everyday Italian, 4.0), ([A-42] Pottery, N/A), ([A-12] Skipping the Line, 12.0)
But the actual output is:
([A-23] Everyday Italian, 4.0), ([A-42] Pottery, 12.0), ([A-12] Skipping the Line)
CodePudding user response:
python's strength is the speed in creating a solution, among others, using ready-made libraries. Why you don't use lib like xmltodict?
for single bookstore:
<bookstore>
<book>[A-23] Everyday Italian</book>**
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
<field></field>
<key id="6408">[A-23]Everyday Italian</key>
<brief>Everyday Italian</brief>
<success></success>
<province> id="256" key=".com.place.fieldtypes:float">
<name>Post</name>
<numbers>
<number></number>
</numbers>
</province>
<province> id="490" key=".com.ave.fieldtypes:float">
**
<name>Score</name>**
<numbers>
**
<number>4.0</number>**
</numbers>
</province>
<province> id="531" key=".com.spot.fieldtypes:float">
<name>Doc</name>
<numbers>
<number></number>
</numbers>
</province>
</bookstore>
python code for read it:
import xmltodict
dict_data = xmltodict.parse(xml_data)
dict_data
title = dict_data["bookstore"]["book"]
score = dict_data["bookstore"]["province"][1]["numbers"]["number"]
Are You sure that your xml is correct? You should create something like list of bookstore objects e.g.:
<BookstoreList>
<Bookstore>
//data here
</Bookstore>
<Bookstore>
//data here
</Bookstore>
// etc.
</BookstoreList>
CodePudding user response:
Here we go..
import xml.etree.ElementTree as ET
xml = '''<r>
<bookstore>
<book>[A-23] Everyday Italian</book>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
<field></field>
<key id="6408">[A-23]Everyday Italian</key>
<brief>Everyday Italian</brief>
<success></success>
<province> id="256" key=".com.place.fieldtypes:float">
<name>Post</name>
<numbers>
<number></number>
</numbers>
</province>
<province> id="490" key=".com.ave.fieldtypes:float">
<name>Score</name>
<numbers>
<number>4.0</number>
</numbers>
</province>
<province> id="531" key=".com.spot.fieldtypes:float">
<name>Doc</name>
<numbers>
<number></number>
</numbers>
</province>
</bookstore>
<bookstore>
<book>[A-42] Pottery</book>
<author>Leo Di Plos</author>
<year>2012</year>
<price>25.00</price>
<field></field>
<key id="4502">[A-42] Pottery</key>
<brief>Pottery</brief>
<success></success>
<province> id="627" key=".com.tri.fieldtypes:float">
<name>Post</name>
<numbers>
<number></number>
</numbers>
</province>
<province> id="124" key=".com.doct.fieldtypes:float">
<name>Doc</name>
<numbers>
<number></number>
</numbers>
</province>
</bookstore>
<bookstore>
<book>[A-12] Skipping the Line</book>
<author>Gloria Gasol</author>
<year>1999</year>
<price>22.00</price>
<field></field>
<key id="1468">[A-23]Skipping the Line</key>
<brief>Skipping the Line</brief>
<success></success>
<province> id="754" key=".com.cit.fieldtypes:float">
<name>Post</name>
<numbers>
<number></number>
</numbers>
</province>
<province> id="211" key=".com.soct.fieldtypes:float">
<name>Score</name>
<numbers>
<number>12.0</number>
</numbers>
</province>
<province> id="458" key=".com.lot.fieldtypes:float">
<name>Doc</name>
<numbers>
<number></number>
</numbers>
</province>
</bookstore>
</r>
'''
root = ET.fromstring(xml)
data = []
for bs in root.findall('.//bookstore'):
book = bs.find('book').text
scores = [s.text for s in bs.findall('.//number') if s.text]
score = 'N/A' if not scores else scores[0]
data.append((book, score))
print(data)
output
[('[A-23] Everyday Italian', '4.0'), ('[A-42] Pottery', 'N/A'), ('[A-12] Skipping the Line', '12.0')]