Topic: Parsing XML - consigli  (Letto 1570 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline lore84

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
Parsing XML - consigli
« il: Novembre 06, 2008, 12:46 »
ciao a tutti,
ho cercato di fare una sorta di parsing di xml.
Contando che l'ho fatto solo per esercitarmi un po' con il nuovo linguaggio e che non mi serve per lavoro, il programma mi parrebbe funzionare ( almeno sembra  :P ), volevo dei consigli da voi su cosa migliorare e cosa modificare perchè sicuramente ci saranno cose per cui ho impiegato n righe di codice ma magari avrei potuto risolvere tutto con un'istruzione  :embarrassed:

In breve mi ero prefisso di fare un programma per parsare un xml ed estrarre i valori che mi servivano ( i tag da "utilizzare" sono indicati in una lista ).
Inoltre stampo gli attributi di alcuni tag solo se questi sono specificati in un dizionario ( indico in un dizionario i tag di cui volgio sapere gli attributi e gli evenutali attributi )

[hlpycode]
from xml.dom import minidom

class XmlSimpleParse:
    def __init__(self, TAG_INIZIO, arr_tag, dic_attr_tag, file_xml):
        #il tag "padre" da cui iniziare ad estrarre
        self.TAG_INIZIO = TAG_INIZIO
        self.arr_tag = arr_tag
        self.file_xml = file_xml
        self.dict_ret_attr = {}
        self.dic_attr_tag = dic_attr_tag
        #array che verra restituito
        self.ret_list = []


    def parseXml(self):
        xmldoc = minidom.parse(self.file_xml)
        #recupero le posizioni dei tag padre da cui partire per cercare i tag che mi servono
        obj_father = xmldoc.getElementsByTagName(self.TAG_INIZIO)

        #ciclo su ogni tag padre
        for indexFather in range(len(obj_father)):   
            tag_father = obj_father[indexFather]
                   
            if tag_father.hasChildNodes:               
                all_father_tag = tag_father.childNodes
                arr_tmp = []               
                #cerco tutti i tag figli
                for i in range(len(all_father_tag)):
                    arr_tmp_attributes = []
                    #se il tag e' nell'array arr_tag (array dei tag che mi servono), allora salvo il suo valore
                    #in un array di supporto ( arr_tmp )
                    if all_father_tag.localName in arr_tag:               
                        arr_tmp.append(all_father_tag.firstChild.data)
                       
                        #controllo se il tag ha attributi e se il tag e' tra quelli di cui voglio sapere gli attributi
                        if all_father_tag.hasAttribute and all_father_tag.localName in self.dic_attr_tag.keys():
                            #salvo il nome del tag in una variabile ( x comodita )
                            dic_attr_tag_keys = self.dic_attr_tag[all_father_tag.localName]
                           
                            #cerco per il tag gli attributi che mi servono
                            for attr_ind in range(len(dic_attr_tag_keys)):
                                #nome dell'attributo
                                key_name = dic_attr_tag_keys[attr_ind]
                                #valore dell'attributo
                                key_value = all_father_tag.attributes[key_name].value                       
                                #creo una lista con tutti gli attributi trovati
                                arr_tmp_attributes.append(key_name+ ":"+key_value)
                               
                            #popolo il dizionario di ritorno mettendo il tag come chiave del dizonario
                            #e gli attributi come valore ( che sara' una lista )
                            self.dict_ret_attr[all_father_tag.localName] = arr_tmp_attributes;
                           
                       
                #attacco all'array da restituire l'array arr_tmp valorizzato nel ciclo
                self.ret_list.append(arr_tmp)
               
        self.__stampaRis()


    def __stampaRis(self):
        for j in range(len(self.ret_list)):
            for k in range(len(self.ret_list[j])):
                print self.arr_tag[k], " ==> ", self.ret_list[j][k]
                try:
                    if self.dict_ret_attr[arr_tag[k]]:
                        print "Attributes= "+arr_tag[k]+" - "+" , ".join(self.dict_ret_attr[arr_tag[k]])
                except:
                    pass





#in questo array metto tutti i tag da cui estrarre i valori
arr_tag = ['nome','cognome','telefono_lavoro', 'telefono_casa', 'indirizzo_email']
#dizionario con gli attributi da cercare per tag
#nella chiave metto il nome del tag da cercare, nel valore una lista con gli attributi da cercare per il tag stesso
dic_attr_tag = {'nome' :  ['id', 'name'],  'telefono_lavoro' : ['tel', ]}


x = XmlSimpleParse("persona", arr_tag, dic_attr_tag,"prova.xml")
x.parseXml()

[/hlpycode]



metto anche il file xml di prova utilizzato
<?xml version="1.0"?>
   <rubrica>
    <persona>
     <nome id="uno" name="test1">Pippo</nome>
     <cognome>Bianchi</cognome>
     <telefono_casa> 010123456 </telefono_casa>
     <telefono_lavoro tel="010654321"> 010654321 </telefono_lavoro>
     <indirizzo_email>pippo@pippo.it </indirizzo_email>
   </persona>
   <persona>
    <nome id="due" name="test2">Giovanni </nome>
    <cognome>Bianchi</cognome>
    <telefono_casa> 010123456 </telefono_casa>
    <telefono_lavoro tel="010654321"> 010654321 </telefono_lavoro>
    <indirizzo_email>giovanni.bianchi@pippo.it </indirizzo_email>
   </persona>
   <persona>
    <nome id="tre" name="test3">Pluto</nome>
    <cognome>Rossi</cognome>
    <telefono_casa> 010123456 </telefono_casa>
    <telefono_lavoro tel="010654321"> 010654321 </telefono_lavoro>
    <indirizzo_email>pluto@pippo.it </indirizzo_email>
   </persona>
</rubrica>


ringrazio anticipatamente per i consigli.

ciao
Lore
« Ultima modifica: Novembre 06, 2008, 12:47 da lore84 »

Offline Wolf

  • python sapiens sapiens
  • *
  • moderatore
  • Post: 1.010
  • Punti reputazione: 0
    • Mostra profilo
Re: Parsing XML - consigli
« Risposta #1 il: Novembre 08, 2008, 17:29 »
Usare BeautifulSoup?

Offline lore84

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
Re: Parsing XML - consigli
« Risposta #2 il: Novembre 08, 2008, 21:37 »
Usare BeautifulSoup?

ciao wolf, sinceramente non sapevo esistesse, vedrò di studiarla e cercherò di rifarla utilizzando BeautifulSoup

se posso, volevo chiederti un parere sul codice che ho postato, se magari ho fatto errori concettuali o di altro tipo, piuttosto che semplificazioni del codice che, essendo all'inizio, purtroppo non conosco

grazie
ciao
Lorenzo

Offline Wolf

  • python sapiens sapiens
  • *
  • moderatore
  • Post: 1.010
  • Punti reputazione: 0
    • Mostra profilo
Re: Parsing XML - consigli
« Risposta #3 il: Novembre 08, 2008, 22:10 »
Più o meno sembra ok, non c'è motivo di usare uppercase per TAG_INIZIO, la funzione parseXML mi sembra un po' troppo incasinata, forse è meglio dividerla in più funzioni e alla fine dovrebbe restituire il risultato, non stamparlo. Per __stampaRis usa solo un _ davanti. Cerca di usare '%s - %s' % (foo, bar) invece di foo+' - '+bar. Non usare except senza specificare l'eccezione da catturare. Non scrivere più di 79 char per riga. Mettere troppi commenti può rendere il codice meno leggibile, se usi nomi chiari per le variabili e non fai cose strane in genere si capisce senza bisogno di spiegare passo passo quello che stai facendo, sarebbe meglio invece usare docstring per la classe e i metodi e eventualmente commentare passaggi che non sono troppo chiari. Il file lo passerei come primo argomento.

Offline Markon

  • python sapiens sapiens
  • *
  • moderatore
  • Post: 4.104
  • Punti reputazione: 5
    • Mostra profilo
    • Neolithic
Re: Parsing XML - consigli
« Risposta #4 il: Novembre 09, 2008, 10:53 »
Citazione
Più o meno sembra ok, non c'è motivo di usare uppercase per TAG_INIZIO, la funzione parseXML mi sembra un po' troppo incasinata, forse è meglio dividerla in più funzioni e alla fine dovrebbe restituire il risultato, non stamparlo. Per __stampaRis usa solo un _ davanti. Cerca di usare '%s - %s' % (foo, bar) invece di foo+' - '+bar. Non usare except senza specificare l'eccezione da catturare. Non scrivere più di 79 char per riga. Mettere troppi commenti può rendere il codice meno leggibile, se usi nomi chiari per le variabili e non fai cose strane in genere si capisce senza bisogno di spiegare passo passo quello che stai facendo, sarebbe meglio invece usare docstring per la classe e i metodi e eventualmente commentare passaggi che non sono troppo chiari. Il file lo passerei come primo argomento.

Diciamo che il prossimo programma che farò, prima di farlo passare per Python lo farò passare per Wolf .
 :D :D :D :party:

Offline lore84

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
Re: Parsing XML - consigli
« Risposta #5 il: Novembre 09, 2008, 11:05 »
la funzione parseXML mi sembra un po' troppo incasinata, forse è meglio dividerla in più funzioni
hai ragione, in effetti poi l'avevo modificata suddividendola in 2 funzioni, la principale che mi prende il testo nei tag e la seconda che mi recupera gli eventuali attributi


Mettere troppi commenti può rendere il codice meno leggibile, se usi nomi chiari per le variabili e non fai cose strane in genere si capisce senza bisogno di spiegare passo passo quello che stai facendo,
su questo non sono daccordo: fino a quando si tratta di un programmino così è un conto, ma quando si lavora su progetti ben più grandi, preferisco commentare quello che riesco perchè in caso ci si dovesse andare a lavorare dopo X tempo almeno sarebbe tutto + chiaro, anche per un'eventuale persona esterna che vedesse il codice per la prima volta, non è detto che per lui/lei i nomi delle variabili siano sufficientemente chiari, ma penso sia questione di "gusti" personali  ;)


e alla fine dovrebbe restituire il risultato, non stamparlo. Per __stampaRis usa solo un _ davanti.
Cerca di usare '%s - %s' % (foo, bar) invece di foo+' - '+bar.
Non usare except senza specificare l'eccezione da catturare.
Non scrivere più di 79 char per riga.
sarebbe meglio invece usare docstring per la classe e i metodi e eventualmente commentare passaggi che non sono troppo chiari.
Il file lo passerei come primo argomento.
grazie 1000 per tutte le correzioni, appena riesco vedrò di metterle in pratica.

ciao!

Offline Sabba

  • python neanderthalensis
  • ****
  • Post: 411
  • Punti reputazione: 2
    • Mostra profilo
Re: Parsing XML - consigli
« Risposta #6 il: Novembre 09, 2008, 11:08 »
Sull'onda della qualità di scrittura del codice python vorrei approfittare per segnalare questo strumento: Pylint (http://www.logilab.org/857)

Ottimo per chi sta imparando e utilissimo in ogni caso. ;)

Offline Wolf

  • python sapiens sapiens
  • *
  • moderatore
  • Post: 1.010
  • Punti reputazione: 0
    • Mostra profilo
Re: Parsing XML - consigli
« Risposta #7 il: Novembre 09, 2008, 18:18 »
Mettere troppi commenti può rendere il codice meno leggibile, se usi nomi chiari per le variabili e non fai cose strane in genere si capisce senza bisogno di spiegare passo passo quello che stai facendo,
su questo non sono daccordo: fino a quando si tratta di un programmino così è un conto, ma quando si lavora su progetti ben più grandi, preferisco commentare quello che riesco perchè in caso ci si dovesse andare a lavorare dopo X tempo almeno sarebbe tutto + chiaro, anche per un'eventuale persona esterna che vedesse il codice per la prima volta, non è detto che per lui/lei i nomi delle variabili siano sufficientemente chiari, ma penso sia questione di "gusti" personali  ;)
Se il programma è organizzato bene dovresti avere funzioni che mediamente non superano le 10-20 righe e svolgono un compito preciso che può essere descritto nella docstring. Quando uno legge codice altrui (o rilegge il suo codice dopo un po') in genere non parte dalla prima riga e legge tutto fino all'ultima, ma cerca di capire cosa fanno le funzioni e come sono connesse tra loro, una volta che ha capito dov'è il problema non è difficile leggere e capire 10-20 righe di codice se sono scritte chiaramente.
Per me risulta più difficile leggere codice se è intervallato da commenti, preferisco avere brevi commenti a lato oppure 2 righe all'inizio che spiegano cosa fanno le righe successive, es:
[hlpycode]
# controlla se l'ip espresso in esadecimale è valido
if all(0 <= int(x, 16) < 256 for x in addr.split('.')) and addr.count('.') == 3:
    ...
[/hlpycode]
ma sarebbe sufficiente fare qualcosa tipo:
[hlpycode]
octets = [int(hex_octet, 16) for hex_octet in hex_ip.split('.')]
if all(0 <= octet <= 255 for octet in octets) and len(octets) == 4:
    ...
[/hlpycode]
per capire che l'ip è espresso in esadecimale, viene convertito in una lista di ottetti in decimale e poi viene controllato se gli ottetti sono 4 e se il loro valore è compreso tra 0 e 255, anche se non ci sono commenti.