fortuna che non era impossibile... |
// tipo Film per test typedef struct { char title[32]; char director[32]; int year; } Film; // tipo Catalog per test typedef struct { time_t t_lastupd; Film films[2]; } Catalog;in un programma la possiamo riempire con un po' di dati (beh, in questo caso pochi, è solo un esempio) e con il nostro XML Serializer cerchiamo di ottenere un documento XML tipo questo:
<?xml version="1.0"?> <CATALOG> <LASTUPDATE>28/11/15 12:26:04</LASTUPDATE> <FILM> <TITLE>Mad Max 2: The Road Warrior</TITLE> <DIRECTOR>George Miller</DIRECTOR> <YEAR>1979</YEAR> </FILM> <FILM> <TITLE>Mad Max: Fury Road</TITLE> <DIRECTOR>George Miller</DIRECTOR> <YEAR>2015</YEAR> </FILM> </CATALOG>Ok, visto che siete impazienti di sapere come si fa, passiamo subito al codice:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <libxml/parser.h> // tipo Film per test typedef struct { char title[32]; char director[32]; int year; } Film; // tipo Catalog per test typedef struct { time_t t_lastupd; Film films[2]; } Catalog; // prototipi locali char* serialize(char* document, const Catalog* catalog); // main() del programma di test int main(int argc, char* argv[]) { // test argomenti if (argc != 1) { printf("%s: wrong arguments counts\n", argv[0]); printf("usage: %s [e.g.: %s]\n", argv[0], argv[0]); return EXIT_FAILURE; } /* libxml2: initializza la libreria e testa potenziali ABI mismatches tra la versione compilata e la attuale shared library usata */ LIBXML_TEST_VERSION; // prepara dati per test char dest_document_xml[2048]; Catalog catalog; catalog.t_lastupd = time(NULL); strcpy(catalog.films[0].title, "Mad Max 2: The Road Warrior"); strcpy(catalog.films[0].director, "George Miller"); catalog.films[0].year = 1979; strcpy(catalog.films[1].title, "Mad Max: Fury Road"); strcpy(catalog.films[1].director, "George Miller"); catalog.films[1].year = 2015; // serializza XML serialize(dest_document_xml, &catalog); // scrive i risultati in un file FILE* fp = fopen("catalog.xml", "w"); fprintf(fp, "%s", dest_document_xml); fclose(fp); // esce con Ok return EXIT_SUCCESS; } // funzione serialize() char* serialize( char* document, // documento destino serializzato const Catalog* catalog) // struttura documento { // crea documento con root node <CATALOG> xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "CATALOG"); xmlDocSetRootElement(doc, root_node); // aggiunge <LASTUPD> child-field al nodo <CATALOG> char str_lastupd[64]; strftime(str_lastupd, sizeof(str_lastupd), "%d/%m/%y %H:%M:%S", localtime(&catalog->t_lastupd)); xmlNewChild(root_node, NULL, BAD_CAST "LASTUPDATE", BAD_CAST str_lastupd); // loop per aggiungere i child-nodes <FILM> e child-fields al nodo <CATALOG> int i; for (i = 0; i < sizeof(catalog->films) / sizeof(Film); i++) { // aggiunge il child-node <FILM> al nodo <CATALOG> xmlNodePtr film_node = xmlNewChild(root_node, NULL, BAD_CAST "FILM", BAD_CAST NULL); // aggiunge i child-fields al nodo <FILM> xmlNewChild(film_node, NULL, BAD_CAST "TITLE", BAD_CAST catalog->films[i].title); xmlNewChild(film_node, NULL, BAD_CAST "DIRECTOR", BAD_CAST catalog->films[i].director); char s_year[8]; sprintf(s_year, "%d", catalog->films[i].year); xmlNewChild(film_node, NULL, BAD_CAST "YEAR", BAD_CAST s_year); } // copia il document al documento destino xmlChar *xmlbuff; int buffersize; xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1); strcpy(document, (char *)xmlbuff); // libera risorse xmlFree(xmlbuff); xmlFreeDoc(doc); xmlCleanupParser(); // return un pointer al document formattato return document; }Ok, come vedete il codice è (come sempre in questo Blog) ampiamente commentato e quindi è auto-esplicativo, per cui non mi dilungherò sulle singole istruzioni e/o gruppi di istruzioni (leggete i commenti! sono li per quello!), ma aggiungerò, solo (al solito), qualche dettaglio strutturale.
Il main() è solo funzionale all'esempio: inizializza la libreria (leggete il commento!), prepara i dati per il test, li passa al Serializer, scrive i risultati in un file.
Quello che conta è la funzione serialize(), che si può usare dove e come si vuole in un programma che usa le strutture dati descritte sopra, e che, soprattutto, può essere usata come esempio per scrivere funzioni analoghe per altre strutture dati: è molto semplice e si può adattare facilmente a qualsiasi altro caso. Come si nota usa varie funzioni della libreria libXML2, e il meccanismo che permette di riempire il documento destino è semplice: si crea un nodo di partenza (root-node) e si aggiungono figli (child-nodes) seguendo la forma della struttura dati originale.
Dimenticavo: 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 serxml.c -I/usr/include/libxml2 -o serxml -lxml2Nel prossimo post (se non cambio idea nel frattempo) vedremo la funzione inversa, un XML Deserializer (e qui ci starebbe bene un "Ohhhhhhh" di stupore).
Ciao e al prossimo post!
Nessun commento:
Posta un commento