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