/* Firebox Tools - Outils de configurations pour le WM Firebox * xml.c - lecture ou écriture de documents XML * * Copyright (C) 2006-2007 Cyrille Bagard * * This file is part of Firebox Tools. * * Firebox Tools is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Firebox Tools is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "xml.h" #include #include #ifdef DEBUG # define XML_LOG fprintf #else # define XML_LOG if (FALSE) fprintf #endif /* ---------------------------------------------------------------------------------- */ /* OPERATIONS DE LECTURE D'UN FICHIER XML */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : filename = nom du fichier à ouvrir. * * xdoc = structure XML chargée. [OUT] * * xroot = noeud premier de l'ensemble des définitions.[OUT] * * xpathCtx = contexte à utiliser pour les recherches. [OUT] * * * * Description : Ouvre un fichier XML de façon encadrée. * * * * Retour : true si l'opération a pu s'effectuer, false sinon. * * * * Remarques : - * * * ******************************************************************************/ gboolean open_xml_file(const char *filename, xmlDoc **xdoc, xmlNode **xroot, xmlXPathContextPtr *xpathCtx) { *xdoc = xmlParseFile(filename); if (*xdoc == NULL) { XML_LOG(stderr, "Can not parse the XML file '%s'\n", filename); return FALSE; } *xroot = xmlDocGetRootElement(*xdoc); if (*xroot == NULL) { XML_LOG(stderr, "Can not access the root node in '%s'\n", filename); xmlFreeDoc(*xdoc); return FALSE; } *xpathCtx = xmlXPathNewContext(*xdoc); if (*xpathCtx == NULL) { XML_LOG(stderr, "Unable to create new XPath context\n"); xmlFreeDoc(*xdoc); return FALSE; } return TRUE; } /****************************************************************************** * * * Paramètres : xpathCtx = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * * * Description : Obtient de façon encadrée l'accès à un noeud défini. * * * * Retour : Adresse de l'accès trouvé. * * * * Remarques : - * * * ******************************************************************************/ xmlXPathObjectPtr get_node_xpath_object(xmlXPathContextPtr xpathCtx, const char *path) { xmlXPathObjectPtr result; /* Noeud XML à renvoyer */ result = xmlXPathEvalExpression(BAD_CAST path, xpathCtx); if (result == NULL) { XML_LOG(stderr, "Unable to evaluate xpath expression '%s'\n", path); return NULL; } if (result->nodesetval == NULL) { XML_LOG(stderr, "Node '%s' not found\n", path); xmlXPathFreeObject(result); return NULL; } return result; } /****************************************************************************** * * * Paramètres : node = noeud dont une propriété est à lire. * * * * Description : Obtient une valeur placée entre <...> et . * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *qck_get_node_text_value(xmlNodePtr node) { char *result; /* Valeur en question renvoyée */ result = NULL; if (node != NULL) if (node->children != NULL) if (node->children->content != NULL) result = strdup((char *)node->children->content); if (result == NULL) XML_LOG(stderr, "No text value for node '%s'\n", node->name); return result; } /****************************************************************************** * * * Paramètres : xpathCtx = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * * * Description : Obtient une valeur placée entre <...> et . * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *get_node_text_value(xmlXPathContextPtr xpathCtx, const char *path) { char *result; /* Valeur en question renvoyée */ xmlXPathObjectPtr xpathObj; /* Point de départ XML */ result = NULL; xpathObj = get_node_xpath_object(xpathCtx, path); if (xpathObj == NULL) return NULL; if (xpathObj->nodesetval->nodeNr > 0) result = qck_get_node_text_value(xpathObj->nodesetval->nodeTab[0]); xmlXPathFreeObject(xpathObj); return result; } /****************************************************************************** * * * Paramètres : node = noeud dont une propriété est à lire. * * name = nom de la propriété à lire. * * * * Description : Obtient la valeur d'une propriété d'un élément. * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *qck_get_node_prop_value(xmlNodePtr node, const char *name) { char *result; /* Valeur en question renvoyée */ xmlAttrPtr attrib; /* Liste d'attributs présents */ result = NULL; if (node == NULL) return NULL; /* Lecture de la valeur */ for (attrib = node->properties; attrib != NULL && result == NULL; attrib = attrib->next) if (xmlStrEqual(attrib->name, BAD_CAST name)) result = strdup((char *)attrib->children->content); return result; } /****************************************************************************** * * * Paramètres : xpathCtx = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud à traiter. * * name = nom de la propriété à lire. * * * * Description : Obtient la valeur d'une propriété d'un élément. * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *get_node_prop_value(xmlXPathContextPtr xpathCtx, const char *path, const char *name) { char *result; /* Valeur en question renvoyée */ xmlXPathObjectPtr xpathObj; /* Point de départ XML */ result = NULL; xpathObj = get_node_xpath_object(xpathCtx, path); if (xpathObj == NULL) return NULL; if (xpathObj->nodesetval->nodeNr > 0) result = qck_get_node_prop_value(xpathObj->nodesetval->nodeTab[0], name); xmlXPathFreeObject(xpathObj); return result; } /****************************************************************************** * * * Paramètres : node = noeud de texte avec un lien avec le document XML. * * * * Description : Construit un chemin d'accès complet selon le fichier XML. * * * * Retour : Valeur à libérer de la mémoire après usage ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *qck_build_filename_with_doc_url(xmlNodePtr node) { char *result; /* Construction à retourner */ char *text; /* Valeur du texte lu */ char *last; /* Point de remplacement */ result = NULL; text = qck_get_node_text_value(node); if (text != NULL) { result = (char *)calloc(xmlStrlen(node->doc->URL) + strlen(text) + 1, sizeof(char)); strcpy(result, (const char *)node->doc->URL); last = strrchr(result, '/'); last++; strcpy(last, text); free(text); } return result; } /****************************************************************************** * * * Paramètres : xpathCtx = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud à traiter. * * * * Description : Construit un chemin d'accès complet selon le fichier XML. * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *build_filename_with_doc_url(xmlXPathContextPtr xpathCtx, const char *path) { char *result; /* Valeur en question renvoyée */ xmlXPathObjectPtr xpathObj; /* Point de départ XML */ result = NULL; xpathObj = get_node_xpath_object(xpathCtx, path); if (xpathObj == NULL) return NULL; if (xpathObj->nodesetval->nodeNr > 0) result = qck_build_filename_with_doc_url(xpathObj->nodesetval->nodeTab[0]); xmlXPathFreeObject(xpathObj); return result; } /* ---------------------------------------------------------------------------------- */ /* OPERATIONS D'ECRITURE D'UN FICHIER XML */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : filename = nom du fichier à ouvrir. * * * * Description : Amorce l'écriture d'un nouveau fichier XML. * * * * Retour : Rédacteur mis en place ou NULL en cas d'erreur. * * * * Remarques : - * * * ******************************************************************************/ xmlTextWriterPtr start_writing_xml_file(const char *filename) { xmlTextWriterPtr result; /* Moyen à retourner */ int retval; /* Bilan d'une opération */ result = xmlNewTextWriterFilename(filename, 0); if (result == NULL) { XML_LOG(stderr, "Error creating the xml writer\n"); return NULL; } retval = xmlTextWriterStartDocument(result, NULL, "UTF-8", "yes"); if (retval < 0) { XML_LOG(stderr, "Error at xmlTextWriterStartDocument\n"); xmlFreeTextWriter(result); return NULL; } retval = xmlTextWriterSetIndent(result, 1); if (retval < 0) { XML_LOG(stderr, "Error setting indentation\n"); xmlFreeTextWriter(result); return NULL; } retval = xmlTextWriterSetIndentString(result, BAD_CAST "\t"); if (retval < 0) { XML_LOG(stderr, "Error setting indentation string\n"); xmlFreeTextWriter(result); return NULL; } return result; } /****************************************************************************** * * * Paramètres : writer = rédacteur dédié à l'écriture. * * * * Description : Met fin à l'écriture d'un nouveau fichier XML. * * * * Retour : Bilan de l'opération : true ou false. * * * * Remarques : Ferme au besoin toutes les balises encore ouvertes. * * * ******************************************************************************/ bool end_writing_xml_file(xmlTextWriterPtr writer) { int retval; /* Bilan de l'opération */ retval = xmlTextWriterEndDocument(writer); if (retval < 0) { XML_LOG(stderr, "Error at xmlTextWriterEndDocument\n"); return false; } xmlFreeTextWriter(writer); return true; } /****************************************************************************** * * * Paramètres : writer = rédacteur dédié à l'écriture. * * name = nom de la balise à écrire. * * * * Description : Ecrit une balise et ne la referme pas. * * * * Retour : Bilan de l'opération : true ou false. * * * * Remarques : - * * * ******************************************************************************/ bool open_xml_element(xmlTextWriterPtr writer, const char *name) { int retval; /* Bilan de l'opération */ retval = xmlTextWriterStartElement(writer, BAD_CAST name); if (retval < 0) XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n"); return (retval >= 0); } /****************************************************************************** * * * Paramètres : writer = rédacteur dédié à l'écriture. * * * * Description : Ferme la dernière balise laissée ouverte. * * * * Retour : Bilan de l'opération : true ou false. * * * * Remarques : - * * * ******************************************************************************/ bool close_xml_element(xmlTextWriterPtr writer) { int retval; /* Bilan de l'opération */ retval = xmlTextWriterEndElement(writer); if (retval < 0) XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n"); return (retval >= 0); } /****************************************************************************** * * * Paramètres : writer = rédacteur dédié à l'écriture. * * name = nom de la balise à écrire. * * format = format de la chaîne à traiter. * * ... = informations à inscrire. * * * * Description : Ecrit une balise avec un contenu textuel. * * * * Retour : Bilan de l'opération : true ou false. * * * * Remarques : - * * * ******************************************************************************/ bool write_xml_element_with_content(xmlTextWriterPtr writer, const char *name, const char *format, ...) { va_list ap; /* Liste d'arguments variable */ int retval; /* Bilan de l'opération */ va_start(ap, format); retval = xmlTextWriterWriteVFormatElement(writer, BAD_CAST name, format, ap); if (retval < 0) XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n"); va_end(ap); return (retval >= 0); } /****************************************************************************** * * * Paramètres : writer = rédacteur dédié à l'écriture. * * name = nom de l'attribut à écrire. * * format = format de la chaîne à traiter. * * ... = informations à inscrire. * * * * Description : Ecrit un attribut avec un contenu textuel. * * * * Retour : Bilan de l'opération : true ou false. * * * * Remarques : - * * * ******************************************************************************/ bool write_xml_attribute(xmlTextWriterPtr writer, const char *name, const char *format, ...) { va_list ap; /* Liste d'arguments variable */ int retval; /* Bilan de l'opération */ va_start(ap, format); retval = xmlTextWriterWriteVFormatAttribute(writer, BAD_CAST name, format, ap); if (retval < 0) XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n"); va_end(ap); return (retval >= 0); } /****************************************************************************** * * * Paramètres : writer = rédacteur dédié à l'écriture. * * format = format de la chaîne à traiter. * * ... = informations à inscrire. * * * * Description : Ecrit un contenu textuel. * * * * Retour : Bilan de l'opération : true ou false. * * * * Remarques : - * * * ******************************************************************************/ bool write_xml_content(xmlTextWriterPtr writer, const char *format, ...) { va_list ap; /* Liste d'arguments variable */ int retval; /* Bilan de l'opération */ va_start(ap, format); retval = xmlTextWriterWriteVFormatString(writer, format, ap); if (retval < 0) XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n"); va_end(ap); return (retval >= 0); }