Changed the internals a lot for DOM, entity support, slight changes of API,
more (if not all) formating of function comments, started documentation, Daniel.
diff --git a/tree.c b/tree.c
index 0aeff3c..202f0b8 100644
--- a/tree.c
+++ b/tree.c
@@ -346,6 +346,125 @@
}
/**
+ * xmlStringGetNodeList:
+ * @doc: the document
+ * @value: the value of the attribute
+ *
+ * Parse the value string and build the node list associated. Should
+ * produce a flat tree with only TEXTs and ENTITY_REFs.
+ * return values: a pointer to the first child
+ */
+xmlNodePtr xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
+ xmlNodePtr ret = NULL, last = NULL;
+ xmlNodePtr node;
+ CHAR *val;
+ const CHAR *cur = value;
+ const CHAR *q;
+
+ if (value == NULL) return(NULL);
+
+ q = cur;
+ while (*cur != 0) {
+ if (*cur == '&') {
+ if (cur != q) {
+ node = xmlNewTextLen(q, cur - q);
+ if (node == NULL) return(ret);
+ if (last == NULL)
+ last = ret = node;
+ else {
+ last->next = node;
+ last = node;
+ }
+ }
+ cur++;
+ q = cur;
+ while ((*cur != 0) && (*cur != ';')) cur++;
+ if (*cur == 0) {
+ fprintf(stderr,
+ "xmlStringGetNodeList: unterminated entity %30s\n", q);
+ return(ret);
+ }
+ if (cur != q) {
+ val = xmlStrndup(q, cur - q);
+ node = xmlNewReference(doc, val);
+ if (node == NULL) return(ret);
+ if (last == NULL)
+ last = ret = node;
+ else {
+ last->next = node;
+ last = node;
+ }
+ free(val);
+ }
+ cur++;
+ q = cur;
+ } else
+ cur++;
+ }
+ if (cur != q) {
+ node = xmlNewTextLen(q, cur - q);
+ if (node == NULL) return(ret);
+ if (last == NULL)
+ last = ret = node;
+ else {
+ last->next = node;
+ last = node;
+ }
+ }
+ return(ret);
+}
+
+/**
+ * xmlNodeListGetString:
+ * @doc: the document
+ * @list: a Node list
+ * @inLine: should we replace entity contents or show their external form
+ *
+ * Returns the string equivalent to the text contained in the Node list
+ * made of TEXTs and ENTITY_REFs
+ * return values: a pointer to the string copy, the calller must free it.
+ */
+CHAR *xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
+ xmlNodePtr node = list;
+ CHAR *ret = NULL;
+ xmlEntityPtr ent;
+
+ if (list == NULL) return(NULL);
+
+ while (node != NULL) {
+ if (node->type == XML_TEXT_NODE) {
+ if (inLine)
+ ret = xmlStrcat(ret, node->content);
+ else
+ ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
+ } else if (node->type == XML_ENTITY_REF_NODE) {
+ if (inLine) {
+ ent = xmlGetDocEntity(doc, node->name);
+ if (ent != NULL)
+ ret = xmlStrcat(ret, ent->content);
+ else
+ ret = xmlStrcat(ret, node->content);
+ } else {
+ CHAR buf[2];
+ buf[0] = '&'; buf[1] = 0;
+ ret = xmlStrncat(ret, buf, 1);
+ ret = xmlStrcat(ret, node->name);
+ buf[0] = ';'; buf[1] = 0;
+ ret = xmlStrncat(ret, buf, 1);
+ }
+ }
+#if 0
+ else {
+ fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
+ node->type);
+ }
+#endif
+ node = node->next;
+ }
+ return(ret);
+}
+
+/**
* xmlNewProp:
* @node: the holding node
* @name: the name of the attribute
@@ -375,9 +494,9 @@
cur->node = node;
cur->name = xmlStrdup(name);
if (value != NULL)
- cur->value = xmlStrdup(value);
+ cur->val = xmlStringGetNodeList(node->doc, value);
else
- cur->value = NULL;
+ cur->val = NULL;
#ifndef WITHOUT_CORBA
cur->_private = NULL;
cur->vepv = NULL;
@@ -401,6 +520,48 @@
}
/**
+ * xmlNewDocProp:
+ * @doc: the document
+ * @name: the name of the attribute
+ * @value: the value of the attribute
+ *
+ * Create a new property carried by a document.
+ * return values: a pointer to the attribute
+ */
+xmlAttrPtr xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
+ xmlAttrPtr cur;
+
+ if (name == NULL) {
+ fprintf(stderr, "xmlNewProp : name == NULL\n");
+ return(NULL);
+ }
+
+ /*
+ * Allocate a new property and fill the fields.
+ */
+ cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
+ if (cur == NULL) {
+ fprintf(stderr, "xmlNewProp : malloc failed\n");
+ return(NULL);
+ }
+
+ cur->type = XML_ATTRIBUTE_NODE;
+ cur->node = NULL;
+ cur->name = xmlStrdup(name);
+ if (value != NULL)
+ cur->val = xmlStringGetNodeList(doc, value);
+ else
+ cur->val = NULL;
+#ifndef WITHOUT_CORBA
+ cur->_private = NULL;
+ cur->vepv = NULL;
+#endif
+
+ cur->next = NULL;
+ return(cur);
+}
+
+/**
* xmlFreePropList:
* @cur: the first property in the list
*
@@ -431,7 +592,7 @@
return;
}
if (cur->name != NULL) free((char *) cur->name);
- if (cur->value != NULL) free((char *) cur->value);
+ if (cur->val != NULL) xmlFreeNodeList(cur->val);
memset(cur, -1, sizeof(xmlAttr));
free(cur);
}
@@ -443,9 +604,11 @@
* @content: the text content if any
*
* Creation of a new node element. @ns and @content are optionnal (NULL).
+ * If content is non NULL, a child list containing the TEXTs and
+ * ENTITY_REFs node will be created.
* return values: a pointer to the new node object.
*/
-xmlNodePtr xmlNewNode(xmlNsPtr ns, const CHAR *name, CHAR *content) {
+xmlNodePtr xmlNewNode(xmlNsPtr ns, const CHAR *name) {
xmlNodePtr cur;
if (name == NULL) {
@@ -473,14 +636,11 @@
cur->name = xmlStrdup(name);
cur->ns = ns;
cur->nsDef = NULL;
+ cur->content = NULL;
#ifndef WITHOUT_CORBA
cur->_private = NULL;
cur->vepv = NULL;
#endif
- if (content != NULL)
- cur->content = xmlStrdup(content);
- else
- cur->content = NULL;
return(cur);
}
@@ -499,8 +659,12 @@
const CHAR *name, CHAR *content) {
xmlNodePtr cur;
- cur = xmlNewNode(ns, name, content);
- if (cur != NULL) cur->doc = doc;
+ cur = xmlNewNode(ns, name);
+ if (cur != NULL) {
+ cur->doc = doc;
+ if (content != NULL)
+ cur->childs = xmlStringGetNodeList(doc, content);
+ }
return(cur);
}
@@ -543,6 +707,55 @@
}
/**
+ * xmlNewReference:
+ * @doc: the document
+ * @name: the reference name, or the reference string with & and ;
+ *
+ * Creation of a new reference node.
+ * return values: a pointer to the new node object.
+ */
+xmlNodePtr xmlNewReference(xmlDocPtr doc, const CHAR *name) {
+ xmlNodePtr cur;
+ xmlEntityPtr ent;
+
+ /*
+ * Allocate a new node and fill the fields.
+ */
+ cur = (xmlNodePtr) malloc(sizeof(xmlNode));
+ if (cur == NULL) {
+ fprintf(stderr, "xmlNewText : malloc failed\n");
+ return(NULL);
+ }
+
+ cur->type = XML_ENTITY_REF_NODE;
+ cur->doc = NULL;
+ cur->parent = NULL;
+ cur->next = NULL;
+ cur->prev = NULL;
+ cur->childs = NULL;
+ cur->properties = NULL;
+ if (name[0] == '&') {
+ int len;
+ name++;
+ len = xmlStrlen(name);
+ if (name[len - 1] == ';')
+ cur->name = xmlStrndup(name, len - 1);
+ else
+ cur->name = xmlStrndup(name, len);
+ } else
+ cur->name = xmlStrdup(name);
+ cur->ns = NULL;
+ cur->nsDef = NULL;
+
+ ent = xmlGetDocEntity(doc, cur->name);
+ if (ent != NULL)
+ cur->content = ent->content;
+ else
+ cur->content = NULL;
+ return(cur);
+}
+
+/**
* xmlNewDocText:
* @doc: the document
* @content: the text content
@@ -559,7 +772,7 @@
}
/**
- * xmlNewText:
+ * xmlNewTextLen:
* @content: the text content
* @len: the text len.
*
@@ -676,7 +889,8 @@
*
*
* Creation of a new child element, added at the end of @parent childs list.
- * @ns and @content parameters are optionnal (NULL).
+ * @ns and @content parameters are optionnal (NULL). If content is non NULL,
+ * a child list containing the TEXTs and ENTITY_REFs node will be created.
* return values: a pointer to the new node object.
*/
xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
@@ -697,18 +911,15 @@
* Allocate a new node
*/
if (ns == NULL)
- cur = xmlNewNode(parent->ns, name, content);
+ cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
else
- cur = xmlNewNode(ns, name, content);
+ cur = xmlNewDocNode(parent->doc, ns, name, content);
if (cur == NULL) return(NULL);
/*
* add the new element at the end of the childs list.
*/
- if (content == NULL)
- cur->type = XML_ELEMENT_NODE;
- else
- cur->type = XML_TEXT_NODE;
+ cur->type = XML_ELEMENT_NODE;
cur->parent = parent;
cur->doc = parent->doc;
if (parent->childs == NULL) {
@@ -754,6 +965,23 @@
*/
cur->parent = parent;
cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
+ /*
+ * Handle the case where parent->content != NULL, in that case it will
+ * create a intermediate TEXT node.
+ */
+ if (parent->content != NULL) {
+ xmlNodePtr text;
+
+ text = xmlNewDocText(parent->doc, parent->content);
+ if (text != NULL) {
+ text->next = parent->childs;
+ if (text->next != NULL)
+ text->next->prev = text;
+ parent->childs = text;
+ free(parent->content);
+ parent->content = NULL;
+ }
+ }
if (parent->childs == NULL) {
parent->childs = cur;
} else {
@@ -824,9 +1052,14 @@
fprintf(stderr, "xmlFreeNode : node == NULL\n");
return;
}
- if (cur->properties != NULL) xmlFreePropList(cur->properties);
+ cur->doc = NULL;
+ cur->parent = NULL;
+ cur->next = NULL;
+ cur->prev = NULL;
if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
- if (cur->content != NULL) free(cur->content);
+ if (cur->properties != NULL) xmlFreePropList(cur->properties);
+ if (cur->type != XML_ENTITY_REF_NODE)
+ if (cur->content != NULL) free(cur->content);
if (cur->name != NULL) free((char *) cur->name);
if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
memset(cur, -1, sizeof(xmlNode));
@@ -989,20 +1222,22 @@
* @name: the attribute name
*
* Search and get the value of an attribute associated to a node
+ * This does the entity substitution.
* return values: the attribute value or NULL if not found.
*/
const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
xmlAttrPtr prop = node->properties;
while (prop != NULL) {
- if (!xmlStrcmp(prop->name, name)) return(prop->value);
+ if (!xmlStrcmp(prop->name, name))
+ return(xmlNodeListGetString(node->doc, prop->val, 1));
prop = prop->next;
}
return(NULL);
}
/**
- * xmlGetProp:
+ * xmlSetProp:
* @node: the node
* @name: the attribute name
* @value: the attribute value
@@ -1015,11 +1250,11 @@
while (prop != NULL) {
if (!xmlStrcmp(prop->name, name)) {
- if (prop->value != NULL)
- free((char *) prop->value);
- prop->value = NULL;
+ if (prop->val != NULL)
+ xmlFreeNode(prop->val);
+ prop->val = NULL;
if (value != NULL)
- prop->value = xmlStrdup(value);
+ prop->val = xmlStringGetNodeList(node->doc, value);
return(prop);
}
prop = prop->next;
@@ -1267,16 +1502,20 @@
* Dump an XML attribute
*/
static void xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
+ CHAR *value;
+
if (cur == NULL) {
fprintf(stderr, "xmlAttrDump : property == NULL\n");
return;
}
xmlBufferWriteChar(" ");
xmlBufferWriteCHAR(cur->name);
- if (cur->value) {
+ value = xmlNodeListGetString(doc, cur->val, 0);
+ if (value) {
xmlBufferWriteChar("=\"");
- xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->value));
+ xmlBufferWriteCHAR(value);
xmlBufferWriteChar("\"");
+ free(value);
}
}
@@ -1309,18 +1548,30 @@
* Dump an XML node list, recursive behaviour,children are printed too.
*/
static void xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
+ int needIndent = 0, i;
+
if (cur == NULL) {
fprintf(stderr, "xmlNodeListDump : node == NULL\n");
return;
}
while (cur != NULL) {
+ if ((cur->type != XML_TEXT_NODE) &&
+ (cur->type != XML_ENTITY_REF_NODE)) {
+ if (!needIndent) {
+ needIndent = 1;
+ xmlBufferWriteChar("\n");
+ }
+ }
xmlNodeDump(doc, cur, level);
cur = cur->next;
}
+ if ((xmlIndentTreeOutput) && (needIndent))
+ for (i = 1;i < level;i++)
+ xmlBufferWriteChar(" ");
}
/**
- * xmlNodeListDump:
+ * xmlNodeDump:
* @doc: the document
* @cur: the current node
* @level: the imbrication level for indenting
@@ -1347,6 +1598,12 @@
}
return;
}
+ if (cur->type == XML_ENTITY_REF_NODE) {
+ xmlBufferWriteChar("&");
+ xmlBufferWriteCHAR(cur->name);
+ xmlBufferWriteChar(";");
+ return;
+ }
if (xmlIndentTreeOutput)
for (i = 0;i < level;i++)
xmlBufferWriteChar(" ");
@@ -1371,11 +1628,7 @@
if (cur->content != NULL)
xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
if (cur->childs != NULL) {
- xmlBufferWriteChar("\n");
xmlNodeListDump(doc, cur->childs, level + 1);
- if (xmlIndentTreeOutput)
- for (i = 0;i < level;i++)
- xmlBufferWriteChar(" ");
}
xmlBufferWriteChar("</");
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
@@ -1531,7 +1784,7 @@
gzFile zoutput = NULL;
char mode[15];
#endif
- FILE *output;
+ FILE *output = NULL;
int ret;
#ifdef HAVE_ZLIB_H
@@ -1584,7 +1837,7 @@
doc = xmlNewDoc("1.0");
ns1 = xmlNewNs(doc, "http://www.ietf.org/standards/dav/", "D");
ns2 = xmlNewNs(doc, "http://www.w3.com/standards/z39.50/", "Z");
- doc->root = xmlNewNode(ns1, "multistatus", NULL);
+ doc->root = xmlNewDocNode(doc, ns1, "multistatus", NULL);
tree = xmlNewChild(doc->root, NULL, "response", NULL);
subtree = xmlNewChild(tree, NULL, "prop", NULL);
xmlNewChild(subtree, ns2, "Authors", NULL);