[libvirt] [PATCH 3/8] Add virXMLValidateAgainstSchema helper method

Daniel P. Berrange berrange at redhat.com
Tue Nov 18 17:59:50 UTC 2014


Add a helper method that can validate an XML document against
an RNG schema
---
 include/libvirt/virterror.h |  1 +
 src/internal.h              |  4 +++
 src/libvirt_private.syms    |  1 +
 src/util/virerror.c         |  6 ++++
 src/util/virxml.c           | 74 +++++++++++++++++++++++++++++++++++++++++++++
 src/util/virxml.h           |  5 +++
 6 files changed, 91 insertions(+)

diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 85dd74c..3d3d80a 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -304,6 +304,7 @@ typedef enum {
     VIR_ERR_STORAGE_VOL_EXIST = 90,     /* the storage vol already exists */
     VIR_ERR_CPU_INCOMPATIBLE = 91,      /* given CPU is incompatible with host
                                            CPU*/
+    VIR_ERR_XML_INVALID_SCHEMA = 92,    /* XML document doens't validate against schema */
 } virErrorNumber;
 
 /**
diff --git a/src/internal.h b/src/internal.h
index f6a88b2..b07421a 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -233,11 +233,15 @@
 #  define VIR_WARNINGS_NO_CAST_ALIGN \
     _Pragma ("GCC diagnostic push") \
     _Pragma ("GCC diagnostic ignored \"-Wcast-align\"")
+#  define VIR_WARNINGS_NO_PRINTF \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wsuggest-attribute=format\"")
 
 #  define VIR_WARNINGS_RESET \
     _Pragma ("GCC diagnostic pop")
 # else
 #  define VIR_WARNINGS_NO_CAST_ALIGN
+#  define VIR_WARNINGS_NO_PRINTF
 #  define VIR_WARNINGS_RESET
 # endif
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0864618..b48dde4 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2226,6 +2226,7 @@ virXMLParseHelper;
 virXMLPickShellSafeComment;
 virXMLPropString;
 virXMLSaveFile;
+virXMLValidateAgainstSchema;
 virXPathBoolean;
 virXPathInt;
 virXPathLong;
diff --git a/src/util/virerror.c b/src/util/virerror.c
index 4aa6d04..f5d7f54 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -1285,6 +1285,12 @@ virErrorMsg(virErrorNumber error, const char *info)
             else
                 errmsg = _("the CPU is incompatible with host CPU: %s");
             break;
+        case VIR_ERR_XML_INVALID_SCHEMA:
+            if (info == NULL)
+                errmsg = _("XML document failed to validate against schema");
+            else
+                errmsg = _("XML document failed to validate against schema: %s");
+            break;
     }
     return errmsg;
 }
diff --git a/src/util/virxml.c b/src/util/virxml.c
index 7f591fb..4508e58 100644
--- a/src/util/virxml.c
+++ b/src/util/virxml.c
@@ -1076,3 +1076,77 @@ virXMLInjectNamespace(xmlNodePtr node,
 
     return 0;
 }
+
+static void catchRNGError(void *ctx,
+                          const char *msg,
+                          ...)
+{
+    virBufferPtr buf = ctx;
+    va_list args;
+
+    va_start(args, msg);
+    VIR_WARNINGS_NO_PRINTF;
+    virBufferVasprintf(buf, msg, args);
+    VIR_WARNINGS_RESET;
+    va_end(args);
+}
+
+
+static void ignoreRNGError(void *ctx ATTRIBUTE_UNUSED,
+                           const char *msg ATTRIBUTE_UNUSED,
+                           ...)
+{}
+
+
+int
+virXMLValidateAgainstSchema(const char *schemafile,
+                            xmlDocPtr doc)
+{
+    xmlRelaxNGParserCtxtPtr rngParser = NULL;
+    xmlRelaxNGPtr rng = NULL;
+    xmlRelaxNGValidCtxtPtr rngValid = NULL;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    int ret = -1;
+
+    if (!(rngParser = xmlRelaxNGNewParserCtxt(schemafile))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unable to create RNG parser for %s"),
+                       schemafile);
+        goto cleanup;
+    }
+
+    if (!(rng = xmlRelaxNGParse(rngParser))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unable to parse RNG %s"),
+                       schemafile);
+        goto cleanup;
+    }
+
+    if (!(rngValid = xmlRelaxNGNewValidCtxt(rng))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unable to create RNG validation context %s"),
+                       schemafile);
+        goto cleanup;
+    }
+
+    xmlRelaxNGSetValidErrors(rngValid,
+                             catchRNGError,
+                             ignoreRNGError,
+                             &buf);
+
+    if (xmlRelaxNGValidateDoc(rngValid, doc) != 0) {
+        virReportError(VIR_ERR_XML_INVALID_SCHEMA,
+                       _("Unable to validate doc against %s\n%s"),
+                       schemafile, virBufferCurrentContent(&buf));
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    virBufferFreeAndReset(&buf);
+    xmlRelaxNGFreeParserCtxt(rngParser);
+    xmlRelaxNGFreeValidCtxt(rngValid);
+    xmlRelaxNGFree(rng);
+    return ret;
+}
diff --git a/src/util/virxml.h b/src/util/virxml.h
index 781b3bf..b94de74 100644
--- a/src/util/virxml.h
+++ b/src/util/virxml.h
@@ -28,6 +28,7 @@
 # include <libxml/parser.h>
 # include <libxml/tree.h>
 # include <libxml/xpath.h>
+# include <libxml/relaxng.h>
 
 int              virXPathBoolean(const char *xpath,
                                  xmlXPathContextPtr ctxt);
@@ -176,4 +177,8 @@ int virXMLInjectNamespace(xmlNodePtr node,
                           const char *uri,
                           const char *key);
 
+int
+virXMLValidateAgainstSchema(const char *schemafile,
+                            xmlDocPtr xml);
+
 #endif                          /* __VIR_XML_H__ */
-- 
2.1.0




More information about the libvir-list mailing list