Scrivere Software è un piacere. Un programma non solo deve funzionare bene ed essere efficiente (questo si dà per scontato), ma deve essere anche bello ed elegante da leggere, comprensibile e facile da manutenere, sia per l'autore che per eventuali lettori futuri. Programmare bene in C è un'arte.
Nei titoli e nei testi troverete qualche rimando cinematografico (ebbene si, sono un cinefilo). Se non vi interessano fate finta di non vederli, già che non sono fondamentali per la comprensione dei post...
Di questo blog ho mandato avanti, fino a Settembre 2018, anche una versione in Spagnolo. Potete trovarla su El arte de la programación en C. Buona lettura.
giovedì 24 dicembre 2015
domenica 6 dicembre 2015
Mission: Impossible - XML Deserializer
come scrivere un XML Deserializer in C
Come promesso torniamo con una nuova missione (non tanto) impossibile per proporre un Deserializer complementare al Serializer dell'ultimo post. Ovviamente, se non avete ancora letto il post precedente, dovreste:
1) vergognarvi
2) andare a leggerlo. Subito!
Ecco, se state leggendo queste righe può darsi che avete già passato i due punti precedenti, quindi possiamo continuare. Useremo anche questa volta la libXML2 per scrivere una funzione che riesce a estrarre tutte le coppie key-value che compongono un documento XML.
Vai col codice!
1) codice auto-esplicativo, ampiamente commentato e... i commenti parlano da soli.
2) il main() serve solo a lanciare la funzione deserialize(): concentratevi su quella.
La funzione, in realtà è divisa in due parti: deserialize() prepara la lettura del documento e recurDoc() (che è una funzione ricorsiva che richiama se stessa) ricorre il documento n-volte fino a quando ci sono campi da leggere.
Questo esempio è adatto a leggere qualsiasi file XML che gli si passa come argomento, e si può specializzare facilmente: ad esempio se gli passate un file di struttura nota (per esempio si può provare con il catalogo XML di film prodotto dal nostro precedente Serializer) potete riempire con i campi key-value letti i campi della struttura dati corrispondente (nel nostro caso la struct Catalog). Insomma, con un po' di immaginazione la coppia Serializer/Deserializer che vi ho proposto, permette un sacco di interessanti attività in programmi che usano dati in formato XML. Buon lavoro...
Vi ricordo nuovamente che, per testare l'esempio su Linux (cosa che ho fatto, ovviamente...) bisogna installare prima la libXML2 (dal repository della distribuzione), e poi compilare il programma con:
1) vergognarvi
2) andare a leggerlo. Subito!
Ecco, se state leggendo queste righe può darsi che avete già passato i due punti precedenti, quindi possiamo continuare. Useremo anche questa volta la libXML2 per scrivere una funzione che riesce a estrarre tutte le coppie key-value che compongono un documento XML.
![]() |
Sempre più facile... |
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <libxml/parser.h> // prototipi locali void deserialize(const char* document); void recurDoc(xmlDocPtr doc, xmlNodePtr cur); // main del programma di test int main(int argc, char **argv) { // test argomenti if (argc <= 1) { printf("Usage: %s docname\n", argv[0]); return(0); } /* libxml2: initializza la libreria e testa potenziali ABI mismatches tra la versione compilata e la attuale shared library usata */ LIBXML_TEST_VERSION; // deserializza XML deserialize(argv[1]); // esce con Ok return EXIT_SUCCESS; } // funzione deserialize() void deserialize( const char* document) { // salta i blank nodes xmlKeepBlanksDefault(0); // estrae il documento dal file xmlDocPtr doc; if ((doc = xmlParseFile(document)) == NULL ) { fprintf(stderr,"Document not parsed successfully. \n"); return; } // test se il documento non è vuoto xmlNodePtr cur; if ((cur = xmlDocGetRootElement(doc)) == NULL) { fprintf(stderr,"empty document\n"); xmlFreeDoc(doc); return; } // ricorre e libera il documento recurDoc(doc, cur); xmlFreeDoc(doc); } // funzione ricorsiva di lettura del documento void recurDoc( xmlDocPtr doc, xmlNodePtr cur) { // loop di lettura xmlChar *value; cur = cur->xmlChildrenNode; while (cur != NULL) { // estrae e libera un elemento if ((value = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)) != NULL) { printf("key: %-10s - value: %s\n", cur->name, value); xmlFree(value); } // chiamata ricorsiva recurDoc(doc, cur); // passa al prossimo elemento cur = cur->next; } // esce return; }E, come sempre:
1) codice auto-esplicativo, ampiamente commentato e... i commenti parlano da soli.
2) il main() serve solo a lanciare la funzione deserialize(): concentratevi su quella.
La funzione, in realtà è divisa in due parti: deserialize() prepara la lettura del documento e recurDoc() (che è una funzione ricorsiva che richiama se stessa) ricorre il documento n-volte fino a quando ci sono campi da leggere.
Questo esempio è adatto a leggere qualsiasi file XML che gli si passa come argomento, e si può specializzare facilmente: ad esempio se gli passate un file di struttura nota (per esempio si può provare con il catalogo XML di film prodotto dal nostro precedente Serializer) potete riempire con i campi key-value letti i campi della struttura dati corrispondente (nel nostro caso la struct Catalog). Insomma, con un po' di immaginazione la coppia Serializer/Deserializer che vi ho proposto, permette un sacco di interessanti attività in programmi che usano dati in formato XML. Buon lavoro...
Vi ricordo nuovamente che, per testare l'esempio su Linux (cosa che ho fatto, ovviamente...) bisogna installare prima la libXML2 (dal repository della distribuzione), e poi compilare il programma con:
gcc desxml.c -I/usr/include/libxml2 -o desxml -lxml2Ciao e al prossimo post!
Iscriviti a:
Post (Atom)