/* * libvirt-gconfig-object.c: base object for XML configuration * * Copyright (C) 2008 Daniel P. Berrange * Copyright (C) 2010-2011 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . * * Author: Daniel P. Berrange */ #include #include #include #include #include "libvirt-gconfig/libvirt-gconfig.h" #include "libvirt-gconfig/libvirt-gconfig-private.h" #define GVIR_CONFIG_OBJECT_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_CONFIG_TYPE_OBJECT, GVirConfigObjectPrivate)) struct _GVirConfigObjectPrivate { gchar *schema; GVirConfigXmlDoc *doc; xmlNodePtr node; }; G_DEFINE_TYPE_WITH_PRIVATE(GVirConfigObject, gvir_config_object, G_TYPE_OBJECT); enum { PROP_0, PROP_SCHEMA, PROP_NODE, PROP_DOC }; static void gvir_xml_generic_error_nop(void *userData G_GNUC_UNUSED, const char *msg G_GNUC_UNUSED, ...) { } static void gvir_xml_structured_error_nop(void *userData G_GNUC_UNUSED, xmlErrorPtr error G_GNUC_UNUSED) { } static void gvir_config_object_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GVirConfigObject *obj = GVIR_CONFIG_OBJECT(object); GVirConfigObjectPrivate *priv = obj->priv; switch (prop_id) { case PROP_SCHEMA: g_value_set_string(value, priv->schema); break; case PROP_NODE: g_value_set_pointer(value, gvir_config_object_get_xml_node(obj)); break; case PROP_DOC: g_value_set_object(value, obj->priv->doc); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } } static void gvir_config_object_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GVirConfigObject *obj = GVIR_CONFIG_OBJECT(object); GVirConfigObjectPrivate *priv = obj->priv; switch (prop_id) { case PROP_SCHEMA: g_free(priv->schema); priv->schema = g_value_dup_string(value); break; case PROP_NODE: priv->node =g_value_get_pointer(value); break; case PROP_DOC: obj->priv->doc = g_value_dup_object(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } } static void gvir_config_object_finalize(GObject *object) { GVirConfigObject *gvir_object = GVIR_CONFIG_OBJECT(object); GVirConfigObjectPrivate *priv = gvir_object->priv; g_free(priv->schema); if (priv->doc != NULL) { g_object_unref(G_OBJECT(priv->doc)); priv->node = NULL; /* node belongs to doc, make sure not to free it */ } if (priv->node != NULL) { g_assert(priv->node->doc == NULL); xmlFreeNode(priv->node); } G_OBJECT_CLASS(gvir_config_object_parent_class)->finalize(object); } static void gvir_config_object_class_init(GVirConfigObjectClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->finalize = gvir_config_object_finalize; object_class->get_property = gvir_config_object_get_property; object_class->set_property = gvir_config_object_set_property; g_object_class_install_property(object_class, PROP_SCHEMA, g_param_spec_string("schema", "Schema", "The doc RNG schema", NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, PROP_NODE, g_param_spec_pointer("node", "XML Node", "The XML node this config object corresponds to", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, PROP_DOC, g_param_spec_object("doc", "XML Doc", "The XML doc this config object corresponds to", GVIR_CONFIG_TYPE_XML_DOC, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } static void gvir_config_object_init(GVirConfigObject *object) { object->priv = GVIR_CONFIG_OBJECT_GET_PRIVATE(object); } void gvir_config_object_validate(GVirConfigObject *config, GError **err) { GVirConfigObjectPrivate *priv; xmlRelaxNGParserCtxtPtr rngParser = NULL; xmlRelaxNGPtr rng = NULL; xmlRelaxNGValidCtxtPtr rngValid = NULL; g_return_if_fail(GVIR_CONFIG_IS_OBJECT(config)); g_return_if_fail(err == NULL || *err == NULL); priv = config->priv; xmlSetGenericErrorFunc(NULL, gvir_xml_generic_error_nop); xmlSetStructuredErrorFunc(NULL, gvir_xml_structured_error_nop); if (!priv->node) { gvir_config_set_error_literal(err, GVIR_CONFIG_OBJECT_ERROR, 0, _("No XML document associated with this config object")); return; } if (!priv->schema) { gvir_config_set_error_literal(err, GVIR_CONFIG_OBJECT_ERROR, 0, _("No XML schema associated with this config object")); return; } rngParser = xmlRelaxNGNewParserCtxt(priv->schema); if (!rngParser) { gvir_config_set_error(err, GVIR_CONFIG_OBJECT_ERROR, 0, _("Unable to create RNG parser for %s"), priv->schema); return; } rng = xmlRelaxNGParse(rngParser); if (!rng) { gvir_config_set_error(err, GVIR_CONFIG_OBJECT_ERROR, 0, _("Unable to parse RNG %s"), priv->schema); xmlRelaxNGFreeParserCtxt(rngParser); return; } xmlRelaxNGFreeParserCtxt(rngParser); rngValid = xmlRelaxNGNewValidCtxt(rng); if (!rngValid) { gvir_config_set_error(err, GVIR_CONFIG_OBJECT_ERROR, 0, _("Unable to create RNG validation context %s"), priv->schema); xmlRelaxNGFree(rng); return; } if (xmlRelaxNGValidateDoc(rngValid, priv->node->doc) != 0) { gvir_config_set_error_literal(err, GVIR_CONFIG_OBJECT_ERROR, 0, _("Unable to validate doc")); xmlRelaxNGFreeValidCtxt(rngValid); xmlRelaxNGFree(rng); return; } xmlRelaxNGFreeValidCtxt(rngValid); xmlRelaxNGFree(rng); } gchar *gvir_config_object_to_xml(GVirConfigObject *config) { g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(config), NULL); return gvir_config_xml_node_to_string(config->priv->node); } const gchar *gvir_config_object_get_schema(GVirConfigObject *config) { g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(config), NULL); return config->priv->schema; } G_GNUC_INTERNAL GVirConfigXmlDoc * gvir_config_object_get_xml_doc(GVirConfigObject *config) { return config->priv->doc; } /* FIXME: will we always have one xmlNode per GConfig object? */ /* FIXME: need to return the right node from subclasses */ /* NB: the xmlNodePtr must not be freed by the caller */ G_GNUC_INTERNAL xmlNodePtr gvir_config_object_get_xml_node(GVirConfigObject *config) { return config->priv->node; } G_GNUC_INTERNAL const char * gvir_config_object_get_node_content(GVirConfigObject *object, const char *node_name) { xmlNodePtr node; node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object)); if (node == NULL) return NULL; return gvir_config_xml_get_child_element_content(node, node_name); } G_GNUC_INTERNAL const char * gvir_config_object_get_attribute(GVirConfigObject *object, const char *node_name, const char *attr_name) { xmlNodePtr node; g_return_val_if_fail(attr_name != NULL, NULL); node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object)); if (node == NULL) return NULL; if (node_name != NULL) { node = gvir_config_xml_get_element(node, node_name, NULL); if (node == NULL) return NULL; } return gvir_config_xml_get_attribute_content(node, attr_name); } static xmlNodePtr gvir_config_object_set_child_internal(GVirConfigObject *object, xmlNodePtr child, gboolean overwrite) { xmlNodePtr parent_node; xmlNodePtr old_node; parent_node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object)); g_return_val_if_fail (parent_node != NULL, NULL); old_node = gvir_config_xml_get_element(parent_node, child->name, NULL); /* FIXME: should we make sure there are no multiple occurrences * of this node? */ if (old_node) { if (overwrite) { old_node = xmlReplaceNode(old_node, child); xmlFreeNode(old_node); } else { return old_node; } } else { xmlAddChild(parent_node, child); } return NULL; } G_GNUC_INTERNAL void gvir_config_object_set_child(GVirConfigObject *object, xmlNodePtr child) { gvir_config_object_set_child_internal(object, child, TRUE); } G_GNUC_INTERNAL void gvir_config_object_foreach_child(GVirConfigObject *object, const char *parent_name, GVirConfigXmlNodeIterator iter_func, gpointer opaque) { xmlNodePtr root_node; xmlNodePtr node; g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object)); root_node = gvir_config_object_get_xml_node(object); g_return_if_fail(root_node != NULL); node = gvir_config_xml_get_element(root_node, parent_name, NULL); if (node == NULL) return; gvir_config_xml_foreach_child(node, iter_func, opaque); } G_GNUC_INTERNAL GVirConfigObject * gvir_config_object_add_child(GVirConfigObject *object, const char *child_name) { xmlNodePtr new_node; xmlNodePtr old_node; g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL); g_return_val_if_fail(child_name != NULL, NULL); new_node = xmlNewDocNode(NULL, NULL, (xmlChar *)child_name, NULL); old_node = gvir_config_object_set_child_internal(object, new_node, FALSE); if (old_node != NULL) { xmlFreeNode(new_node); return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT, "doc", object->priv->doc, "node", old_node, NULL)); } return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT, "doc", object->priv->doc, "node", new_node, NULL)); } G_GNUC_INTERNAL void gvir_config_object_add_child_with_attribute(GVirConfigObject *object, const char *child_name, const char *attr_name, const char *attr_value) { GVirConfigObject *child; child = gvir_config_object_add_child(object, child_name); gvir_config_object_set_attribute(child, attr_name, attr_value, NULL); g_object_unref(G_OBJECT(child)); } void gvir_config_object_add_child_with_attribute_enum(GVirConfigObject *object, const char *child_name, const char *attr_name, GType attr_type, unsigned int attr_value) { GVirConfigObject *child; child = gvir_config_object_add_child(object, child_name); gvir_config_object_set_attribute_with_type(child, attr_name, attr_type, attr_value, NULL); g_object_unref(G_OBJECT(child)); } G_GNUC_INTERNAL GVirConfigObject * gvir_config_object_replace_child(GVirConfigObject *object, const char *child_name) { xmlNodePtr new_node; g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL); g_return_val_if_fail(child_name != NULL, NULL); new_node = xmlNewDocNode(NULL, NULL, (xmlChar *)child_name, NULL); gvir_config_object_set_child_internal(object, new_node, TRUE); return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT, "doc", object->priv->doc, "node", new_node, NULL)); } G_GNUC_INTERNAL void gvir_config_object_replace_child_with_attribute(GVirConfigObject *object, const char *child_name, const char *attr_name, const char *attr_value) { GVirConfigObject *child; child = gvir_config_object_replace_child(object, child_name); gvir_config_object_set_attribute(child, attr_name, attr_value, NULL); g_object_unref(G_OBJECT(child)); } G_GNUC_INTERNAL void gvir_config_object_replace_child_with_attribute_enum(GVirConfigObject *object, const char *child_name, const char *attr_name, GType attr_type, unsigned int attr_value) { GVirConfigObject *child; child = gvir_config_object_replace_child(object, child_name); gvir_config_object_set_attribute_with_type(child, attr_name, attr_type, attr_value, NULL); g_object_unref(G_OBJECT(child)); } struct NodeMatch { const char *name; const char *ns; }; static gboolean maybe_unlink_node(xmlNodePtr node, void *opaque) { gboolean dounlink = TRUE; struct NodeMatch *match = (struct NodeMatch *)opaque; if (match->ns != NULL) { dounlink = dounlink && (g_strcmp0(match->ns, (char *)node->ns->href) == 0); } if (match->name != NULL) { dounlink = dounlink && (g_strcmp0(match->name, (char *)node->name) == 0); } if (dounlink) { xmlUnlinkNode(node); xmlFreeNode(node); } return dounlink; } static gboolean remove_oneshot(xmlNodePtr node, gpointer opaque) { return !maybe_unlink_node(node, opaque); } G_GNUC_INTERNAL void gvir_config_object_delete_child(GVirConfigObject *object, const char *child_name, const char *ns_href) { struct NodeMatch match; g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object)); match.name = child_name; match.ns = ns_href; gvir_config_object_foreach_child(object, NULL, remove_oneshot, &match); } static gboolean remove_always(xmlNodePtr node, gpointer opaque) { maybe_unlink_node(node, opaque); return TRUE; } G_GNUC_INTERNAL void gvir_config_object_delete_children(GVirConfigObject *object, const char *child_name, const char *ns_href) { struct NodeMatch match; g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object)); match.name = child_name; match.ns = ns_href; gvir_config_object_foreach_child(object, NULL, remove_always, &match); } G_GNUC_INTERNAL void gvir_config_object_set_node_content(GVirConfigObject *object, const char *node_name, const char *value) { xmlChar *encoded_data; GVirConfigObject *node; g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object)); if (value == NULL) { gvir_config_object_delete_child(object, node_name, NULL); return; } if (node_name != NULL) { node = gvir_config_object_replace_child(object, node_name); g_return_if_fail(node != NULL); } else { node = g_object_ref(object); } encoded_data = xmlEncodeEntitiesReentrant(node->priv->node->doc, (xmlChar *)value); xmlNodeSetContent(node->priv->node, encoded_data); xmlFree(encoded_data); g_object_unref(G_OBJECT(node)); } G_GNUC_INTERNAL void gvir_config_object_set_node_content_uint64(GVirConfigObject *object, const char *node_name, guint64 value) { char *str; g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object)); str = g_strdup_printf("%"G_GUINT64_FORMAT, value); gvir_config_object_set_node_content(object, node_name, str); g_free(str); } /* FIXME: how to notify of errors/node not found? */ G_GNUC_INTERNAL guint64 gvir_config_object_get_node_content_uint64(GVirConfigObject *object, const char *node_name) { xmlNodePtr node; const char *str; guint64 value; node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object)); if (node == NULL) return 0; str = gvir_config_xml_get_child_element_content(node, node_name); if (!str) return 0; value = g_ascii_strtoull(str, NULL, 0); return value; } G_GNUC_INTERNAL gint gvir_config_object_get_node_content_genum(GVirConfigObject *object, const char *node_name, GType enum_type, gint default_value) { xmlNodePtr node; const char *str; gint value; node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object)); if (node == NULL) return default_value; str = gvir_config_xml_get_child_element_content(node, node_name); if (!str) return default_value; value = gvir_config_genum_get_value(enum_type, str, default_value); return value; } G_GNUC_INTERNAL gint gvir_config_object_get_attribute_genum(GVirConfigObject *object, const char *node_name, const char *attr_name, GType enum_type, gint default_value) { xmlNodePtr node; const char *attr_val; gint value; g_return_val_if_fail(attr_name != NULL, default_value); node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object)); if (node == NULL) return default_value; if (node_name != NULL) { node = gvir_config_xml_get_element(node, node_name, NULL); if (node == NULL) return default_value; } attr_val = gvir_config_xml_get_attribute_content(node, attr_name); if (attr_val == NULL) return default_value; value = gvir_config_genum_get_value(enum_type, attr_val, default_value); return value; } G_GNUC_INTERNAL guint64 gvir_config_object_get_attribute_uint64(GVirConfigObject *object, const char *node_name, const char *attr_name, guint64 default_value) { const char *str; str = gvir_config_object_get_attribute(object, node_name, attr_name); if (str == NULL) return default_value; return g_ascii_strtoull(str, NULL, 0); } G_GNUC_INTERNAL gboolean gvir_config_object_get_attribute_boolean(GVirConfigObject *object, const char *node_name, const char *attr_name, gboolean default_value) { const char *str; str = gvir_config_object_get_attribute(object, node_name, attr_name); if (g_strcmp0(str, "yes") == 0) { return TRUE; } else if (g_strcmp0(str, "no") == 0) { return FALSE; } else { return default_value; } } GVirConfigObject *gvir_config_object_new_from_xml(GType type, const char *root_name, const char *schema, const gchar *xml, GError **error) { GVirConfigObject *object; GVirConfigXmlDoc *doc; xmlNodePtr node; GError *tmp_error = NULL; node = gvir_config_xml_parse(xml, root_name, &tmp_error); if (tmp_error != NULL) { g_propagate_error(error, tmp_error); return NULL; } doc = gvir_config_xml_doc_new(node->doc); object = GVIR_CONFIG_OBJECT(g_object_new(type, "doc", doc, "node", node, "schema", schema, NULL)); g_object_unref(G_OBJECT(doc)); return object; } G_GNUC_INTERNAL GVirConfigObject * gvir_config_object_new_from_tree(GType type, GVirConfigXmlDoc *doc, const char *schema, xmlNodePtr tree) { g_return_val_if_fail(g_type_is_a(type, GVIR_CONFIG_TYPE_OBJECT), NULL); g_return_val_if_fail(GVIR_CONFIG_IS_XML_DOC(doc), NULL); g_return_val_if_fail(tree != NULL, NULL); return GVIR_CONFIG_OBJECT(g_object_new(type, "doc", doc, "node", tree, "schema", schema, NULL)); } GVirConfigObject *gvir_config_object_new(GType type, const char *root_name, const char *schema) { GVirConfigObject *object; GVirConfigXmlDoc *doc; xmlDocPtr xml_doc; xmlNodePtr node; doc = gvir_config_xml_doc_new(NULL); g_object_get(G_OBJECT(doc), "doc", &xml_doc, NULL); g_assert(xml_doc != NULL); node = xmlNewDocNode(xml_doc, NULL, (xmlChar *)root_name, NULL); xmlDocSetRootElement(xml_doc, node); object = GVIR_CONFIG_OBJECT(g_object_new(type, "doc", doc, "node", node, "schema", schema, NULL)); g_object_unref(G_OBJECT(doc)); return object; } G_GNUC_INTERNAL void gvir_config_object_set_attribute(GVirConfigObject *object, ...) { xmlDocPtr doc; va_list args; g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object)); g_object_get(G_OBJECT(object->priv->doc), "doc", &doc, NULL); va_start(args, object); while (TRUE) { const char *name; const char *value; name = va_arg(args, const char *); if (name == NULL) { break; } gvir_config_object_remove_attribute(object, name); value = va_arg(args, const char *); if (value == NULL) { g_warn_if_reached(); break; } xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)value); } va_end(args); } G_GNUC_INTERNAL void gvir_config_object_set_attribute_with_type(GVirConfigObject *object, ...) { va_list args; g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object)); va_start(args, object); while (TRUE) { const char *name; GType attr_type; char *str; name = va_arg(args, const char *); if (name == NULL) { break; } gvir_config_object_remove_attribute(object, name); attr_type = va_arg(args, GType); if (G_TYPE_IS_ENUM(attr_type)) { int val; const char *enum_str; val = va_arg(args, int); enum_str = gvir_config_genum_get_nick(attr_type, val); if (enum_str != NULL) { str = g_strdup(enum_str); } else { str = NULL; } } else switch (attr_type) { case G_TYPE_UINT64: { guint64 val; val = va_arg(args, guint64); str = g_strdup_printf("%"G_GUINT64_FORMAT, val); break; } case G_TYPE_UINT: { guint val; val = va_arg(args, guint); str = g_strdup_printf("%u", val); break; } case G_TYPE_INT: { gint val; val = va_arg(args, gint); str = g_strdup_printf("%d", val); break; } case G_TYPE_STRING: str = va_arg(args, char *); xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)str); str = NULL; break; case G_TYPE_BOOLEAN: { gboolean val; val = va_arg(args, gboolean); str = g_strdup_printf("%s", val?"yes":"no"); break; } default: g_warning("Unhandled type: %s", g_type_name(attr_type)); g_assert_not_reached(); } if (str != NULL) { xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)str); g_free(str); } } va_end(args); } static void gvir_config_object_attach(GVirConfigObject *parent, GVirConfigObject *child, gboolean replace) { g_return_if_fail(GVIR_CONFIG_IS_OBJECT(parent)); g_return_if_fail(GVIR_CONFIG_IS_OBJECT(child)); if (replace) { gvir_config_object_delete_children(parent, (char *)child->priv->node->name, NULL); } xmlUnlinkNode(child->priv->node); xmlAddChild(parent->priv->node, child->priv->node); if (child->priv->doc != NULL) { g_object_unref(G_OBJECT(child->priv->doc)); child->priv->doc = NULL; } if (parent->priv->doc != NULL) { child->priv->doc = g_object_ref(parent->priv->doc); } } G_GNUC_INTERNAL void gvir_config_object_attach_replace(GVirConfigObject *parent, const char *child_name, GVirConfigObject *child) { g_return_if_fail(child_name != NULL); if (child == NULL) gvir_config_object_delete_children(parent, child_name, NULL); else gvir_config_object_attach(parent, child, TRUE); } G_GNUC_INTERNAL void gvir_config_object_attach_add(GVirConfigObject *parent, GVirConfigObject *child) { gvir_config_object_attach(parent, child, FALSE); } G_GNUC_INTERNAL void gvir_config_object_remove_attribute(GVirConfigObject *object, const char *attr_name) { int status; do { status = xmlUnsetProp(object->priv->node, (xmlChar *)attr_name); } while (status == 0); } static gboolean gvir_config_object_set_xmlnode_namespace(xmlNodePtr node, const char *ns, const char *ns_uri) { xmlNsPtr namespace; namespace = xmlNewNs(node, (xmlChar *)ns_uri, (xmlChar *)ns); if (namespace == NULL) return FALSE; xmlSetNs(node, namespace); return TRUE; } static gboolean gvir_config_object_set_namespace_recursively(xmlNodePtr node, const char *ns, const char *ns_uri) { xmlNodePtr n; for (n = node; n != NULL; n = n->next) { if (n->type == XML_ELEMENT_NODE) { if (!gvir_config_object_set_xmlnode_namespace(n, ns, ns_uri)) return FALSE; } if (!gvir_config_object_set_namespace_recursively(n->children, ns, NULL)) return FALSE; } return TRUE; } G_GNUC_INTERNAL gboolean gvir_config_object_set_namespace(GVirConfigObject *object, const char *ns, const char *ns_uri, gboolean ns_children) { g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), FALSE); g_return_val_if_fail(ns != NULL, FALSE); g_return_val_if_fail(ns_uri != NULL, FALSE); if (!ns_children) { return gvir_config_object_set_xmlnode_namespace(object->priv->node, ns, ns_uri); } return gvir_config_object_set_namespace_recursively(object->priv->node, ns, ns_uri); } G_GNUC_INTERNAL GVirConfigObject * gvir_config_object_get_child_with_type(GVirConfigObject *object, const gchar *child_name, GType child_type) { xmlNodePtr node; g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL); g_return_val_if_fail(child_name != NULL, NULL); node = gvir_config_xml_get_element(object->priv->node, child_name, NULL); if (node == NULL) return NULL; return gvir_config_object_new_from_tree(child_type, object->priv->doc, object->priv->schema, node); } G_GNUC_INTERNAL GVirConfigObject * gvir_config_object_get_child(GVirConfigObject *object, const gchar *child_name) { return gvir_config_object_get_child_with_type(object, child_name, GVIR_CONFIG_TYPE_OBJECT); } G_GNUC_INTERNAL gboolean gvir_config_object_has_child(GVirConfigObject *object, const gchar *child_name) { xmlNodePtr node; g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), FALSE); g_return_val_if_fail(child_name != NULL, FALSE); node = gvir_config_xml_get_element(object->priv->node, child_name, NULL); return (node != NULL); }