2009-09-29 9 views
24

Mi piace Python, ma non voglio scrivere 10 righe solo per ottenere un attributo da un elemento. Forse sono solo io, ma minidom non è quello mini. Il codice che devo scrivere per analizzare qualcosa che usa sembra molto simile al codice Java.Esiste un parser XML Python progettato pensando agli umani?

C'è qualcosa che è più user-friendly? Qualcosa con operatori sovraccaricati e che mappa gli elementi sugli oggetti?

mi piacerebbe essere in grado di accedere a questo:


<root> 
<node value="30">text</node> 
</root> 

come qualcosa di simile a questo:


obj = parse(xml_string) 
print obj.node.value 

e non utilizzando getChildren o alcuni altri metodi del genere.

+1

XPath conta come facile da usare? http://stackoverflow.com/questions/8692/how-to-use-xpath-in-python – Welbog

+0

Sarei molto interessato a una versione Java di questo! – Federer

risposta

22

Si dovrebbe dare un'occhiata a ElementTree. Non sta facendo esattamente quello che vuoi ma è molto meglio del minidom. Se ricordo bene, a partire da Python 2.4, è incluso nelle librerie standard. Per maggiore velocità usa cElementTree. Per maggiore velocità (e più funzioni) è possibile utilizzare lxml (controllare l'API oggettivare per le proprie esigenze/approccio).

Devo aggiungere che lo BeautifulSoup fa in parte quello che vuoi. C'è anche Amara che ha questo approccio.

+3

+1, ElementTree è eccellente. – Mark

+0

ElementTree è eccellente. –

+0

Concordato, ElementTree è super-facile da usare. Non così eccezionale con gli spazi dei nomi di fantasia (ancora) ma migliorando sempre. Evita il minidom quando possibile. –

3

In realtà ho scritto una libreria che fa esattamente le cose come la immaginavi. La libreria si chiama "xe" e puoi scaricarla da: http://home.avvanta.com/~steveha/xe.html

xe può importare XML per farti lavorare con i dati in modo orientato agli oggetti. In realtà usa xml.dom.minidom per fare il parsing, ma poi cammina sull'albero risultante e impacchetta i dati in oggetti xe.

EDIT: Ok, sono andato avanti e ho implementato il tuo esempio in xe, così puoi vedere come funziona. Ecco le classi per implementare l'XML che hai mostrato:

import xe 

class Node(xe.TextElement): 
    def __init__(self, text="", value=None): 
     xe.TextElement.__init__(self, "node", text) 
     if value is not None: 
      self.attrs["value"] = value 

class Root(xe.NestElement): 
    def __init__(self): 
     xe.NestElement.__init__(self, "root") 
     self.node = Node() 

Ed ecco un esempio di utilizzo di quanto sopra. Ho inserito il tuo XML di esempio in un file chiamato "example.xml", ma potresti anche metterlo in una stringa e passare la stringa.

>>> root = Root() 
>>> print root 
<root/> 
>>> root.import_xml("example.xml") 
<Root object at 0xb7e0c52c> 
>>> print root 
<root> 
    <node value="30">text</node> 
</root> 
>>> print root.node.attrs["value"] 
30 
>>> 

Si noti che in questo esempio, il tipo di "valore" sarà una stringa. Se hai davvero bisogno di attributi di un altro tipo, è possibile anche con un po 'di lavoro, ma non mi sono preoccupato di questo esempio. (Se guardi PyFeed, c'è una classe per OPML che ha un attributo che non è testo.)

2

Avevo lo stesso bisogno di un semplice parser xml e dopo un lungo tempo passato a controllare diverse librerie ho trovato xmltramp.

Basato sul tuo esempio xml:

import xmltramp 

xml_string = """<root> 
<node value="30">text</node> 
</root>""" 

obj = xmltramp.parse(xml_string) 
print obj.node('value')    # 30 
print str(obj.node)     # text 

non ho trovato niente di più user-friendly.

0

Ho trascorso un bel po 'di tempo esaminando gli esempi forniti sopra e attraverso i repository elencati su pip.

L'(più Pythonic e) modo più semplice di XML parsing che ho trovato finora è stata XMLToDict - https://github.com/martinblech/xmltodict

L'esempio dalla documentazione disponibile presso GitHub sopra è inferiore incollato copia-; Ha reso la vita MOLTO semplice e FACILE per me un sacco di volte;

>>> doc = xmltodict.parse(""" 
... <mydocument has="an attribute"> 
... <and> 
...  <many>elements</many> 
...  <many>more elements</many> 
... </and> 
... <plus a="complex"> 
...  element as well 
... </plus> 
... </mydocument> 
... """) 
>>> 
>>> doc['mydocument']['@has'] 
u'an attribute' 
>>> doc['mydocument']['and']['many'] 
[u'elements', u'more elements'] 
>>> doc['mydocument']['plus']['@a'] 
u'complex' 
>>> doc['mydocument']['plus']['#text'] 
u'element as well' 

Funziona davvero bene e mi ha dato proprio quello che stavo cercando. Tuttavia, se stai guardando le trasformazioni inverse, si tratta di una questione completamente diversa.