You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
heartbeat/include/crm/common/xml.h

324 lines
9.3 KiB

/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program 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.1 of the License, or (at your option) any later version.
*
* This software 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CRM_COMMON_XML__H
#define CRM_COMMON_XML__H
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <ha_msg.h>
#include <clplumbing/cl_log.h>
/* #define USE_LIBXML 1 */
#if CRM_DEV_BUILD
# define XML_PARANOIA_CHECKS 1
#else
# define XML_PARANOIA_CHECKS 0
#endif
#ifdef USE_LIBXML
# include <libxml/tree.h>
typedef xmlNode crm_data_t;
#else
typedef struct ha_msg crm_data_t;
#endif
extern gboolean add_message_xml(
HA_Message *msg, const char *field, const crm_data_t *xml);
extern crm_data_t *get_message_xml(HA_Message *msg, const char *field);
extern GHashTable *xml2list(crm_data_t *parent);
#if CRM_DEPRECATED_SINCE_2_0_3
extern GHashTable *xml2list_202(crm_data_t *parent);
#endif
extern void hash2nvpair(gpointer key, gpointer value, gpointer user_data);
extern void hash2field(gpointer key, gpointer value, gpointer user_data);
extern void hash2metafield(gpointer key, gpointer value, gpointer user_data);
extern gboolean do_id_check(crm_data_t *xml_obj, GHashTable *id_hash,
gboolean silent_add, gboolean silent_rename);
/*
* Replacement function for xmlCopyPropList which at the very least,
* doesnt work the way *I* would expect it to.
*
* Copy all the attributes/properties from src into target.
*
* Not recursive, does not return anything.
*
*/
extern void copy_in_properties(crm_data_t *target, const crm_data_t *src);
/*
* Find a child named search_path[i] at level i in the XML fragment where i=0
* is an immediate child of <i>root</i>.
*
* Terminate with success if i == len, or search_path[i] == NULL.
*
* On success, returns the sub-fragment described by search_path.
* On failure, returns NULL.
*/
extern crm_data_t *find_xml_node_nested(
crm_data_t *root, const char **search_path, int len);
/*
* Find a child named search_path[i] at level i in the XML fragment where i=0
* is an immediate child of <i>root</i>.
*
* Once the last child specified by node_path is found, find the value
* of attr_name.
*
* If <i>error<i> is set to TRUE, then it is an error for the attribute not
* to be found and the function will log accordingly.
*
* On success, returns the value of attr_name.
* On failure, returns NULL.
*/
extern const char *get_xml_attr_nested(crm_data_t *parent,
const char **node_path, int length,
const char *attr_name, gboolean error);
#define free_xml(a_node) do { \
if(a_node != NULL) { \
crm_validate_data(a_node); \
ha_msg_del(a_node); \
} \
} while(0)
void free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node);
#define zap_xml_from_parent(parent, xml_obj) free_xml_from_parent(parent, xml_obj); xml_obj = NULL
/*
* Create a node named "name" as a child of "parent"
* If parent is NULL, creates an unconnected node.
*
* Returns the created node
*
*/
extern crm_data_t *create_xml_node(crm_data_t *parent, const char *name);
/*
* Make a copy of name and value and use the copied memory to create
* an attribute for node.
*
* If node, name or value are NULL, nothing is done.
*
* If name or value are an empty string, nothing is done.
*
* Returns FALSE on failure and TRUE on success.
*
*/
extern const char *crm_xml_add(
crm_data_t *node, const char *name, const char *value);
extern const char *crm_xml_add_int(
crm_data_t* node, const char *name, int value);
/*
* Unlink the node and set its doc pointer to NULL so free_xml()
* will act appropriately
*/
extern void unlink_xml_node(crm_data_t *node);
/*
* Set a timestamp attribute on a_node
*/
extern void add_xml_tstamp(crm_data_t *a_node);
/*
*
*/
extern void purge_diff_markers(crm_data_t *a_node);
/*
* Returns a deep copy of src_node
*
*/
extern crm_data_t *copy_xml(const crm_data_t *src_node);
/*
* Add a copy of xml_node to new_parent
*/
extern crm_data_t *add_node_copy(
crm_data_t *new_parent, const crm_data_t *xml_node);
extern int add_node_nocopy(crm_data_t *parent, const char *name, crm_data_t *child);
/*
* XML I/O Functions
*
* Whitespace between tags is discarded.
*/
extern crm_data_t *file2xml(FILE *input, gboolean compressed);
extern crm_data_t *stdin2xml(void);
extern crm_data_t *string2xml(const char *input);
extern int write_xml_file(
crm_data_t *xml_node, const char *filename, gboolean compress);
extern char *dump_xml_formatted(const crm_data_t *msg);
extern char *dump_xml_unformatted(const crm_data_t *msg);
extern void print_xml_formatted(
int log_level, const char *function,
const crm_data_t *an_xml_node, const char *text);
/*
* Diff related Functions
*/
extern crm_data_t *diff_xml_object(
crm_data_t *left, crm_data_t *right, gboolean suppress);
extern void log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function);
extern gboolean apply_xml_diff(
crm_data_t *old, crm_data_t *diff, crm_data_t **new);
/*
* Searching & Modifying
*/
extern crm_data_t *find_xml_node(
crm_data_t *cib, const char * node_path, gboolean must_find);
extern crm_data_t *find_entity(
crm_data_t *parent, const char *node_name, const char *id);
extern crm_data_t *subtract_xml_object(
crm_data_t *left, crm_data_t *right, const char *marker);
extern int add_xml_object(
crm_data_t *parent, crm_data_t *target, const crm_data_t *update);
extern void xml_remove_prop(crm_data_t *obj, const char *name);
extern gboolean replace_xml_child(
crm_data_t *parent, crm_data_t *child, crm_data_t *update, gboolean delete_only);
extern gboolean update_xml_child(crm_data_t *child, crm_data_t *to_update);
extern int find_xml_children(
crm_data_t **children, crm_data_t *root,
const char *tag, const char *field, const char *value,
gboolean search_matches);
/*
*
*/
extern const char *crm_element_value(const crm_data_t *data, const char *name);
extern char *crm_element_value_copy(const crm_data_t *data, const char *name);
extern const char *crm_element_name(const crm_data_t *data);
extern void xml_validate(const crm_data_t *root);
extern gboolean xml_has_children(const crm_data_t *root);
extern char *calculate_xml_digest(crm_data_t *local_cib, gboolean sort, gboolean do_filter);
extern gboolean validate_with_dtd(
crm_data_t *xml_blob, gboolean to_logs, const char *dtd_file);
#if XML_PARANOIA_CHECKS
# define crm_validate_data(obj) xml_validate(obj)
#else
# define crm_validate_data(obj) CRM_DEV_ASSERT(obj != NULL)
#endif
#define xml_child_iter(parent, child, loop_code) \
if(parent != NULL) { \
int __counter = 0; \
crm_data_t *child = NULL; \
crm_validate_data(parent); \
for (__counter = 0; __counter < parent->nfields; __counter++) { \
if(parent->types[__counter] != FT_STRUCT \
&& parent->types[__counter] != FT_UNCOMPRESS) { \
continue; \
} \
child = parent->values[__counter]; \
if(child == NULL) { \
crm_debug_4("Skipping %s == NULL", \
parent->names[__counter]); \
} else { \
loop_code; \
} \
} \
} else { \
crm_debug_4("Parent of loop was NULL"); \
}
#define xml_child_iter_filter(parent, child, filter, loop_code) \
if(parent != NULL) { \
int __counter = 0; \
crm_data_t *child = NULL; \
crm_validate_data(parent); \
for (__counter = 0; __counter < parent->nfields; __counter++) { \
if(parent->types[__counter] != FT_STRUCT \
&& parent->types[__counter] != FT_UNCOMPRESS) { \
continue; \
} \
child = parent->values[__counter]; \
if(child == NULL) { \
crm_debug_4("Skipping %s == NULL", \
parent->names[__counter]); \
} else if(filter == NULL/*constant condition*/ \
|| safe_str_eq(filter, parent->names[__counter])) { \
loop_code; \
} else { \
crm_debug_4("Skipping <%s../>", \
parent->names[__counter]); \
} \
} \
} else { \
crm_debug_4("Parent of loop was NULL"); \
}
#define xml_prop_iter(parent, prop_name, prop_value, code) if(parent != NULL) { \
const char *prop_name = NULL; \
const char *prop_value = NULL; \
int __counter = 0; \
crm_validate_data(parent); \
crm_debug_5("Searching %d fields", parent->nfields); \
for (__counter = 0; __counter < parent->nfields; __counter++) { \
crm_debug_5("Searching field %d", __counter); \
prop_name = parent->names[__counter]; \
if(parent->types[__counter] != FT_STRING) { \
continue; \
} else if(prop_name[0] == '_' \
&& prop_name[1] == '_') { \
continue; \
} \
prop_value = parent->values[__counter]; \
code; \
} \
} else { \
crm_debug_4("Parent of loop was NULL"); \
}
#endif