/* Firebox Tools - Outils de configurations pour le WM Firebox * xml.c - lecture ou écriture de documents XML * * Copyright (C) 2009-2019 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 #include #include #include #include #include #include "cpp.h" #include "extstr.h" #include "pathname.h" #ifdef DEBUG # define XML_LOG fprintf #else # define XML_LOG if (FALSE) fprintf #endif /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. [OUT] * * context = contexte à utiliser pour les recherches. [OUT] * * * * Description : Crée un nouveau fichier XML. * * * * Retour : true si l'opération a pu s'effectuer, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool create_new_xml_file(xmlDocPtr *xdoc, xmlXPathContextPtr *context) { *xdoc = xmlNewDoc(BAD_CAST "1.0"); if (*xdoc == NULL) return false; *context = xmlXPathNewContext(*xdoc); if (*context == NULL) { xmlFreeDoc(*xdoc); return false; } return true; } /****************************************************************************** * * * Paramètres : content = données XML présentes en mémoire et à charge. * * length = quantité de ces données. * * xdoc = structure XML chargée. [OUT] * * context = contexte à utiliser pour les recherches. [OUT] * * * * Description : Charge un document XML entièrement en mémoire. * * * * Retour : true si l'opération a pu s'effectuer, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool load_xml_from_memory(const char *content, size_t length, xmlDocPtr *xdoc, xmlXPathContextPtr *context) { *xdoc = xmlReadMemory(content, length, "noname.xml", NULL, 0); if (*xdoc == NULL) return false; *context = xmlXPathNewContext(*xdoc); if (*context == NULL) { xmlFreeDoc(*xdoc); return false; } return true; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * filename = nom du fichier à remplir. * * * * Description : Sauvegarde une structure XML dans un fichier. * * * * Retour : true si l'opération a pu s'effectuer, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool save_xml_file(xmlDocPtr xdoc, const char *filename) { bool result; /* Bilan à retourner */ int ret; /* Bilan de l'appel */ /** * Le parti est pris de ne pas enregistrer de document vide ! */ if (xmlDocGetRootElement(xdoc) == NULL) { ret = unlink(filename); result = (ret == 0); } else { result = mkpath(filename); if (!result) goto exit; ret = xmlSaveFormatFileEnc(filename, xdoc, "UTF-8", 1); result = (ret != -1); } exit: return result; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée à supprimer. * * context = contexte utilisé pour les recherches. * * * * Description : Ferme une structure XML. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void close_xml_file(xmlDocPtr xdoc, xmlXPathContextPtr context) { xmlXPathFreeContext(context); xmlFreeDoc(xdoc); xmlCleanupParser(); } /* ---------------------------------------------------------------------------------- */ /* OPERATIONS DE LECTURE D'UN FICHIER XML */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : filename = nom du fichier à ouvrir. * * xdoc = structure XML chargée. [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, xmlXPathContextPtr *xpathCtx) { /** * On s'autorise à récupérer des erreurs de fichier vide, ie ne contenant que : * * * * On espère que la récupération d'autres situations d'erreurs est bien gérée. */ *xdoc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER); if (*xdoc == NULL) { XML_LOG(stderr, "Can not parse the XML file '%s'\n", filename); 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 le nom de balise d'un noeud donné. * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *qck_get_node_name(xmlNodePtr node) { char *result; /* Valeur en question renvoyée */ result = NULL; if (node != NULL) result = strdup((const char *)node->name); return result; } /****************************************************************************** * * * Paramètres : xpathCtx = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * * * Description : Obtient le nom de balise d'un noeud donné. * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *get_node_name(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_name(xpathObj->nodesetval->nodeTab[0]); xmlXPathFreeObject(xpathObj); 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); /** * Si le noeud existe mais qu'il n'y pas de contenu, * il faut marquer la différence entre deux retours NULL. * * On choisit donc : * - NULL : pas de valeur trouvée car noeud non existant. * - "" : pas de valeur trouvée, mais noeud bien présent. */ if (result == NULL) result = strdup(""); } 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 : node = noeud dont une propriété est à lire. * * name = nom de la propriété à lire. * * out = valeur entière lue depuis le contenu textuel. [OUT] * * * * Description : Obtient la valeur entière d'une propriété d'un élément. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool qck_get_node_prop_long_value(xmlNodePtr node, const char *name, long *out) { bool result; /* Bilan à retourner */ char *value; /* Valeur brute lue */ value = qck_get_node_prop_value(node, name); if (value) { result = true; *out = strtol(value, NULL, 10); free(value); } else result = false; return result; } /****************************************************************************** * * * Paramètres : node = noeud dont une propriété est à lire. * * name = nom de la propriété à lire. * * out = valeur entière lue depuis le contenu textuel. [OUT] * * * * Description : Obtient la valeur entière d'une propriété d'un élément. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool qck_get_node_prop_uint64_value(xmlNodePtr node, const char *name, uint64_t *out) { bool result; /* Bilan à retourner */ char *value; /* Valeur brute lue */ value = qck_get_node_prop_value(node, name); if (value) { result = true; *out = strtoull(value, NULL, 10); free(value); } else result = false; 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 : xpathCtx = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud à traiter. * * name = nom de la propriété à lire. * * out = valeur entière obtenue via contenu textuel. [OUT] * * * * Description : Obtient la valeur entière d'une propriété d'un élément. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool get_node_prop_long_value(xmlXPathContextPtr xpathCtx, const char *path, const char *name, long *out) { bool result; /* Bilan à retourner */ 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_long_value(xpathObj->nodesetval->nodeTab[0], name, out); xmlXPathFreeObject(xpathObj); 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. * * out = valeur entière obtenue via contenu textuel. [OUT] * * * * Description : Obtient la valeur entière d'une propriété d'un élément. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool get_node_prop_uint64_value(xmlXPathContextPtr xpathCtx, const char *path, const char *name, uint64_t *out) { bool result; /* Bilan à retourner */ 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_uint64_value(xpathObj->nodesetval->nodeTab[0], name, out); 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); } /* ---------------------------------------------------------------------------------- */ /* OPERATIONS D'ECRITURE D'UN FICHIER XML */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * * * Description : Fournit le premier noeud correspondant à un chemin XPath. * * * * Retour : Adresse du noeud trouvé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ xmlNodePtr get_node_from_xpath(xmlXPathContextPtr context, const char *path) { xmlNodePtr result; /* Noeud trouvé à renvoyer */ xmlXPathObjectPtr xobject; /* Point de départ XML */ result = NULL; xobject = get_node_xpath_object(context, path); if (xobject == NULL) return NULL; if (xobject->nodesetval->nodeNr > 0) result = xobject->nodesetval->nodeTab[0]; xmlXPathFreeObject(xobject); return result; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * name = nom du nouveau noeud à créer. * * * * Description : Ajoute un noeud à un autre noeud. * * * * Retour : Adresse du noeud mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ xmlNodePtr add_node_to_xpath(xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path, const char *name) { xmlNodePtr result; /* Noeud créé à retourner */ xmlNodePtr parent; /* Support du nouveau noeud */ parent = get_node_from_xpath(context, path); if (parent == NULL) return NULL; result = add_node_to_node(xdoc, parent, name); return result; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * parent = noeud parent de rattachement. * * name = nom du nouveau noeud à créer. * * * * Description : Ajoute un noeud à un autre noeud. * * * * Retour : Adresse du noeud mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ xmlNodePtr add_node_to_node(xmlDocPtr xdoc, xmlNodePtr parent, const char *name) { xmlNodePtr result; /* Noeud créé à retourner */ result = xmlNewDocNode(xdoc, NULL, BAD_CAST name, NULL); result = xmlAddChild(parent, result); return result; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * node = noeud à retirer de la structure. * * * * Description : Retire un noeud d'un document XML. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void _remove_node_from_doc(xmlDocPtr xdoc, xmlNodePtr node) { xmlUnlinkNode(node); xmlFreeNode(node); } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * * * Description : Retire un noeud d'un document XML. * * * * Retour : true si le noeud XML a bien été trouvé, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool remove_node_from_doc(xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path) { bool result; /* Bilan à retourner */ xmlNodePtr node; /* Noeud à considérer */ node = get_node_from_xpath(context, path); if (node != NULL) { _remove_node_from_doc(xdoc, node); result = true; } else result = false; return result; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * * * Description : S'assure qu'un noeud donné est bien présent dans le document.* * * * Retour : Noeud en question ou NULL en cas d'échec à la création. * * * * Remarques : - * * * ******************************************************************************/ xmlNodePtr ensure_node_exist(xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path) { xmlNodePtr result; /* Noeud à retourner */ char **levels; /* Niveaux dans le chemin */ size_t levels_count; /* Nombre de ces niveaux */ xmlNodePtr last; /* Dernier noeud valide */ size_t i; /* Boucle de parcours #1 */ char *iter_path; /* Chamin d'accès pour le test */ size_t j; /* Boucle de parcours #2 */ xmlNodePtr iter; /* Test d'accès à un noeud */ char *cond; /* Marque de condition ('[') */ result = get_node_from_xpath(context, path); if (result == NULL) { levels = strtoka(path, "/", &levels_count); /* Recherche la racine valide la plus haute */ last = xmlDocGetRootElement(xdoc); for (i = 0; i < levels_count && last != NULL; i++) { iter_path = strdup(""); for (j = 0; j <= i; j++) { iter_path = stradd(iter_path, "/"); iter_path = stradd(iter_path, levels[j]); } iter = get_node_from_xpath(context, iter_path); free(iter_path); if (iter == NULL) break; else last = iter; } /* Inscription des noeuds restants */ if (last == NULL) { last = xmlNewDocNode(xdoc, NULL, BAD_CAST levels[i++], NULL); xmlDocSetRootElement(xdoc, last); if (i == levels_count) result = last; } for ( ; i < levels_count && last != NULL; i++) { cond = strchr(levels[i], '['); if (cond != NULL) *cond = '\0'; result = xmlNewDocNode(xdoc, NULL, BAD_CAST levels[i], NULL); result = xmlAddChild(last, result); last = result; } /* Libération de la mémoire */ for (i = 0; i < levels_count; i++) free(levels[i]); free(levels); } return result; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * content = texte à inscrire en contenu. * * * * Description : S'assure qu'un noeud donné est bien présent dans le document.* * * * Retour : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool add_content_to_node(xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path, const char *content) { xmlNodePtr node; /* Noeud à modifier */ if (content == NULL) return true; node = ensure_node_exist(xdoc, context, path); if (node == NULL) return false; xmlNodeSetContent(node, BAD_CAST content); return true; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * value = nombre à inscrire en contenu. * * * * Description : Ajoute un noeud avec contenu numérique au document. * * * * Retour : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool add_uint_content_to_node(xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path, unsigned int value) { xmlNodePtr node; /* Noeud à modifier */ char content[sizeof(XSTR(UINT_MAX)) + 1];/* Valeur en chaîne */ if (content == NULL) return true; node = ensure_node_exist(xdoc, context, path); if (node == NULL) return false; sprintf(content, "%u", value); xmlNodeSetContent(node, BAD_CAST content); return true; } /****************************************************************************** * * * Paramètres : node = noeud dont le contenu est à mettre à jour. * * name = nom de la propriété à créer. * * value = chaîne de caractère à placer. * * * * Description : Ajoute une propriété à un noeud existant donné. * * * * Retour : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool _add_string_attribute_to_node(xmlNodePtr node, const char *name, const char *value) { xmlAttrPtr attrib; /* Attribut créé et en place */ attrib = xmlSetProp(node, BAD_CAST name, BAD_CAST value); return (attrib != NULL); } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * name = nom de la propriété à créer. * * value = chaîne de caractère à placer. * * * * Description : Ajoute une propriété à un noeud existant donné. * * * * Retour : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool add_string_attribute_to_node(xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path, const char *name, const char *value) { xmlNodePtr node; /* Noeud à modifier */ if (value == NULL) return true; node = ensure_node_exist(xdoc, context, path); if (node == NULL) return false; return _add_string_attribute_to_node(node, name, value); } /****************************************************************************** * * * Paramètres : node = noeud dont le contenu est à mettre à jour. * * name = nom de la propriété à créer. * * value = valeur numérique à placer. * * * * Description : Ajoute une propriété à un noeud existant donné. * * * * Retour : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool _add_long_attribute_to_node(xmlNodePtr node, const char *name, long value) { char tmp[11/*strlen("2147483647")*/]; /* Stockage temporaire */ snprintf(tmp, 11, "%ld", value); return _add_string_attribute_to_node(node, name, tmp); } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * name = nom de la propriété à créer. * * value = valeur numérique à placer. * * * * Description : Ajoute une propriété à un noeud existant donné. * * * * Retour : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool add_long_attribute_to_node(xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path, const char *name, long value) { xmlNodePtr node; /* Noeud à modifier */ node = ensure_node_exist(xdoc, context, path); if (node == NULL) return false; return _add_long_attribute_to_node(node, name, value); } /****************************************************************************** * * * Paramètres : node = noeud dont le contenu est à mettre à jour. * * name = nom de la propriété à créer. * * value = valeur numérique à placer. * * * * Description : Ajoute une propriété à un noeud existant donné. * * * * Retour : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool _add_uint64_attribute_to_node(xmlNodePtr node, const char *name, uint64_t value) { bool result; /* Bilan à retourner */ char *tmp; /* Stockage temporaire */ int ret; /* Bilan de l'impression */ ret = asprintf(&tmp, "%" PRIu64, value); if (ret == -1) result = false; else { result = _add_string_attribute_to_node(node, name, tmp); free(tmp); } return result; } /****************************************************************************** * * * Paramètres : xdoc = structure XML chargée. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès au noeud visé. * * name = nom de la propriété à créer. * * value = valeur numérique à placer. * * * * Description : Ajoute une propriété à un noeud existant donné. * * * * Retour : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool add_uint64_attribute_to_node(xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path, const char *name, uint64_t value) { xmlNodePtr node; /* Noeud à modifier */ node = ensure_node_exist(xdoc, context, path); if (node == NULL) return false; return _add_uint64_attribute_to_node(node, name, value); }