- release 1.8.2 - HTML handling improvement - new tree handling functions
- release 1.8.2
- HTML handling improvement
- new tree handling functions
- default namespace on attribute bug fixed
- libxml use for C++ fixed (for good this time !)
Daniel
diff --git a/tree.c b/tree.c
index 86dd6b3..83bed92 100644
--- a/tree.c
+++ b/tree.c
@@ -1578,12 +1578,85 @@
}
/**
+ * xmlAddNextSibling:
+ * @cur: the child node
+ * @elem: the new node
+ *
+ * Add a new element @elem as the next siblings of @cur
+ * If the new element was already inserted in a document it is
+ * first unlinked from its existing context.
+ *
+ * Returns the new element or NULL in case of error.
+ */
+xmlNodePtr
+xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
+ if (cur == NULL) {
+ fprintf(stderr, "xmlAddNextSibling : cur == NULL\n");
+ return(NULL);
+ }
+ if (elem == NULL) {
+ fprintf(stderr, "xmlAddNextSibling : elem == NULL\n");
+ return(NULL);
+ }
+
+ xmlUnlinkNode(elem);
+ elem->doc = cur->doc;
+ elem->parent = cur->parent;
+ elem->next = cur;
+ elem->prev = cur->prev;
+ cur->prev = elem;
+ if (elem->prev != NULL)
+ elem->prev->next = elem;
+ if ((elem->parent != NULL) && (elem->parent->childs == cur))
+ elem->parent->childs = elem;
+ return(elem);
+}
+
+/**
+ * xmlAddPrevSibling:
+ * @cur: the child node
+ * @elem: the new node
+ *
+ * Add a new element @elem as the previous siblings of @cur
+ * If the new element was already inserted in a document it is
+ * first unlinked from its existing context.
+ *
+ * Returns the new element or NULL in case of error.
+ */
+xmlNodePtr
+xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
+ if (cur == NULL) {
+ fprintf(stderr, "xmlAddPrevSibling : cur == NULL\n");
+ return(NULL);
+ }
+ if (elem == NULL) {
+ fprintf(stderr, "xmlAddPrevSibling : elem == NULL\n");
+ return(NULL);
+ }
+
+ xmlUnlinkNode(elem);
+ elem->doc = cur->doc;
+ elem->parent = cur->parent;
+ elem->prev = cur;
+ elem->next = cur->next;
+ cur->next = elem;
+ if (elem->next != NULL)
+ elem->next->prev = elem;
+ if ((elem->parent != NULL) && (elem->parent->last == cur))
+ elem->parent->last = elem;
+ return(elem);
+}
+
+/**
* xmlAddSibling:
* @cur: the child node
* @elem: the new node
*
- * Add a new element to the list of siblings of @cur
- * Returns the element or NULL in case of error.
+ * Add a new element @elem to the list of siblings of @cur
+ * If the new element was already inserted in a document it is
+ * first unlinked from its existing context.
+ *
+ * Returns the new element or NULL in case of error.
*/
xmlNodePtr
xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
@@ -1599,14 +1672,20 @@
return(NULL);
}
- if ((cur->doc != NULL) && (elem->doc != NULL) &&
- (cur->doc != elem->doc)) {
- fprintf(stderr,
- "xmlAddSibling: Elements moved to a different document\n");
+ /*
+ * Constant time is we can rely on the ->parent->last to find
+ * the last sibling.
+ */
+ if ((cur->parent != NULL) &&
+ (cur->parent->childs != NULL) &&
+ (cur->parent->last != NULL) &&
+ (cur->parent->last->next == NULL)) {
+ cur = cur->parent->last;
+ } else {
+ while (cur->next != NULL) cur = cur->next;
}
- while (cur->next != NULL) cur = cur->next;
-
+ xmlUnlinkNode(elem);
if (elem->doc == NULL)
elem->doc = cur->doc; /* the parent may not be linked to a doc ! */
@@ -1784,6 +1863,47 @@
cur->parent = NULL;
}
+/**
+ * xmlReplaceNode:
+ * @old: the old node
+ * @cur: the node
+ *
+ * Unlink the old node from it's current context, prune the new one
+ * at the same place. If cur was already inserted in a document it is
+ * first unlinked from its existing context.
+ *
+ * Returns the old node
+ */
+xmlNodePtr
+xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
+ if (old == NULL) {
+ fprintf(stderr, "xmlReplaceNode : old == NULL\n");
+ return(NULL);
+ }
+ if (cur == NULL) {
+ xmlUnlinkNode(old);
+ return(old);
+ }
+ xmlUnlinkNode(cur);
+ cur->doc = old->doc;
+ cur->parent = old->parent;
+ cur->next = old->next;
+ if (cur->next != NULL)
+ cur->next->prev = cur;
+ cur->prev = old->prev;
+ if (cur->prev != NULL)
+ cur->prev->next = cur;
+ if (cur->parent != NULL) {
+ if (cur->parent->childs == old)
+ cur->parent->childs = cur;
+ if (cur->parent->last == old)
+ cur->parent->last = cur;
+ }
+ old->next = old->prev = NULL;
+ old->parent = NULL;
+ return(old);
+}
+
/************************************************************************
* *
* Copy operations *
@@ -2180,16 +2300,66 @@
}
/**
+ * xmlDocSetRootElement:
+ * @doc: the document
+ * @root: the new document root element
+ *
+ * Set the root element of the document (doc->root is a list
+ * containing possibly comments, PIs, etc ...).
+ *
+ * Returns the old root element if any was found
+ */
+xmlNodePtr
+xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
+ xmlNodePtr old = NULL;
+
+ if (doc == NULL) return(NULL);
+ old = doc->root;
+ while (old != NULL) {
+ if (old->type == XML_ELEMENT_NODE)
+ break;
+ old = old->next;
+ }
+ if (old == NULL) {
+ if (doc->root == NULL) {
+ doc->root = root;
+ } else {
+ xmlAddSibling(doc->root, root);
+ }
+ } else {
+ xmlReplaceNode(old, root);
+ }
+ return(old);
+}
+
+/**
* xmlNodeSetLang:
* @cur: the node being changed
* @lang: the langage description
*
- * Searches the language of a node, i.e. the values of the xml:lang
- * attribute or the one carried by the nearest ancestor.
+ * Set the language of a node, i.e. the values of the xml:lang
+ * attribute.
*/
void
xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
- /* TODO xmlNodeSetLang check against the production [33] LanguageID */
+ if (cur == NULL) return;
+ switch(cur->type) {
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_COMMENT_NODE:
+ case XML_DOCUMENT_NODE:
+ case XML_DOCUMENT_TYPE_NODE:
+ case XML_DOCUMENT_FRAG_NODE:
+ case XML_NOTATION_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ return;
+ case XML_ELEMENT_NODE:
+ case XML_ATTRIBUTE_NODE:
+ case XML_PI_NODE:
+ case XML_ENTITY_REF_NODE:
+ case XML_ENTITY_NODE:
+ break;
+ }
xmlSetProp(cur, BAD_CAST "xml:lang", lang);
}
@@ -2217,6 +2387,39 @@
}
/**
+ * xmlNodeSetName:
+ * @cur: the node being changed
+ * @name: the new tag name
+ *
+ * Searches the language of a node, i.e. the values of the xml:lang
+ * attribute or the one carried by the nearest ancestor.
+ */
+void
+xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
+ if (cur == NULL) return;
+ if (name == NULL) return;
+ switch(cur->type) {
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_COMMENT_NODE:
+ case XML_DOCUMENT_NODE:
+ case XML_DOCUMENT_TYPE_NODE:
+ case XML_DOCUMENT_FRAG_NODE:
+ case XML_NOTATION_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ return;
+ case XML_ELEMENT_NODE:
+ case XML_ATTRIBUTE_NODE:
+ case XML_PI_NODE:
+ case XML_ENTITY_REF_NODE:
+ case XML_ENTITY_NODE:
+ break;
+ }
+ if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
+ cur->name = xmlStrdup(name);
+}
+
+/**
* xmlNodeGetBase:
* @doc: the document the node pertains to
* @cur: the node being checked
@@ -2787,8 +2990,17 @@
if (namespace == NULL)
return(xmlGetProp(node, name));
while (prop != NULL) {
+ /*
+ * One need to have
+ * - same attribute names
+ * - and the attribute carrying that namespace
+ * or
+ * no namespace on the attribute and the element carrying it
+ */
if ((!xmlStrcmp(prop->name, name)) &&
- (prop->ns != NULL) && (!xmlStrcmp(prop->ns->href, namespace))) {
+ (((prop->ns == NULL) && (node->ns != NULL) &&
+ (!xmlStrcmp(node->ns->href, namespace))) ||
+ (prop->ns != NULL) && (!xmlStrcmp(prop->ns->href, namespace)))) {
xmlChar *ret;
ret = xmlNodeListGetString(node->doc, prop->val, 1);