====== Utilizzo di base di Libxml2 ====== Autore: **//Fabio Di Matteo//** \\ Ultima revisione: **//19/09/2008//** \\ \\ [[http://xmlsoft.org/|Libxml2]] e' una libreria che si occupa dell'elaborazione dei file [[http://it.wikipedia.org/wiki/XML|Xml]] . \\ Con essa si possono scrivere e leggere quindi file Xml.\\ Risorse: \\ [[http://student.santarosa.edu/~dturover/?node=libxml2|http://student.santarosa.edu/~dturover/?node=libxml2]]\\ [[http://xmlsoft.org/tutorial/xmltutorial.pdf|http://xmlsoft.org/tutorial/xmltutorial.pdf]] ===== Un pochino di teoria ===== Un file xml e' un file di testo formato da diversi nodi che assomigliano ai tag html. Un nodo xml e' qualcosa del genere: Hello World Le cose che si possono manipolare sono il **nodo** stesso, gli **attributi** del nodo e il **contenuto del nodo**. ===== File xml da esaminare ===== Immaginiamo per esempio che il seguente file serva ad una qualche applicazione per prendere informazioni riguardo un articolo. Fabio Di Matteo 01 Gennaio 1970 Titolo articolo Questo e' il testo dell'articolo. Come vediamo esiste un tag (nodo) '''' che e' la radice principale ovvero il tag piu' esterno (la root del file xml). \\ All'inerno della root abbiamo poi altri nodi principali come '''' e '''' . Dentro quest'ultimi infine gli elementi che racchiudono i dati. Sotto '''' ci sono '', , '', invece sotto '''' c'e' solo '''' . ===== Le nostre funzioni ===== xmlChar* ReadXmlNodeContent(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key ); void NewXmlNode(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key, xmlChar *keyvalue ); void SetXmlNodeContent(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key, xmlChar *keyvalue ); void DelXmlNode(char *filename, xmlChar* root ,xmlChar* node, xmlChar *key); Scriveremo delle funzioni per scrivere e leggere i tag del file. ===== Esempi di utilizzo delle funzioni ===== Ecco come potrebbero utilizzarsi le funzioni: ... /*Aggiunge un nuovo nodo dentro body di nome testo2 con il contenuto "iuppiieeeee"*/ NewXmlNode("file.xml", "articolo" ,"body", "testo2", "iuppiieeeee" ) ; /*Modifica il nodo data contenuto nel nodo info con il valore "31/10/1915" */ SetXmlNodeContent("file.xml", "articolo" ,"info", "data", "31/10/1915" ) ; /*Cancelliamo il nodo titolo contenuto nel nodo info*/ DelXmlNode(argv[1], "articolo", "info", "titolo" ); /*Stampa a video il contenuto del nodo autore che a sua volta e' figlio del nodo info*/ xmlChar *mykey = ReadXmlNodeContent("file.xml", "articolo" , "info", "autore" ); printf("Autore-->%s\n", mykey); ... ==== Lettura contenuto nodo ==== Per la lettura dei tag la funzione avra' il seguente prototipo xmlChar* ReadXmlNodeContent(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key ); Dove: * ''char* filename'' e' il percorso del file xml; * ''xmlChar* root'' e' il nodo root (nel nostro caso ////); * ''xmlChar* node'' e' il nodo della sottocategoria (nel nostro caso potrebbe essere //// oppure ////) ; * ''xmlChar* key'' e' invece ,finalmente ,la chiave che contiene i dati(nel nostro caso potrebbe essere // // per il nodo //// oppure //// per il nodo ////); \\ \\ La funzione restituisce il valore della chiave ''xmlChar* key'' sottoforma di ''xmlChar* '' che puo' essere trattato come qualsiasi puntatore a char. ==== Aggiunta nuovo Nodo ==== Per la lettura dei tag la funzione avra' il seguente prototipo void NewXmlNode(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key, xmlChar *keyvalue ); Dove: * ''char* filename'' e' il percorso del file xml; * ''xmlChar* root'' e' il nodo root (nel nostro caso ////); * ''xmlChar* node'' e' il nodo della sottocategoria (nel nostro caso potrebbe essere //// oppure ////) ; * ''xmlChar* key'' e' ,la chiave che contiene i dati(nel nostro caso potrebbe essere // // per il nodo //// oppure //// per il nodo ////); * ''xmlChar* keyvalue'' e' il contenuto del nodo . \\ \\ ==== Modifica contenuto nodo ==== Per la modifica del contenuto di un nodo la funzione avra' il seguente prototipo void SetXmlNodeContent(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key, xmlChar *keyvalue ); Dove: * ''char* filename'' e' il percorso del file xml; * ''xmlChar* root'' e' il nodo root (nel nostro caso ////); * ''xmlChar* node'' e' il nodo della sottocategoria (nodo figlio) (nel nostro caso potrebbe essere //// oppure ////) ; * ''xmlChar* key'' e' invece la chiave che contiene i dati(nel nostro caso potrebbe essere // // per il nodo //// oppure //// per il nodo ////); \\ \\ * ''xmlChar* keyvalue'' e' il contenuto del nodo \\ \\ ==== Eliminazione di un nodo ==== Per eliminare un nodo serve una funzione come questa il seguente prototipo void DelXmlNode(char *filename, xmlChar* root ,xmlChar* node, xmlChar *key); Dove: * ''char* filename'' e' il percorso del file xml; * ''xmlChar* root'' e' il nodo root (nel nostro caso ////); * ''xmlChar* node'' e' il nodo della sottocategoria (nodo figlio) (nel nostro caso potrebbe essere //// oppure ////) ; * ''xmlChar* key'' e' invece la chiave che contiene i dati(nel nostro caso potrebbe essere // // per il nodo //// oppure //// per il nodo ////); \\ \\ ===== Sorgente completo di tutte le funzioni ===== #include #include #include #include #include /*prototipo funzioni ausiliarie (vedi in fondo)*/ xmlChar* ReadParseNode (xmlDocPtr doc, xmlNodePtr cur,xmlChar *key) ; void AddParseNode (xmlDocPtr doc, xmlNodePtr cur, char *key, char* keyvalue) ; void SetParseNode (xmlDocPtr doc, xmlNodePtr cur, xmlChar *key, xmlChar* keyvalue) ; void DelParseNode (xmlDocPtr doc, xmlNodePtr cur, xmlChar *key); /*Prototipi funzioni principali*/ xmlChar* ReadXmlNodeContent(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key ); void NewXmlNode(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key, xmlChar *keyvalue ); void DelXmlNode(char *filename, xmlChar* root ,xmlChar* node, xmlChar *key); void SetXmlNodeContent(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key, xmlChar *keyvalue ); xmlChar* ReadXmlNodeContent(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key ){ /* Variabili che ci servono*/ xmlDocPtr doc; xmlNodePtr cur; //nodo da cui si comincia a cercare xmlChar *value; //valore di ritorno della funzione /* Verifichiamo se il file xml e' conforme*/ doc = xmlParseFile(filename); if (doc == NULL ) { fprintf(stderr,"Non e' stato possibile interpretare il file xml. \n"); return ; } /* Ricaviamo il nodo radice del file xml (root node)*/ cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr,"Documento vuoto!\n"); xmlFreeDoc(doc); return; } /* Verifichiamo che esista un nodo root con il nostro nome*/ if (xmlStrcmp(cur->name, root)) { fprintf(stderr,"Errore nel formato del file xml\n"); xmlFreeDoc(doc); return; } /* Adesso partendo da il nodo "node" scandisce i solo nodi contenuti in esso * finche non trova la chiave di nome "key" vedi proptotipo funzione. */ cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name,(const xmlChar *) node ))){ /* funzione d'appoggio, per non appesantire il codice * dove doc e' il puntatore al file xml, cur e' la posizione * del nodo corrente, key e' il nome della chiave e keyvalue */ value = ReadParseNode (doc, cur,key ); return value; } cur = cur->next; } /*Scarichiamo dalla memoria cio' che non serve*/ xmlFreeDoc(doc); /*ritorniamo il valore della funzione*/ return value; } void NewXmlNode(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key, xmlChar *keyvalue ) { /* Variabili che ci servono*/ xmlDocPtr doc; xmlNodePtr cur; //nodo da cui si comincia a cercare /* Verifichiamo se il file xml e' conforme*/ doc = xmlParseFile(filename); if (doc == NULL ) { fprintf(stderr,"Non e' stato possibile interpretare il file xml. \n"); return ; } /* Ricaviamo il nodo radice del file xml (root node)*/ cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr,"Documento vuoto!\n"); xmlFreeDoc(doc); return; } /* Verifichiamo che esista un nodo root con il nostro nome*/ if (xmlStrcmp(cur->name, root)) { fprintf(stderr,"Errore nel formato del file xml\n"); xmlFreeDoc(doc); return; } /* Adesso partendo da il nodo "node" scandisce i solo nodi contenuti in esso * finche non trova la chiave di nome "key" vedi proptotipo funzione. */ cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name,(const xmlChar *) node ))){ /* funzione d'appoggio, per non appesantire il codice * dove doc e' il puntatore al file xml, cur e' la posizione * del nodo corrente, key e' il nome della chiave e keyvalue * il valore della chiave*/ AddParseNode (doc, cur,key, keyvalue ); } cur = cur->next; } /*Salviamo il file*/ xmlSaveFormatFile (filename, doc, 1); /*Scarichiamo dalla memoria cio' che non serve*/ xmlFreeDoc(doc); return ; } void DelXmlNode(char *filename ,xmlChar* root ,xmlChar* node, xmlChar *key){ /* Variabili che ci servono*/ xmlDocPtr doc; xmlNodePtr cur; //nodo da cui si comincia a cercare /* Verifichiamo se il file xml e' conforme*/ doc = xmlParseFile(filename); if (doc == NULL ) { fprintf(stderr,"Non e' stato possibile interpretare il file xml. \n"); return ; } /* Ricaviamo il nodo radice del file xml (root node)*/ cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr,"Documento vuoto!\n"); xmlFreeDoc(doc); return; } /* Verifichiamo che esista un nodo root con il nostro nome*/ if (xmlStrcmp(cur->name, root)) { fprintf(stderr,"Errore nel formato del file xml\n"); xmlFreeDoc(doc); return; } /* Adesso partendo da il nodo "node" scandisce i solo nodi contenuti in esso * finche non trova la chiave di nome "key" vedi proptotipo funzione. */ cur = cur->xmlChildrenNode; FILE* fxml; while (cur != NULL) { if ((!xmlStrcmp(cur->name,(const xmlChar *) node ))){ /* funzione d'appoggio, per non appesantire il codice * dove doc e' il puntatore al file xml, cur e' la posizione * del nodo corrente, key e' il nome della chiave e keyvalue */ DelParseNode (doc, cur, key); } cur = cur->next; } /*Salviamo il file*/ xmlSaveFormatFile (filename, doc, 1); /*Scarichiamo dalla memoria cio' che non serve*/ xmlFreeDoc(doc); } /* Queste sono funzioni ausiliarie alle funzioni principali , non sono da usarsi da sole. * Potevano comunque essere accorpate dentro le funzioni principali, ma per non appesantirle abbiamo * deciso di tenerle fuori proprio come nel tutorial ufficiale*/ xmlChar* ReadParseNode (xmlDocPtr doc, xmlNodePtr cur,xmlChar *key) { /*Variabile di ritorno della funzione */ xmlChar *value; /*Nodo da cui si comincia a cercare*/ cur = cur->xmlChildrenNode; /* Individua la chiave contenuta nel nodo cur e ne restituisce il valore * grazie alla variabile "cur" */ while (cur != NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *) key))) { value = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } cur = cur->next; } return value; } void SetXmlNodeContent(char* filename, xmlChar* root ,xmlChar* node, xmlChar* key, xmlChar *keyvalue ){ /* Variabili che ci servono*/ xmlDocPtr doc; xmlNodePtr cur; //nodo da cui si comincia a cercare /* Verifichiamo se il file xml e' conforme*/ doc = xmlParseFile(filename); if (doc == NULL ) { fprintf(stderr,"Non e' stato possibile interpretare il file xml. \n"); return ; } /* Ricaviamo il nodo radice del file xml (root node)*/ cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr,"Documento vuoto!\n"); xmlFreeDoc(doc); return; } /* Verifichiamo che esista un nodo root con il nostro nome*/ if (xmlStrcmp(cur->name, root)) { fprintf(stderr,"Errore nel formato del file xml\n"); xmlFreeDoc(doc); return; } /* Adesso partendo da il nodo "node" scandisce i solo nodi contenuti in esso * finche non trova la chiave di nome "key" vedi proptotipo funzione. */ cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name,(const xmlChar *) node ))){ /* funzione d'appoggio, per non appesantire il codice * dove doc e' il puntatore al file xml, cur e' la posizione * del nodo corrente, key e' il nome della chiave e keyvalue * il valore della chiave*/ SetParseNode (doc, cur,key, keyvalue ); } cur = cur->next; } /*Salviamo il file*/ xmlSaveFormatFile (filename, doc, 1); /*Scarichiamo dalla memoria cio' che non serve*/ xmlFreeDoc(doc); return ; } void SetParseNode (xmlDocPtr doc, xmlNodePtr cur, xmlChar *key, xmlChar* keyvalue) { /* Modifica la chiave "key" con valore "keyvalue" nella posizione * "cur" */ /*Nodo da cui si comincia a cercare*/ cur = cur->xmlChildrenNode; /* Individua la chiave contenuta nel nodo cur e ne restituisce il valore * grazie alla variabile "cur" */ while (cur != NULL) { if ((!xmlStrcmp(cur->name, key))) { xmlNodeSetContent(cur,keyvalue ); } cur = cur->next; } return; } void DelParseNode (xmlDocPtr doc, xmlNodePtr cur, xmlChar *key) { /* Modifica la chiave "key" con valore "keyvalue" nella posizione * "cur" */ /*Nodo da cui si comincia a cercare*/ cur = cur->xmlChildrenNode; /* Individua la chiave contenuta nel nodo cur e ne restituisce il valore * grazie alla variabile "cur" */ while (cur != NULL) { if ((!xmlStrcmp(cur->next->name, key))) { /*qualcoca per cancellare il nodo*/ cur->next=NULL; } cur = cur->next; } return; } void AddParseNode (xmlDocPtr doc, xmlNodePtr cur, char *key, char* keyvalue) { /* Aggiunge la chiave "key" con valore "keyvalue" nella posizione * "cur" */ xmlNewTextChild (cur, NULL, key, keyvalue); return; } int main(int argc, char *argv[]){ /*Aggiunge un nuovo nodo dentro body di nome testo2 con il contenuto "iuppiieeeee"*/ NewXmlNode(argv[1], "articolo" ,"body", "testo2", "iuppiieeeee" ) ; /*Cancelliamo il nodo titolo contenuto nel nodo info*/ DelXmlNode(argv[1], "articolo", "info", "titolo" ); /*Modifica il nodo data contenuto nel nodo info con il valore "31/10/1915" */ SetXmlNodeContent(argv[1], "articolo" ,"info", "data", "31/10/1915" ) ; /*Stampa a video il contenuto del nodo autore che a sua volta e' figlio del nodo info*/ xmlChar *mykey = ReadXmlNodeContent(argv[1], "articolo" , "info", "autore" ); printf("Autore-->%s\n", mykey); return 0; } ===== Makefile ===== //Linkaggio a libxml2 dinamico // CPP = gcc OPTS = `xml2-config --cflags --libs` all: $(CPP) main.c -o main $(OPTS) clean: rm main