[Libvir] [PATCH] XPath accessors cleanup

Daniel Veillard veillard at redhat.com
Fri Mar 30 09:38:21 UTC 2007


  It a long time cleanup TODO,  the XML parsing code of xml.c
is invaded with libxml2 specific XPath lookup code, this patch
defines 5 clearly isolated accessor functions and then fixes all
the src/xml.c code to use those. IMHO this clearly improve readability
and maintanability and I think I also found a couple of bugs in the
process.
  The patch enclosed only fixes xml.c and xml.h, the next step is
to chase other modules to apply the same treatment if needed.

Daniel

-- 
Red Hat Virtualization group http://redhat.com/virtualization/
Daniel Veillard      | virtualization library  http://libvirt.org/
veillard at redhat.com  | libxml GNOME XML XSLT toolkit  http://xmlsoft.org/
http://veillard.com/ | Rpmfind RPM search engine  http://rpmfind.net/
-------------- next part --------------
Index: src/xml.c
===================================================================
RCS file: /data/cvs/libxen/src/xml.c,v
retrieving revision 1.68
diff -u -p -r1.68 xml.c
--- src/xml.c	21 Mar 2007 15:24:56 -0000	1.68
+++ src/xml.c	30 Mar 2007 09:30:04 -0000
@@ -17,9 +17,6 @@
 #ifdef WITH_XEN
 #include <xs.h>
 #endif
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/xpath.h>
 #include <math.h> /* for isnan() */
 #include "internal.h"
 #include "hash.h"
@@ -27,6 +24,15 @@
 #include "xml.h"
 #include "xs_internal.h" /* for xenStoreDomainGetNetworkID */
 
+/**
+ * virXMLError:
+ * @conn: a connection if any
+ * @error: the error number
+ * @info: information/format string
+ * @value: extra integer parameter for the error string
+ *
+ * Report an error coming from the XML module.
+ */
 static void
 virXMLError(virConnectPtr conn, virErrorNumber error, const char *info, int value)
 {
@@ -40,6 +46,173 @@ virXMLError(virConnectPtr conn, virError
                     errmsg, info, NULL, value, 0, errmsg, info, value);
 }
 
+#ifndef PROXY
+/**
+ * virXPathString:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ *
+ * Convenience function to evaluate an XPath string
+ *
+ * Returns a new string which must be deallocated by the caller or NULL
+ *         if the evaluation failed.
+ */
+char *
+virXPathString(const char *xpath, xmlXPathContextPtr ctxt) {
+    xmlXPathObjectPtr obj;
+    char *ret;
+
+    if ((ctxt == NULL) || (xpath == NULL)) {
+        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
+	            "Invalid parameter to virXPathString()", 0);
+        return(NULL);
+    }
+    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+        (obj->stringval == NULL) || (obj->stringval[0] == 0))
+        return(NULL);
+    ret = (char *) obj->stringval;
+    obj->stringval = NULL;
+    xmlXPathFreeObject(obj);
+    return(ret);
+}
+
+/**
+ * virXPathNumber:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned double value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ *         or -1 if the evaluation failed.
+ */
+int
+virXPathNumber(const char *xpath, xmlXPathContextPtr ctxt, double *value) {
+    xmlXPathObjectPtr obj;
+
+    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
+	            "Invalid parameter to virXPathNumber()", 0);
+        return(-1);
+    }
+    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
+        (isnan(obj->floatval))) {
+	xmlXPathFreeObject(obj);
+	return(-1);
+    }
+    
+    *value = obj->floatval;
+    xmlXPathFreeObject(obj);
+    return(0);
+}
+
+/**
+ * virXPathBoolean:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ *
+ * Convenience function to evaluate an XPath boolean
+ *
+ * Returns 0 if false, 1 if true, or -1 if the evaluation failed.
+ */
+int
+virXPathBoolean(const char *xpath, xmlXPathContextPtr ctxt) {
+    xmlXPathObjectPtr obj;
+    int ret;
+
+    if ((ctxt == NULL) || (xpath == NULL)) {
+        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
+	            "Invalid parameter to virXPathBoolean()", 0);
+        return(-1);
+    }
+    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) ||
+        (obj->boolval < 0) || (obj->boolval > 1)) {
+	xmlXPathFreeObject(obj);
+	return(-1);
+    }
+    ret = obj->boolval;
+    
+    xmlXPathFreeObject(obj);
+    return(ret);
+}
+
+/**
+ * virXPathNode:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ *
+ * Convenience function to evaluate an XPath node set and returning
+ * only one node, the first one in the set if any
+ *
+ * Returns a pointer to the node or NULL if the evaluation failed.
+ */
+xmlNodePtr
+virXPathNode(const char *xpath, xmlXPathContextPtr ctxt) {
+    xmlXPathObjectPtr obj;
+    xmlNodePtr ret;
+
+    if ((ctxt == NULL) || (xpath == NULL)) {
+        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
+	            "Invalid parameter to virXPathNode()", 0);
+        return(NULL);
+    }
+    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
+        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
+	(obj->nodesetval->nodeTab == NULL)) {
+	xmlXPathFreeObject(obj);
+	return(NULL);
+    }
+    
+    ret = obj->nodesetval->nodeTab[0];
+    xmlXPathFreeObject(obj);
+    return(ret);
+}
+/**
+ * virXPathNodeSet:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @list: the returned list of nodes (or NULL if only count matters)
+ *
+ * Convenience function to evaluate an XPath node set
+ *
+ * Returns the number of nodes found in which case @list is set (and
+ *         must be freed) or -1 if the evaluation failed.
+ */
+int
+virXPathNodeSet(const char *xpath, xmlXPathContextPtr ctxt, xmlNodePtr **list) {
+    xmlXPathObjectPtr obj;
+    int ret;
+
+    if ((ctxt == NULL) || (xpath == NULL)) {
+        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
+	            "Invalid parameter to virXPathNodeSet()", 0);
+        return(-1);
+    }
+    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
+        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
+	(obj->nodesetval->nodeTab == NULL)) {
+	xmlXPathFreeObject(obj);
+	if (list != NULL)
+	    *list = NULL;
+	return(-1);
+    }
+    
+    if (list != NULL) {
+	*list = obj->nodesetval->nodeTab;
+	obj->nodesetval->nodeTab = NULL;
+    }
+    ret = obj->nodesetval->nodeNr;
+    xmlXPathFreeObject(obj);
+    return(ret);
+}
+#endif /* !PROXY */
+
 /**
  * virBufferGrow:
  * @buf:  the buffer
@@ -360,12 +533,12 @@ static int virDomainParseXMLGraphicsDesc
 static int
 virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf, xmlXPathContextPtr ctxt, int vcpus, int xendConfigVersion)
 {
-    xmlXPathObjectPtr obj = NULL;
     xmlNodePtr cur, txt;
     xmlChar *type = NULL;
     xmlChar *loader = NULL;
     xmlChar *boot_dev = NULL;
     int res;
+    char *str;
 
     cur = node->children;
     while (cur != NULL) {
@@ -403,16 +576,13 @@ virDomainParseXMLOSDescHVM(virConnectPtr
     }
 
     /* get the device emulation model */
-    obj = xmlXPathEval(BAD_CAST "string(/domain/devices/emulator[1])", ctxt);
-    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
-        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+    str = virXPathString("string(/domain/devices/emulator[1])", ctxt);
+    if (str == NULL) {
         virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0); /* TODO: error */
         goto error;
     }
-    virBufferVSprintf(buf, "(device_model '%s')",
-                      (const char *) obj->stringval);
-    xmlXPathFreeObject(obj);
-    obj = NULL;
+    virBufferVSprintf(buf, "(device_model '%s')", str);
+    xmlFree(str);
 
     virBufferVSprintf(buf, "(vcpus %d)", vcpus);
 
@@ -429,102 +599,78 @@ virDomainParseXMLOSDescHVM(virConnectPtr
         }
 
         /* get the 1st floppy device file */
-        obj = xmlXPathEval(BAD_CAST "/domain/devices/disk[@device='floppy' and target/@dev='fda']/source", ctxt);
-        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
-            cur = obj->nodesetval->nodeTab[0];
-            virBufferVSprintf(buf, "(fda '%s')",
-                              (const char *) xmlGetProp(cur, BAD_CAST "file"));
-            cur = NULL;
-        }
-        if (obj) {
-            xmlXPathFreeObject(obj);
-            obj = NULL;
+	cur = virXPathNode(
+	  "/domain/devices/disk[@device='floppy' and target/@dev='fda']/source",
+			   ctxt);
+	if (cur != NULL) {
+            xmlChar *fdfile;
+
+            fdfile = xmlGetProp(cur, BAD_CAST "file");
+	    if (fdfile != NULL) {
+		virBufferVSprintf(buf, "(fda '%s')", fdfile);
+		free(fdfile);
+	    }
         }
 
         /* get the 2nd floppy device file */
-        obj = xmlXPathEval(BAD_CAST "/domain/devices/disk[@device='floppy' and target/@dev='fdb']/source", ctxt);
-        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
-            xmlChar *fdfile = NULL;
-            cur = obj->nodesetval->nodeTab[0];
+	cur = virXPathNode(
+	  "/domain/devices/disk[@device='floppy' and target/@dev='fdb']/source",
+			   ctxt);
+	if (cur != NULL) {
+            xmlChar *fdfile;
+
             fdfile = xmlGetProp(cur, BAD_CAST "file");
-            virBufferVSprintf(buf, "(fdb '%s')",
-                              (const char *) fdfile);
-            xmlFree(fdfile);
-            cur = NULL;
-        }
-        if (obj) {
-            xmlXPathFreeObject(obj);
-            obj = NULL;
+	    if (fdfile != NULL) {
+		virBufferVSprintf(buf, "(fdb '%s')", fdfile);
+		free(fdfile);
+	    }
         }
 
 
         /* get the cdrom device file */
         /* Only XenD <= 3.0.2 wants cdrom config here */
         if (xendConfigVersion == 1) {
-            obj = xmlXPathEval(BAD_CAST "/domain/devices/disk[@device='cdrom' and target/@dev='hdc']/source", ctxt);
-            if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-                (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
-                xmlChar *cdfile = NULL;
-                cur = obj->nodesetval->nodeTab[0];
+	    cur = virXPathNode(
+	"/domain/devices/disk[@device='cdrom' and target/@dev='hdc']/source",
+	                       ctxt);
+	    if (cur != NULL) {
+                xmlChar *cdfile;
+
                 cdfile = xmlGetProp(cur, BAD_CAST "file");
-                virBufferVSprintf(buf, "(cdrom '%s')",
-                                  (const char *)cdfile);
-                xmlFree(cdfile);
-                cur = NULL;
-            }
-            if (obj) {
-                xmlXPathFreeObject(obj);
-                obj = NULL;
+		if (cdfile != NULL) {
+		    virBufferVSprintf(buf, "(cdrom '%s')",
+				      (const char *)cdfile);
+		    xmlFree(cdfile);
+		}
             }
         }
 
-        obj = xmlXPathEval(BAD_CAST "/domain/features/acpi", ctxt);
-        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
+        if (virXPathNode("/domain/features/acpi", ctxt) != NULL)
             virBufferAdd(buf, "(acpi 1)", 8);
-        }
-        if (obj)
-            xmlXPathFreeObject(obj);
-        obj = xmlXPathEval(BAD_CAST "/domain/features/apic", ctxt);
-        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
+        if (virXPathNode("/domain/features/apic", ctxt) != NULL)
             virBufferAdd(buf, "(apic 1)", 8);
-        }
-        if (obj)
-            xmlXPathFreeObject(obj);
-        obj = xmlXPathEval(BAD_CAST "/domain/features/pae", ctxt);
-        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
+        if (virXPathNode("/domain/features/pae", ctxt) != NULL)
             virBufferAdd(buf, "(pae 1)", 7);
-        }
-        if (obj)
-            xmlXPathFreeObject(obj);
-        obj = NULL;
     }
 
-    obj = xmlXPathEval(BAD_CAST "count(domain/devices/console) > 0", ctxt);
-    if ((obj == NULL) || (obj->type != XPATH_BOOLEAN)) {
+    res = virXPathBoolean("count(domain/devices/console) > 0", ctxt);
+    if (res < 0) {
         virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0);
         goto error;
     }
-    if (obj->boolval) {
+    if (res) {
         virBufferAdd(buf, "(serial pty)", 12);
     }
-    xmlXPathFreeObject(obj);
-    obj = NULL;
 
     /* Is a graphics device specified? */
-    obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics[1]", ctxt);
-    if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-        (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr > 0)) {
-        res = virDomainParseXMLGraphicsDescImage(conn, obj->nodesetval->nodeTab[0], buf, xendConfigVersion);
+    cur = virXPathNode("/domain/devices/graphics[1]", ctxt);
+    if (cur != NULL) {
+        res = virDomainParseXMLGraphicsDescImage(conn, cur, buf,
+	                                         xendConfigVersion);
         if (res != 0) {
             goto error;
         }
     }
-    xmlXPathFreeObject(obj);
 
     virBufferAdd(buf, "))", 2);
 
@@ -535,8 +681,6 @@ virDomainParseXMLOSDescHVM(virConnectPtr
  error:
     if (boot_dev)
         xmlFree(boot_dev);
-    if (obj != NULL)
-        xmlXPathFreeObject(obj);
     return(-1);
 }
 
@@ -559,7 +703,6 @@ static int
 virDomainParseXMLOSDescPV(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf, xmlXPathContextPtr ctxt, int xendConfigVersion)
 {
     xmlNodePtr cur, txt;
-    xmlXPathObjectPtr obj = NULL;
     const xmlChar *type = NULL;
     const xmlChar *root = NULL;
     const xmlChar *kernel = NULL;
@@ -626,15 +769,14 @@ virDomainParseXMLOSDescPV(virConnectPtr 
     /* Is a graphics device specified? */
     /* Old style config before merge of PVFB */
     if (xendConfigVersion < 3) {
-        obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics[1]", ctxt);
-        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr > 0)) {
-            res = virDomainParseXMLGraphicsDescImage(conn, obj->nodesetval->nodeTab[0], buf, xendConfigVersion);
+        cur = virXPathNode("/domain/devices/graphics[1]", ctxt);
+        if (cur != NULL) {
+            res = virDomainParseXMLGraphicsDescImage(conn, cur, buf,
+	                                             xendConfigVersion);
             if (res != 0) {
                 goto error;
             }
         }
-        xmlXPathFreeObject(obj);
     }
 
  error:
@@ -958,14 +1100,16 @@ virDomainParseXMLDesc(virConnectPtr conn
     virBuffer buf;
     xmlChar *prop;
     xmlParserCtxtPtr pctxt;
-    xmlXPathObjectPtr obj = NULL;
-    xmlXPathObjectPtr tmpobj = NULL;
     xmlXPathContextPtr ctxt = NULL;
     int i, res;
     int bootloader = 0;
     int hvm = 0;
     unsigned int vcpus = 1;
     unsigned long mem = 0, max_mem = 0;
+    char *str;
+    double f;
+    xmlNodePtr *nodes;
+    int nb_nodes;
 
     if (name != NULL)
         *name = NULL;
@@ -1012,117 +1156,90 @@ virDomainParseXMLDesc(virConnectPtr conn
     /*
      * extract some of the basics, name, memory, cpus ...
      */
-    obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt);
-    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
-        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
-        virXMLError(conn, VIR_ERR_NO_NAME, xmldesc, 0);
-        goto error;
-    }
-    virBufferVSprintf(&buf, "(name '%s')", obj->stringval);
-    nam = strdup((const char *) obj->stringval);
+    nam = virXPathString("string(/domain/name[1])", ctxt);
     if (nam == NULL) {
-        virXMLError(conn, VIR_ERR_NO_MEMORY, "copying name", 0);
+        virXMLError(conn, VIR_ERR_NO_NAME, xmldesc, 0);
         goto error;
     }
-    xmlXPathFreeObject(obj);
+    virBufferVSprintf(&buf, "(name '%s')", nam);
 
-    obj = xmlXPathEval(BAD_CAST "number(/domain/memory[1])", ctxt);
-    if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
-        (isnan(obj->floatval)) || (obj->floatval < MIN_XEN_GUEST_SIZE * 1024)) {
+    if ((virXPathNumber("number(/domain/memory[1])", ctxt, &f) < 0) ||
+        (f < MIN_XEN_GUEST_SIZE * 1024)) {
         max_mem = 128;
     } else {
-        max_mem = (obj->floatval / 1024);
+        max_mem = (f / 1024);
     }
-    xmlXPathFreeObject(obj);
-    obj = xmlXPathEval(BAD_CAST "number(/domain/currentMemory[1])", ctxt);
-    if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
-        (isnan(obj->floatval)) || (obj->floatval < MIN_XEN_GUEST_SIZE * 1024)) {
+
+    if ((virXPathNumber("number(/domain/currentMemory[1])", ctxt, &f) < 0) ||
+        (f < MIN_XEN_GUEST_SIZE * 1024)) {
         mem = max_mem;
     } else {
-        mem = (obj->floatval / 1024);
+        mem = (f / 1024);
         if (mem > max_mem) {
             max_mem = mem;
         }
     }
-    xmlXPathFreeObject(obj);
     virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)", mem, max_mem);
 
-    obj = xmlXPathEval(BAD_CAST "number(/domain/vcpu[1])", ctxt);
-    if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
-        (!isnan(obj->floatval)) && (obj->floatval > 0)) {
-        vcpus = (unsigned int) obj->floatval;
+    if ((virXPathNumber("number(/domain/vcpu[1])", ctxt, &f) == 0) &&
+        (f > 0)) {
+        vcpus = (unsigned int) f;
     }
     virBufferVSprintf(&buf, "(vcpus %u)", vcpus);
-    xmlXPathFreeObject(obj);
 
-    obj = xmlXPathEval(BAD_CAST "string(/domain/uuid[1])", ctxt);
-    if ((obj == NULL) || ((obj->type == XPATH_STRING) &&
-                          (obj->stringval != NULL) && (obj->stringval[0] != 0))) {
-        virBufferVSprintf(&buf, "(uuid '%s')", obj->stringval);
+    str = virXPathString("string(/domain/uuid[1])", ctxt);
+    if (str != NULL) {
+        virBufferVSprintf(&buf, "(uuid '%s')", str);
+	free(str);
     }
-    xmlXPathFreeObject(obj);
 
-    obj = xmlXPathEval(BAD_CAST "string(/domain/bootloader[1])", ctxt);
-    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
-        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
-        virBufferVSprintf(&buf, "(bootloader '%s')", obj->stringval);
+    str = virXPathString("string(/domain/bootloader[1])", ctxt);
+    if (str != NULL) {
+        virBufferVSprintf(&buf, "(bootloader '%s')", str);
         /*
          * if using pygrub, the kernel and initrd strings are not
          * significant and should be discarded
          */
-        if (xmlStrstr(obj->stringval, BAD_CAST "pygrub"))
+        if (strstr(str, "pygrub"))
             bootloader = 2;
         else
             bootloader = 1;
+	free(str);
     }
-    xmlXPathFreeObject(obj);
 
-    obj = xmlXPathEval(BAD_CAST "string(/domain/on_poweroff[1])", ctxt);
-    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
-        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
-        virBufferVSprintf(&buf, "(on_poweroff '%s')", obj->stringval);
+    str = virXPathString("string(/domain/on_poweroff[1])", ctxt);
+    if (str != NULL) {
+        virBufferVSprintf(&buf, "(on_poweroff '%s')", str);
+	free(str);
     }
-    xmlXPathFreeObject(obj);
 
-    obj = xmlXPathEval(BAD_CAST "string(/domain/on_reboot[1])", ctxt);
-    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
-        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
-        virBufferVSprintf(&buf, "(on_reboot '%s')", obj->stringval);
+    str = virXPathString("string(/domain/on_reboot[1])", ctxt);
+    if (str != NULL) {
+        virBufferVSprintf(&buf, "(on_reboot '%s')", str);
+	free(str);
     }
-    xmlXPathFreeObject(obj);
 
-    obj = xmlXPathEval(BAD_CAST "string(/domain/on_crash[1])", ctxt);
-    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
-        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
-        virBufferVSprintf(&buf, "(on_crash '%s')", obj->stringval);
+    str = virXPathString("string(/domain/on_crash[1])", ctxt);
+    if (str != NULL) {
+        virBufferVSprintf(&buf, "(on_crash '%s')", str);
+	free(str);
     }
-    xmlXPathFreeObject(obj);
 
     if (bootloader != 2) {
-        obj = xmlXPathEval(BAD_CAST "/domain/os[1]", ctxt);
-        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
+        if ((node = virXPathNode("/domain/os[1]", ctxt)) != NULL) {
             /* Analyze of the os description, based on HVM or PV. */
-            tmpobj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1])", ctxt);
-            if ((tmpobj != NULL) &&
-                ((tmpobj->type != XPATH_STRING) || (tmpobj->stringval == NULL)
-                 || (tmpobj->stringval[0] == 0))) {
-                xmlXPathFreeObject(tmpobj);
-                virXMLError(conn, VIR_ERR_OS_TYPE, nam, 0);
-                goto error;
-            }
+	    str = virXPathString("string(/domain/os/type[1])", ctxt);
 
-            if ((tmpobj == NULL)
-                || !xmlStrEqual(tmpobj->stringval, BAD_CAST "hvm")) {
-                res = virDomainParseXMLOSDescPV(conn, obj->nodesetval->nodeTab[0],
+            if ((str == NULL) || (strcmp(str, "hvm"))) {
+                res = virDomainParseXMLOSDescPV(conn, node,
                                                 &buf, ctxt, xendConfigVersion);
             } else {
                 hvm = 1;
-                res = virDomainParseXMLOSDescHVM(conn, obj->nodesetval->nodeTab[0],
-                                                 &buf, ctxt, vcpus, xendConfigVersion);
+                res = virDomainParseXMLOSDescHVM(conn, node, &buf, ctxt,
+		                                 vcpus, xendConfigVersion);
             }
 
-            xmlXPathFreeObject(tmpobj);
+            if (str != NULL) free(str);
 
             if (res != 0)
                 goto error;
@@ -1130,49 +1247,49 @@ virDomainParseXMLDesc(virConnectPtr conn
             virXMLError(conn, VIR_ERR_NO_OS, nam, 0);
             goto error;
         }
-        xmlXPathFreeObject(obj);
     }
 
     /* analyze of the devices */
-    obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
-    if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-        (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
-        for (i = 0; i < obj->nodesetval->nodeNr; i++) {
-            res = virDomainParseXMLDiskDesc(conn, obj->nodesetval->nodeTab[i], &buf, hvm, xendConfigVersion);
+    nb_nodes = virXPathNodeSet("/domain/devices/disk", ctxt, &nodes);
+    if (nb_nodes > 0) {
+        for (i = 0; i < nb_nodes; i++) {
+            res = virDomainParseXMLDiskDesc(conn, nodes[i], &buf,
+	                                    hvm, xendConfigVersion);
             if (res != 0) {
+	        free(nodes);
                 goto error;
             }
         }
+	free(nodes);
     }
-    xmlXPathFreeObject(obj);
 
-    obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt);
-    if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-        (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
-        for (i = 0; i < obj->nodesetval->nodeNr; i++) {
+    nb_nodes = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes);
+    if (nb_nodes > 0) {
+        for (i = 0; i < nb_nodes; i++) {
             virBufferAdd(&buf, "(device ", 8);
-            res = virDomainParseXMLIfDesc(conn, obj->nodesetval->nodeTab[i], &buf, hvm);
+            res = virDomainParseXMLIfDesc(conn, nodes[i], &buf, hvm);
             if (res != 0) {
+	        free(nodes);
                 goto error;
             }
             virBufferAdd(&buf, ")", 1);
         }
+	free(nodes);
     }
-    xmlXPathFreeObject(obj);
 
     /* New style PVFB config  - 3.0.4 merge */
     if (xendConfigVersion >= 3 && !hvm) {
-        obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics", ctxt);
-        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
-            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
-            for (i = 0; i < obj->nodesetval->nodeNr; i++) {
-                res = virDomainParseXMLGraphicsDescVFB(conn, obj->nodesetval->nodeTab[i], &buf);
+        nb_nodes = virXPathNodeSet("/domain/devices/graphics", ctxt, &nodes);
+	if (nb_nodes > 0) {
+            for (i = 0; i < nb_nodes; i++) {
+                res = virDomainParseXMLGraphicsDescVFB(conn, nodes[i], &buf);
                 if (res != 0) {
+		    free(nodes);
                     goto error;
                 }
             }
+	    free(nodes);
         }
-        xmlXPathFreeObject(obj);
     }
 
 
@@ -1195,8 +1312,6 @@ virDomainParseXMLDesc(virConnectPtr conn
         free(nam);
     if (name != NULL)
         *name = NULL;
-    if (obj != NULL)
-        xmlXPathFreeObject(obj);
     if (ctxt != NULL)
         xmlXPathFreeContext(ctxt);
     if (xml != NULL)
Index: src/xml.h
===================================================================
RCS file: /data/cvs/libxen/src/xml.h,v
retrieving revision 1.13
diff -u -p -r1.13 xml.h
--- src/xml.h	16 Mar 2007 15:03:21 -0000	1.13
+++ src/xml.h	30 Mar 2007 09:30:04 -0000
@@ -1,5 +1,5 @@
 /*
- * internal.h: internal definitions just used by code from the library
+ * xml.h: internal definitions used for XML parsing routines.
  */
 
 #ifndef __VIR_XML_H__
@@ -8,6 +8,9 @@
 #include "libvirt/libvirt.h"
 #include "internal.h"
 
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -32,6 +35,19 @@ int virBufferVSprintf(virBufferPtr buf, 
   ATTRIBUTE_FORMAT(printf, 2, 3);
 int virBufferStrcat(virBufferPtr buf, ...);
 
+int		virXPathBoolean	(const char *xpath,
+				 xmlXPathContextPtr ctxt);
+char *		virXPathString	(const char *xpath,
+				 xmlXPathContextPtr ctxt);
+int		virXPathNumber	(const char *xpath,
+				 xmlXPathContextPtr ctxt,
+				 double *value);
+xmlNodePtr	virXPathNode	(const char *xpath,
+				 xmlXPathContextPtr ctxt);
+int		virXPathNodeSet	(const char *xpath,
+				 xmlXPathContextPtr ctxt,
+				 xmlNodePtr **list);
+
 char *virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, int xendConfigVersion);
 unsigned char *virParseUUID(char **ptr, const char *uuid);
 char *virParseXMLDevice(virConnectPtr conn, char *xmldesc, int hvm, int xendConfigVersion);


More information about the libvir-list mailing list