1) virXMLChildNode and virXMLChildNodeSet
Parse xml based on 'node' rather than 'ctxt'.
2) virXMLChildPropString
Support to parse child node's property value by path,
which is as "child_node_name/prop_name".
3) virXMLChildNodeContent
Support to parse child node's content.
4) virBufferIgnore
Mark a buffer with the flag 'ignored'.
5) virBufferTouched
Check whether the buffer has been touched, which means
this buffer has been used or ignored.
6) virBufferInheritIndent
Inherit the indentation from another buffer.
Signed-off-by: Shi Lei <shi_lei(a)massclouds.com>
---
src/libvirt_private.syms | 6 ++
src/util/virbuffer.c | 44 ++++++++++++++
src/util/virbuffer.h | 8 ++-
src/util/virxml.c | 120 +++++++++++++++++++++++++++++++++++++++
src/util/virxml.h | 6 ++
5 files changed, 182 insertions(+), 2 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e9bb2391..fad0ff71 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1864,9 +1864,12 @@ virBufferEscapeString;
virBufferFreeAndReset;
virBufferGetEffectiveIndent;
virBufferGetIndent;
+virBufferIgnore;
+virBufferInheritIndent;
virBufferSetIndent;
virBufferStrcat;
virBufferStrcatVArgs;
+virBufferTouched;
virBufferTrim;
virBufferTrimChars;
virBufferTrimLen;
@@ -3539,6 +3542,9 @@ virVsockSetGuestCid;
virParseScaledValue;
virXMLBufferCreate;
virXMLCheckIllegalChars;
+virXMLChildNode;
+virXMLChildNodeSet;
+virXMLChildPropString;
virXMLExtractNamespaceXML;
virXMLFormatElement;
virXMLNewNode;
diff --git a/src/util/virbuffer.c b/src/util/virbuffer.c
index 8f9cd57e..b6f936c8 100644
--- a/src/util/virbuffer.c
+++ b/src/util/virbuffer.c
@@ -80,6 +80,24 @@ virBufferSetIndent(virBuffer *buf, int indent)
}
+/**
+ * virBufferInheritIndent:
+ * @buf: the buffer
+ * @frombuf: new indentation size from it.
+ *
+ * Just like virBufferSetIndent, but the indentation comes from
+ * another buffer.
+ */
+void
+virBufferInheritIndent(virBuffer *buf, virBuffer *frombuf)
+{
+ if (!buf || !frombuf)
+ return;
+
+ buf->indent = virBufferGetEffectiveIndent(frombuf);
+}
+
+
/**
* virBufferGetIndent:
* @buf: the buffer
@@ -291,6 +309,32 @@ virBufferUse(const virBuffer *buf)
return buf->str->len;
}
+/**
+ * virBufferTouched:
+ * @buf: the buffer to be checked
+ *
+ * Return true when the buffer has content or
+ * it has been ignored(by calling virBufferIgnore);
+ * otherwise, return false.
+ */
+bool
+virBufferTouched(virBuffer *buf)
+{
+ return buf->ignored || virBufferUse(buf);
+}
+
+/**
+ * virBufferIgnore:
+ * @buf: the buffer to be ignored
+ *
+ * Ignore the buffer explicitly.
+ */
+void
+virBufferIgnore(virBuffer *buf)
+{
+ buf->ignored = true;
+}
+
/**
* virBufferAsprintf:
* @buf: the buffer to append to
diff --git a/src/util/virbuffer.h b/src/util/virbuffer.h
index 0e72d078..ddb29cb5 100644
--- a/src/util/virbuffer.h
+++ b/src/util/virbuffer.h
@@ -32,7 +32,7 @@
*/
typedef struct _virBuffer virBuffer;
-#define VIR_BUFFER_INITIALIZER { NULL, 0 }
+#define VIR_BUFFER_INITIALIZER { NULL, 0, false }
/**
* VIR_BUFFER_INIT_CHILD:
@@ -41,11 +41,12 @@ typedef struct _virBuffer virBuffer;
* Initialize a virBuffer structure and set up the indentation level for
* formatting XML subelements of @parentbuf.
*/
-#define VIR_BUFFER_INIT_CHILD(parentbuf) { NULL, (parentbuf)->indent + 2 }
+#define VIR_BUFFER_INIT_CHILD(parentbuf) { NULL, (parentbuf)->indent + 2, false }
struct _virBuffer {
GString *str;
int indent;
+ bool ignored;
};
const char *virBufferCurrentContent(virBuffer *buf);
@@ -86,6 +87,7 @@ void virBufferURIEncodeString(virBuffer *buf, const char *str);
void virBufferAdjustIndent(virBuffer *buf, int indent);
void virBufferSetIndent(virBuffer *, int indent);
+void virBufferInheritIndent(virBuffer *buf, virBuffer *frombuf);
size_t virBufferGetIndent(const virBuffer *buf);
size_t virBufferGetEffectiveIndent(const virBuffer *buf);
@@ -94,3 +96,5 @@ void virBufferTrim(virBuffer *buf, const char *trim);
void virBufferTrimChars(virBuffer *buf, const char *trim);
void virBufferTrimLen(virBuffer *buf, int len);
void virBufferAddStr(virBuffer *buf, const char *str);
+bool virBufferTouched(virBuffer *buf);
+void virBufferIgnore(virBuffer *buf);
diff --git a/src/util/virxml.c b/src/util/virxml.c
index 5ceef738..a6e50459 100644
--- a/src/util/virxml.c
+++ b/src/util/virxml.c
@@ -1746,3 +1746,123 @@ virXMLNewNode(xmlNsPtr ns,
return ret;
}
+
+
+/**
+ * virXMLChildNode:
+ * @node: Parent XML dom node pointer
+ * @name: Name of the child element
+ *
+ * Convenience function to return the child element of a XML node.
+ *
+ * Returns the pointer of child element node or NULL in case of failure.
+ * If there are many nodes match condition, it only returns the first node.
+ */
+xmlNodePtr
+virXMLChildNode(xmlNodePtr node, const char *name)
+{
+ xmlNodePtr cur = node->children;
+ while (cur) {
+ if (cur->type == XML_ELEMENT_NODE && virXMLNodeNameEqual(cur, name))
+ return cur;
+ cur = cur->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * virXMLChildPropString:
+ * @node: Parent XML dom node pointer
+ * @path: Path of the property (attribute) to get
+ *
+ * Convenience function to return copy of an attribute value by a path.
+ * Path consists of names of child elements and an attribute.
+ * The delimiter is '/'.
+ *
+ * E.g.: For <self><son><grandson
name="..."></grandson></son></self>,
+ * the path is 'son/grandSon/name' to get attribute 'name'.
+ *
+ * Returns the property (attribute) value as string or NULL in case of failure.
+ * The caller is responsible for freeing the returned buffer.
+ */
+char *
+virXMLChildPropString(xmlNodePtr node, const char *path)
+{
+ char *next;
+ char *sep;
+ xmlNodePtr tnode = node;
+ g_autofree char *tmp = NULL;
+ tmp = g_strdup(path);
+
+ next = tmp;
+ while ((sep = strchr(next, '/'))) {
+ *sep = '\0';
+
+ if ((tnode = virXMLChildNode(tnode, next)) == NULL)
+ return NULL;
+
+ next = sep + 1;
+ }
+
+ return virXMLPropString(tnode, next);
+}
+
+
+/**
+ * virXMLChildNodeSet:
+ * @node: Parent XML dom node pointer
+ * @name: Name of the children element
+ * @list: the returned list of nodes (or NULL if only count matters)
+ *
+ * Convenience function to evaluate a set of children elements
+ *
+ * Returns the number of nodes found in which case @list is set (and
+ * must be freed) or -1 if the evaluation failed.
+ */
+int
+virXMLChildNodeSet(xmlNodePtr node, const char *name, xmlNodePtr **list)
+{
+ size_t count = 0;
+ xmlNodePtr cur = node->children;
+
+ if (list != NULL)
+ *list = NULL;
+
+ while (cur) {
+ if (cur->type == XML_ELEMENT_NODE && virXMLNodeNameEqual(cur, name))
{
+ if (list != NULL) {
+ if (VIR_APPEND_ELEMENT_COPY(*list, count, cur) < 0)
+ return -1;
+ } else {
+ count++;
+ }
+ }
+ cur = cur->next;
+ }
+ return count;
+}
+
+
+/**
+ * virXMLChildNodeContent:
+ * @node: XML parent node pointer
+ * @name: child node name
+ *
+ * Convenience function to return copy of content of an child node.
+ * E.g., for <parent><child>content</child></parent>, call
+ * virXMLChildNodeContent(parent_node_ptr, "child") to get the content
+ * of the child node.
+ *
+ * Returns the content value as string or NULL in case of failure.
+ * The caller is responsible for freeing the returned buffer.
+ */
+char *
+virXMLChildNodeContent(xmlNodePtr node, const char *name)
+{
+ xmlNodePtr child = virXMLChildNode(node, name);
+ if (!child)
+ return NULL;
+
+ return virXMLNodeContentString(child);
+}
diff --git a/src/util/virxml.h b/src/util/virxml.h
index c83d16a1..7dac1d3e 100644
--- a/src/util/virxml.h
+++ b/src/util/virxml.h
@@ -134,6 +134,10 @@ virXMLPropUInt(xmlNodePtr node,
unsigned int *result)
ATTRIBUTE_NONNULL(0) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4);
+xmlNodePtr virXMLChildNode(xmlNodePtr node, const char *name);
+int virXMLChildNodeSet(xmlNodePtr node, const char *name, xmlNodePtr **list);
+char * virXMLChildPropString(xmlNodePtr node, const char *path);
+
int
virXMLPropEnum(xmlNodePtr node,
const char* name,
@@ -375,3 +379,5 @@ virXMLBufferCreate(void);
xmlNodePtr
virXMLNewNode(xmlNsPtr ns,
const char *name);
+
+char * virXMLChildNodeContent(xmlNodePtr node, const char *name);
--
2.25.1