XML mit xml.sax in Python-Dateityp überführen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
alan
User
Beiträge: 81
Registriert: Dienstag 10. April 2007, 11:30

Hallo allerseits

ich habe mich mittlerweile etwas in Python eingearbeitet und will mich jetzt an einem etwas größeren Programm versuchen.

Ich will mit xml.sax eine XML-Datei lesen, das aus dictionaries und key-value-Paaren aufgebaut ist, z.B:

------

Code: Alles auswählen

<dict>
  <key>version</key><string>1.0.1</string>
  <key>...
  <dict>
    <key>1</key>
    <dict>
        <key>Name</key><string>alan</string>
    </dict>
    <key>2</key>
    <dict>
        <key>Name</key><string>huber</string>
    </dict>
  </dict>   
</dict>
-------

Um das in eine Python-Dateityp zu überführen, will ich das als Array repräsentieren, etwa so:
{'version':'1.0.1', {1:{'Name':'alan'}, 2:{'Name':'huber'}}}


Weiß jetzt allerdings nicht so recht weiter, wie ich das umsetzen soll:
Hier bin ich momentan:

Code: Alles auswählen

from xml.sax import make_parser
from xml.sax.handler import ContentHandler


class Reader(ContentHandler):

    def __init__(self):
        self._currentElement = None
        self._result = None

    def startElement(self, name, attrs):
        self.currentElement = name

    def endElement(self, name):
        pass

    def characters(self, content):
        self._handleValues(content)

    def _handleValues(self, value):
        doSomeMagic

Die einzigen Parameter, die _handleValues() hat, sind currentElement (z.B. 'string') und content (z.B. 'Name'), also nie Schlüssel und Wert ('Name' und 'alan') auf einmal, denn attrs.getValue[name] liefert hier ja Blödsinn.

Ich weiß jetzt nicht, wie ich weitermachen soll.

Ich bin für jede Hilfe sehr dankbar
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Hallo alan, willkommen im Forum!
alan hat geschrieben:Ich weiß jetzt nicht, wie ich weitermachen soll.
Warum willst du unbedingt SAX verwenden? Von allen XML-APIs die Python unterstützt ist SAX die unangenehmste, die die low-level ist. Ist es Interesse an SAX oder könntest du dich mit DOM oder ElementTree ebenso anfrenden?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

Eine nicht ganz so hübsche, da quick'n'dirty geschriebene Lösung mit `iterparse()` aus `ElementTree`:

Code: Alles auswählen

from StringIO import StringIO
from elementtree import ElementTree as etree

source = """
<dict>
  <key>version</key><string>1.0.1</string>
  <key>spam</key>
  <dict>
    <key>1</key>
    <dict>
        <key>Name</key><string>alan</string>
    </dict>
    <key>2</key>
    <dict>
        <key>Name</key><string>huber</string>
    </dict>
  </dict>
</dict>
"""


def get_node(position, tag_name, nodes):
    real_position, node = nodes.next()
    if position != real_position or tag_name != node.tag:
        raise ValueError('expected %r %s tag but found %r %s tag instead'
                         % (tag_name, position, node.tag, real_position))
    return node


def parse_item(position, node, nodes):
    if (position, node.tag) != ('start', 'key'):
        raise ValueError("expected 'key' start tag but found %r %s instead"
                         % (node.tag, position))
    key = get_node('end', 'key', nodes).text
    position, node = nodes.next()
    if position != 'start' or node.tag not in ('string', 'dict'):
        raise ValueError("expected 'string' or 'dict' start tag but"
                         "found %r %s tag" % (node.tag, position))
    if node.tag == 'string':
        return (key, get_node('end', 'string', nodes).text)
    else:
        return (key, parse_dict(nodes))


def parse_dict(nodes):
    result = dict()
    while True:
        position, node = nodes.next()
        if (position, node.tag) == ('end', 'dict'):
            return result
        else:
            key, value = parse_item(position, node, nodes)
            result[key] = value


def parse(source_file):
    nodes = etree.iterparse(source_file, ('start', 'end'))
    get_node('start', 'dict', nodes)
    return parse_dict(nodes)


def main():
    print parse(StringIO(source))


if __name__ == '__main__':
    main()
Aus den Parse-Funktionen sollte man wahrscheinlich besser Methoden machen, damit man die `nodes` nicht herumreichen muss.
alan
User
Beiträge: 81
Registriert: Dienstag 10. April 2007, 11:30

Ich habe [noch] relativ wenig Ahnung von XML..Was ich aus Tutorials mitgenommen habe, ist, dass SAX wesentlich performanter ist, als DOM. Von ElementTree lese ich allerdings gerade zum ersten Mal :)
Für SAX habe ich mich dann entschieden, weil meine XML-Dateien leicht um die 10 MB und mehr erreichen können. Ist da SAX nicht vernünftiger?
BlackJack

Bei solchen Grössen kann SAX schon Sinn machen, weil nicht der ganze DOM-Baum im Speicher aufgebaut wird. Allerdings ist es etwas aufwändiger zu Programmieren.

Ich würde auf jeden Fall erst einmal testen, ob es mit realen grossen Dateien und `ElementTree` Probleme mit dem Speicherplatz gibt, bevor ich mich mit SAX herumschlage.
Antworten