Python and XML Help

O

ookrin

I'm in the process of learning python and PyQt4. I had decided to make
myself a simple app and soon discovered that I needed to crash into
xml to use some of the data I was going to be getting off of the
server.

I picked up enough xml to use the sax parser to get the data out of
the xml. I can get as far as printing it to the screen, but there is
where I get stuck.... I can't seem to send the data to anywhere else,
into another variable, to another function. The parser stops after the
first line it finds.

class offlineLoad():
def loadXmlFile(self):
print "Loading from File"
xf = open('CharacterID.xml','r')
xml = xmlHandler()
saxparser = make_parser()
print "parser created"
saxparser.setContentHandler(xml)
print "parser runn"
try:
saxparser.parse(xf)
except:
print "Error Reading xml"

class xmlHandler(ContentHandler):
def startElement(self, name, attrs):
self.charList = []
charName = []
charID = []
if name == "row":
charName = attrs.get("name", "")
charID = attrs.get("characterID", "")
print charName, '\t', charID
self.buildlist(self,charName,charID)
#self.test()

def test(self):
print "TeST"
def buildlist(self,charName,charID):
print charName, '\t',charID

so here... test will print, but buildlist makes the parser stop and
print "Error reading XML" after the first row it finds. Appending
charName and charID to another variable makes it stop as well. I'm
confused at this point
 
D

Diez B. Roggisch

ookrin said:
I'm in the process of learning python and PyQt4. I had decided to make
myself a simple app and soon discovered that I needed to crash into
xml to use some of the data I was going to be getting off of the
server.

I picked up enough xml to use the sax parser to get the data out of
the xml. I can get as far as printing it to the screen, but there is
where I get stuck.... I can't seem to send the data to anywhere else,
into another variable, to another function. The parser stops after the
first line it finds.

class offlineLoad():
def loadXmlFile(self):
print "Loading from File"
xf = open('CharacterID.xml','r')
xml = xmlHandler()
saxparser = make_parser()
print "parser created"
saxparser.setContentHandler(xml)
print "parser runn"
try:
saxparser.parse(xf)
except:
print "Error Reading xml"

This is a very bad thing to do - there are only very few justified cases
of catch-all for exceptions. This certainly isn't one, as it suppresses
the real cause for what is happening.

Which makes it harder for you & for us to diagnose the problem, because
you don't show (and currently can't) the stacktrace to us.
class xmlHandler(ContentHandler):
def startElement(self, name, attrs):
self.charList = []

If this shall gather some state over the coures of time, this is the
wrong place to initialize it, as it will get overwritten with each element.
charName = []
charID = []

There is no need to "prefill" variables. And it's confusing you do it
with a different type than what you assign to them below.
if name == "row":
charName = attrs.get("name", "")
charID = attrs.get("characterID", "")
print charName, '\t', charID
self.buildlist(self,charName,charID)
#self.test()

def test(self):
print "TeST"
def buildlist(self,charName,charID):
print charName, '\t',charID

so here... test will print, but buildlist makes the parser stop and
print "Error reading XML" after the first row it finds. Appending
charName and charID to another variable makes it stop as well. I'm
confused at this point

Please show us the stacktrace you suppress. Then help might be possible.

Diez
 
O

ookrin

ookrin schrieb:


I'm in the process of learning python and PyQt4. I had decided to make
myself a simple app and soon discovered that I needed to crash into
xml to use some of the data I was going to be getting off of the
server.
I picked up enough xml to use the sax parser to get the data out of
the xml. I can get as far as printing it to the screen, but there is
where I get stuck.... I can't seem to send the data to anywhere else,
into another variable, to another function. The parser stops after the
first line it finds.
class offlineLoad():
    def loadXmlFile(self):
        print "Loading from File"
        xf = open('CharacterID.xml','r')
        xml = xmlHandler()
        saxparser = make_parser()
        print "parser created"
        saxparser.setContentHandler(xml)
        print "parser runn"
        try:
            saxparser.parse(xf)
        except:
            print "Error Reading xml"

This is a very bad thing to do - there are only very few justified cases
of catch-all for exceptions. This certainly isn't one, as it suppresses
the real cause for what is happening.

Which makes it harder for you & for us to diagnose the problem, because
you don't show (and currently can't) the stacktrace to us.
class xmlHandler(ContentHandler):
    def startElement(self, name, attrs):
        self.charList = []

If this shall gather some state over the coures of time, this is the
wrong place to initialize it, as it will get overwritten with each element.
        charName = []
        charID = []

There is no need to "prefill" variables. And it's confusing you do it
with a different type than what you assign to them below.


        if name == "row":
            charName = attrs.get("name", "")
            charID = attrs.get("characterID", "")
            print charName, '\t', charID
            self.buildlist(self,charName,charID)
            #self.test()
    def test(self):
        print "TeST"
    def buildlist(self,charName,charID):
        print charName, '\t',charID
so here... test will print, but buildlist makes the parser stop and
print "Error reading XML" after the first row it finds.  Appending
charName and charID to another variable makes it stop as well. I'm
confused at this point

Please show us the stacktrace you suppress. Then help might be possible.

Diez

Sorry for the delay, easter weekend:

I know you don't need to prefill the variables with python, and they
weren't there originally, I was just getting frustrated and trying
various things to see if they worked. There is actually no stacktrace
error. It will just print me the error message that I have when I try
to send the variables outside of the if loop. (from the try - except
statement.) I can still run click the button and it'll do it again.

There are three rows that I have to get out of my xml all the same
except with different values:
< row name="CharName" charID="IDNumber" >

So it prints out the first of the three lines and then just says
"Error Reading XML" if I'm running the buildlist() and trying to send
the variables out. As long as I don't try to do anything, it works
fine.

I can get these out and print them to the cmd line. But I want to
collect these in a variable and send it back off to my gui in pyqt4 to
list them. which is where i'm getting stuck.
 
J

John Machin

There is actually no stacktrace
error. It will just print me the error message that I have when I try
to send the variables outside of the if loop. (from the try - except
statement.)

That's because (as Diez has already pointed out, and told you to stop
doing) you are *suppressing* the error message and stack trace that
will help diagnose what is going wrong in your callback method.

Instead of this:
try:
saxparser.parse(xf)
except:
print "Error Reading xml"
do just this:
saxparser.parse(xf)
or if you really want to print something at the time, do this:
try:
saxparser.parse(xf)
except:
print "something meaningful"
raise # throw the exception back for normal handling

And just in case you're not taking the advice of Scott D. D. either,
let me tell you again: use ElementTree, it's easier (no callbacks to
complicate things) and the ratio of helpful-user-count to problem-
likelihood is likely to be much higher than with sax.

Cheers,
John
 
O

ookrin

That's because (as Diez has already pointed out, and told you to stop
doing) you are *suppressing* the error message and stack trace that
will help diagnose what is going wrong in your callback method.

Instead of this:
        try:
            saxparser.parse(xf)
        except:
            print "Error Reading xml"
do just this:
        saxparser.parse(xf)
or if you really want to print something at the time, do this:
        try:
            saxparser.parse(xf)
        except:
            print "something meaningful"
            raise # throw the exception back for normal handling

And just in case you're not taking the advice of Scott D. D. either,
let me tell you again: use ElementTree, it's easier (no callbacks to
complicate things) and the ratio of helpful-user-count to problem-
likelihood is likely to be much higher than with sax.

Cheers,
John

Ok, I didn't know that was what I was actively doing by using the try-
except. I am still learning. And it's not that I won't take the advice
for using ElementTree, I just currently don't know anything about it.
I just didn't want to say, "I have no idea what you're talking about!"
to Scott cause I figured that would be rude, but I guess so is not
saying anything, sorry. So I'll need to read up on it before I
actually try to do anything with that approach.


Seeing the errors - I changed the two classes to this:

class offlineLoad():
def loadXmlFile(self):
print "Loading from File"
xf = open('CharacterID.xml','r')
xml = xmlHandler()
saxparser = make_parser()
saxparser.setContentHandler(xml)

saxparser.parse(xf)

class xmlHandler(ContentHandler):
def __init__(self):
print "---"
self.idList = []

def startElement(self, name, attrs):
if name == "row":
charName = attrs.get("name", "")
charID = attrs.get("characterID", "")
self.buildlist(charName,charID)

def buildlist(self,charName,charID):
temp = charName,charID
self.idList.append(temp)
print "----"
print self.idList

I know calling the self.idList = [] in the init probably isn't
correct, but I couldn't think of any other way currently so it doesn't
get rebuilt every time the definition gets called. This works and at
least I think it puts everything into an array for me. I'm going to
look at the element tree now, but I probably won't figure it out
tonight.

I'm using python 2.6

Thanks so far,
Andrew
 
J

John Machin

Seeing the errors - I changed the two classes to this:

class offlineLoad():
    def loadXmlFile(self):
        print "Loading from File"
        xf = open('CharacterID.xml','r')
        xml = xmlHandler()
        saxparser = make_parser()
        saxparser.setContentHandler(xml)

        saxparser.parse(xf)

class xmlHandler(ContentHandler):
    def __init__(self):
        print "---"
        self.idList = []

    def startElement(self, name, attrs):
        if name == "row":
            charName = attrs.get("name", "")
            charID = attrs.get("characterID", "")
            self.buildlist(charName,charID)

    def buildlist(self,charName,charID):
        temp = charName,charID
        self.idList.append(temp)
        print "----"
        print self.idList

I know calling the self.idList = [] in the init probably isn't
correct, but I couldn't think of any other way currently so it doesn't
get rebuilt every time the definition gets called. This works and at
least I think it puts everything into an array for me.

AFAICT having self.idList = [] in the __init__ method is the only
sensible way to do what you want. Non-sensible ways: make it global to
the module, or local to a class method

You do have a problem with what you've got so far: you've done the
heist, you've stuffed the loot into a sack, but where's the getaway
car? IOW your loadXmlFile method needs a line like

return xml.idList

Wouldn't loadXMLFile be better as a stand-alone function? A class
which is not a subclass of anything more meaty than object and has
only one method (which isn't __init__) smells strongly of excess
reliance on paradigms best left behind with the language from which
you acquired them :)

Cheers,
John
 
O

ookrin

ookrin said:
.... I am still learning. And it's not that I won't take the advice
for using ElementTree, I just currently don't know anything about it.
I just didn't want to say, "I have no idea what you're talking about!"
to Scott cause I figured that would be rude, but I guess so is not
saying anything, sorry. So I'll need to read up on it before I
actually try to do anything with that approach.
Seeing the errors - I changed the two classes to this:
  ... [some code that actually says a _little_ bit about his target] .....

If you had done a better job of asking your question, you'd have found a
quick answer.  That is why everyone points people at smartquestions, not
to pick on them.

Presuming you have an xml structure like:
     txt = '''<abc> something <def>
            <name name='steve' characterID='sid'> Some contents. </name>
            <name name='stevey' characterID='sidy'>Other contents.</name>
            </def></abc>'''
     import xml.etree.ElementTree as ET
     structure = ET.fromstring(xmls)
     for node in structure.findall('def/name'):
         print '%s: %s / %s: %s' % (node.tag, node.attrib['name'],
                               node.attrib['characterID'], node.text)

or a file named 'my.xml' with the same contents:
     import xml.etree.ElementTree as ET
     structure = ET.parse('my.xml')
     for node in structure.findall('def/name'):
         print '%s: %s / %s: %s' % (node.tag, node.attrib['name'],
                               node.attrib['characterID'], node.text)

--Scott David Daniels
(e-mail address removed)

Thanks very much for your patience with me and thanks for the help
everyone.
This is my end result:

self.api = apiConnection(self.userID,self.apiKey)
xmlData = self.api.returnXml()
if(xmlData != "None"):
struct = ET.fromstring(xmlData)
self.charIDs =[]
i=0
for node in struct.findall('result/rowset/row'):
char = node.attrib['name']
id = node.attrib['characterID']
temp = char, id
#append them to the variable for later
self.charIDs.append(temp)
i+=1
#Setup the select window and run it
#selects which character I want
self.selectCharUi = selectChar(self,self.charIDs)
self.selectCharUi.selectWindow.exec_()

#Get the name that was selected
self.selectedCharName = self.selectCharUi.returnValue
()
#Set the text widget with the name
self.lE_charID.setText(self.selectedCharName)
#enable the Ok button
self.pbOk.setEnabled(True)

It collects the names and IDs, sends them to a pyqt4 window with a
list widget to list the names, a name gets selected and then I get the
name that was selected. Though now that I think about it, maybe using
a dictionary would be better. Elsewhere I gather up the userID, apiID,
characterName and characterID and write it t a file. I hope it doesn't
look too horrible.

John - my programming experience was two semesters of c++ about 6
years ago. Everything else I've learned from the internet. =/

I'll try to make my questions better next time.

Andrew
 

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
474,007
Messages
2,570,266
Members
46,865
Latest member
AveryHamme

Latest Threads

Top