Barra laterale

programmazione:libxml2:utilizzo_di_base

Utilizzo di base di Libxml2

Autore: Fabio Di Matteo
Ultima revisione: 19/09/2008

Libxml2 e' una libreria che si occupa dell'elaborazione dei file Xml .
Con essa si possono scrivere e leggere quindi file Xml.

Risorse:
http://student.santarosa.edu/~dturover/?node=libxml2
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:

    <nodo attributo1="valore_attr1" attributo2="12345">
            <nodo figlio>Hello World</nodo figlio>
    </nodo>

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.

<?xml version="1.0"?>
<articolo>
  <info>
    <autore>Fabio Di Matteo</autore>
    <data>01 Gennaio 1970</data>
    <titolo>Titolo articolo</titolo>
  </info>
  <body>
    <testo>Questo e' il testo dell'articolo.</testo>
  </body>
</articolo>

Come vediamo esiste un tag (nodo) <articolo> 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 <info> e <body> . Dentro quest'ultimi infine gli elementi che racchiudono i dati. Sotto <info> ci sono <autore>, <data>, <titolo>, invece sotto <body> c'e' solo <testo> .

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 <articolo>);
  • xmlChar* node e' il nodo della sottocategoria (nel nostro caso potrebbe essere <info> oppure <body>) ;
  • xmlChar* key e' invece ,finalmente ,la chiave che contiene i dati(nel nostro caso potrebbe essere <autore> <data> <titolo> per il nodo <info> oppure <testo> per il nodo <body>);

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 <articolo>);
  • xmlChar* node e' il nodo della sottocategoria (nel nostro caso potrebbe essere <info> oppure <body>) ;
  • xmlChar* key e' ,la chiave che contiene i dati(nel nostro caso potrebbe essere <autore> <data> <titolo> per il nodo <info> oppure <testo> per il nodo <body>);
  • 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 <articolo>);
  • xmlChar* node e' il nodo della sottocategoria (nodo figlio) (nel nostro caso potrebbe essere <info> oppure <body>) ;
  • xmlChar* key e' invece la chiave che contiene i dati(nel nostro caso potrebbe essere <autore> <data> <titolo> per il nodo <info> oppure <testo> per il nodo <body>);

* 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 <articolo>);
  • xmlChar* node e' il nodo della sottocategoria (nodo figlio) (nel nostro caso potrebbe essere <info> oppure <body>) ;
  • xmlChar* key e' invece la chiave che contiene i dati(nel nostro caso potrebbe essere <autore> <data> <titolo> per il nodo <info> oppure <testo> per il nodo <body>);

Sorgente completo di tutte le funzioni

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
 
 
/*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

programmazione/libxml2/utilizzo_di_base.txt · Ultima modifica: 18/04/2018 - 15:49 (modifica esterna)