summaryrefslogtreecommitdiff
path: root/tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'tree.c')
-rw-r--r--tree.c1698
1 files changed, 1153 insertions, 545 deletions
diff --git a/tree.c b/tree.c
index f607688..8a6b63a 100644
--- a/tree.c
+++ b/tree.c
@@ -119,6 +119,9 @@ static int xmlCheckDTD = 1;
(n)->last = ulccur; \
}}
+#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
+ (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
+
/* #define DEBUG_BUFFER */
/* #define DEBUG_TREE */
@@ -1982,7 +1985,6 @@ xmlFreeProp(xmlAttrPtr cur) {
xmlFree(cur);
}
-#ifdef LIBXML_TREE_ENABLED
/**
* xmlRemoveProp:
* @cur: an attribute
@@ -2033,7 +2035,6 @@ xmlRemoveProp(xmlAttrPtr cur) {
#endif
return(-1);
}
-#endif /* LIBXML_TREE_ENABLED */
/**
* xmlNewDocPI:
@@ -2803,6 +2804,55 @@ xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
#endif /* LIBXML_TREE_ENABLED */
/**
+ * xmlAddPropSibling:
+ * @prev: the attribute to which @prop is added after
+ * @cur: the base attribute passed to calling function
+ * @prop: the new attribute
+ *
+ * Add a new attribute after @prev using @cur as base attribute.
+ * When inserting before @cur, @prev is passed as @cur->prev.
+ * When inserting after @cur, @prev is passed as @cur.
+ * If an existing attribute is found it is detroyed prior to adding @prop.
+ *
+ * Returns the attribute being inserted or NULL in case of error.
+ */
+static xmlNodePtr
+xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
+ xmlAttrPtr attr;
+
+ if (cur->type != XML_ATTRIBUTE_NODE)
+ return(NULL);
+
+ /* check if an attribute with the same name exists */
+ if (prop->ns == NULL)
+ attr = xmlHasNsProp(cur->parent, prop->name, NULL);
+ else
+ attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
+
+ if (prop->doc != cur->doc) {
+ xmlSetTreeDoc(prop, cur->doc);
+ }
+ prop->parent = cur->parent;
+ prop->prev = prev;
+ if (prev != NULL) {
+ prop->next = prev->next;
+ prev->next = prop;
+ if (prop->next)
+ prop->next->prev = prop;
+ } else {
+ prop->next = cur;
+ cur->prev = prop;
+ }
+ if (prop->prev == NULL && prop->parent != NULL)
+ prop->parent->properties = (xmlAttrPtr) prop;
+ if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
+ /* different instance, destroy it (attributes must be unique) */
+ xmlRemoveProp((xmlAttrPtr) attr);
+ }
+ return prop;
+}
+
+/**
* xmlAddNextSibling:
* @cur: the child node
* @elem: the new node
@@ -2861,21 +2911,7 @@ xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
return(cur->next);
}
} else if (elem->type == XML_ATTRIBUTE_NODE) {
- /* check if an attribute with the same name exists */
- xmlAttrPtr attr;
-
- if (cur->type != XML_ATTRIBUTE_NODE)
- return(NULL);
- if (elem->ns == NULL)
- attr = xmlHasNsProp(cur->parent, elem->name, NULL);
- else
- attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
- /* elem has already been unlinked so can never be attr */
- if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
- /* different instance, destroy it (attributes must be unique) */
- xmlUnlinkNode((xmlNodePtr) attr);
- xmlFreeProp(attr);
- }
+ return xmlAddPropSibling(cur, cur, elem);
}
if (elem->doc != cur->doc) {
@@ -2887,7 +2923,7 @@ xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
cur->next = elem;
if (elem->next != NULL)
elem->next->prev = elem;
- if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
+ if ((elem->parent != NULL) && (elem->parent->last == cur))
elem->parent->last = elem;
return(elem);
}
@@ -2953,21 +2989,7 @@ xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
return(cur->prev);
}
} else if (elem->type == XML_ATTRIBUTE_NODE) {
- /* check if an attribute with the same name exists */
- xmlAttrPtr attr;
-
- if (cur->type != XML_ATTRIBUTE_NODE)
- return(NULL);
- if (elem->ns == NULL)
- attr = xmlHasNsProp(cur->parent, elem->name, NULL);
- else
- attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
- /* elem has already been unlinked so can never be attr */
- if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
- /* different instance, destroy it (attributes must be unique) */
- xmlUnlinkNode((xmlNodePtr) attr);
- xmlFreeProp(attr);
- }
+ return xmlAddPropSibling(cur->prev, cur, elem);
}
if (elem->doc != cur->doc) {
@@ -2979,16 +3001,8 @@ xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
cur->prev = elem;
if (elem->prev != NULL)
elem->prev->next = elem;
- if (elem->parent != NULL) {
- if (elem->type == XML_ATTRIBUTE_NODE) {
- if (elem->parent->properties == (xmlAttrPtr) cur) {
- elem->parent->properties = (xmlAttrPtr) elem;
- }
- } else {
- if (elem->parent->children == cur) {
+ if ((elem->parent != NULL) && (elem->parent->children == cur)) {
elem->parent->children = elem;
- }
- }
}
return(elem);
}
@@ -3030,7 +3044,7 @@ xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
* Constant time is we can rely on the ->parent->last to find
* the last sibling.
*/
- if ((cur->parent != NULL) &&
+ if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
(cur->parent->children != NULL) &&
(cur->parent->last != NULL) &&
(cur->parent->last->next == NULL)) {
@@ -3046,6 +3060,8 @@ xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
xmlNodeAddContent(cur, elem->content);
xmlFreeNode(elem);
return(cur);
+ } else if (elem->type == XML_ATTRIBUTE_NODE) {
+ return xmlAddPropSibling(cur, cur, elem);
}
if (elem->doc != cur->doc) {
@@ -3454,11 +3470,6 @@ xmlUnlinkNode(xmlNodePtr cur) {
xmlNodePtr parent;
parent = cur->parent;
if (cur->type == XML_ATTRIBUTE_NODE) {
- /* If attribute is an ID from subset then remove it */
- if ((((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID) &&
- xmlIsID(parent->doc, parent, (xmlAttrPtr) cur)) {
- xmlRemoveID(cur->doc, (xmlAttrPtr) cur);
- }
if (parent->properties == (xmlAttrPtr) cur)
parent->properties = ((xmlAttrPtr) cur)->next;
} else {
@@ -3532,12 +3543,6 @@ xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
if (cur->type == XML_ATTRIBUTE_NODE) {
if (cur->parent->properties == (xmlAttrPtr)old)
cur->parent->properties = ((xmlAttrPtr) cur);
-
- /* If old attribute is ID and defined in DTD then remove ID */
- if ((((xmlAttrPtr) old)->atype == XML_ATTRIBUTE_ID) &&
- xmlIsID(old->doc, old->parent, (xmlAttrPtr) old)) {
- xmlRemoveID(old->doc, (xmlAttrPtr) old);
- }
} else {
if (cur->parent->children == old)
cur->parent->children = cur;
@@ -4341,21 +4346,26 @@ xmlGetNodePath(xmlNodePtr node)
*/
tmp = cur->prev;
while (tmp != NULL) {
- if ((cur->type == XML_TEXT_NODE) ||
- (cur->type == XML_CDATA_SECTION_NODE))
+ if ((tmp->type == XML_TEXT_NODE) ||
+ (tmp->type == XML_CDATA_SECTION_NODE))
occur++;
tmp = tmp->prev;
}
+ /*
+ * Evaluate if this is the only text- or CDATA-section-node;
+ * if yes, then we'll get "text()", otherwise "text()[1]".
+ */
if (occur == 0) {
tmp = cur->next;
- while (tmp != NULL && occur == 0) {
- if ((tmp->type == XML_TEXT_NODE) ||
- (tmp->type == XML_CDATA_SECTION_NODE))
- occur++;
- tmp = tmp->next;
- }
- if (occur != 0)
- occur = 1;
+ while (tmp != NULL) {
+ if ((tmp->type == XML_TEXT_NODE) ||
+ (tmp->type == XML_CDATA_SECTION_NODE))
+ {
+ occur = 1;
+ break;
+ }
+ tmp = tmp->next;
+ }
} else
occur++;
} else if (cur->type == XML_PI_NODE) {
@@ -5501,6 +5511,11 @@ xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
node->nsDef = cur;
return(cur);
}
+ if (doc == NULL) {
+ doc = node->doc;
+ if (doc == NULL)
+ return(NULL);
+ }
if (doc->oldNs == NULL) {
/*
* Allocate a new Namespace and fill the fields.
@@ -5638,6 +5653,11 @@ xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
node->nsDef = cur;
return (cur);
}
+ if (doc == NULL) {
+ doc = node->doc;
+ if (doc == NULL)
+ return(NULL);
+ }
if (doc->oldNs == NULL) {
/*
* Allocate a new Namespace and fill the fields.
@@ -5951,6 +5971,154 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
}
#endif /* LIBXML_TREE_ENABLED */
+static xmlAttrPtr
+xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
+ const xmlChar *nsName, int useDTD)
+{
+ xmlAttrPtr prop;
+
+ if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
+ return(NULL);
+
+ if (node->properties != NULL) {
+ prop = node->properties;
+ if (nsName == NULL) {
+ /*
+ * We want the attr to be in no namespace.
+ */
+ do {
+ if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
+ return(prop);
+ }
+ prop = prop->next;
+ } while (prop != NULL);
+ } else {
+ /*
+ * We want the attr to be in the specified namespace.
+ */
+ do {
+ if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
+ ((prop->ns->href == nsName) ||
+ xmlStrEqual(prop->ns->href, nsName)))
+ {
+ return(prop);
+ }
+ prop = prop->next;
+ } while (prop != NULL);
+ }
+ }
+
+#ifdef LIBXML_TREE_ENABLED
+ if (! useDTD)
+ return(NULL);
+ /*
+ * Check if there is a default/fixed attribute declaration in
+ * the internal or external subset.
+ */
+ if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
+ xmlDocPtr doc = node->doc;
+ xmlAttributePtr attrDecl = NULL;
+ xmlChar *elemQName, *tmpstr = NULL;
+
+ /*
+ * We need the QName of the element for the DTD-lookup.
+ */
+ if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
+ tmpstr = xmlStrdup(node->ns->prefix);
+ tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
+ tmpstr = xmlStrcat(tmpstr, node->name);
+ if (tmpstr == NULL)
+ return(NULL);
+ elemQName = tmpstr;
+ } else
+ elemQName = (xmlChar *) node->name;
+ if (nsName == NULL) {
+ /*
+ * The common and nice case: Attr in no namespace.
+ */
+ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
+ elemQName, name, NULL);
+ if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
+ attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
+ elemQName, name, NULL);
+ }
+ } else {
+ xmlNsPtr *nsList, *cur;
+
+ /*
+ * The ugly case: Search using the prefixes of in-scope
+ * ns-decls corresponding to @nsName.
+ */
+ nsList = xmlGetNsList(node->doc, node);
+ if (nsList == NULL) {
+ if (tmpstr != NULL)
+ xmlFree(tmpstr);
+ return(NULL);
+ }
+ cur = nsList;
+ while (*cur != NULL) {
+ if (xmlStrEqual((*cur)->href, nsName)) {
+ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
+ name, (*cur)->prefix);
+ if (attrDecl)
+ break;
+ if (doc->extSubset != NULL) {
+ attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
+ name, (*cur)->prefix);
+ if (attrDecl)
+ break;
+ }
+ }
+ cur++;
+ }
+ xmlFree(nsList);
+ }
+ if (tmpstr != NULL)
+ xmlFree(tmpstr);
+ /*
+ * Only default/fixed attrs are relevant.
+ */
+ if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
+ return((xmlAttrPtr) attrDecl);
+ }
+#endif /* LIBXML_TREE_ENABLED */
+ return(NULL);
+}
+
+static xmlChar*
+xmlGetPropNodeValueInternal(xmlAttrPtr prop)
+{
+ if (prop == NULL)
+ return(NULL);
+ if (prop->type == XML_ATTRIBUTE_NODE) {
+ /*
+ * Note that we return at least the empty string.
+ * TODO: Do we really always want that?
+ */
+ if (prop->children != NULL) {
+ if ((prop->children == prop->last) &&
+ ((prop->children->type == XML_TEXT_NODE) ||
+ (prop->children->type == XML_CDATA_SECTION_NODE)))
+ {
+ /*
+ * Optimization for the common case: only 1 text node.
+ */
+ return(xmlStrdup(prop->children->content));
+ } else {
+ xmlChar *ret;
+
+ ret = xmlNodeListGetString(prop->doc, prop->children, 1);
+ if (ret != NULL)
+ return(ret);
+ }
+ }
+ return(xmlStrdup((xmlChar *)""));
+ } else if (prop->type == XML_ATTRIBUTE_DECL) {
+ return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
+ }
+ return(NULL);
+}
+
/**
* xmlHasProp:
* @node: the node
@@ -6020,86 +6188,8 @@ xmlHasProp(xmlNodePtr node, const xmlChar *name) {
*/
xmlAttrPtr
xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
- xmlAttrPtr prop;
-#ifdef LIBXML_TREE_ENABLED
- xmlDocPtr doc;
-#endif /* LIBXML_TREE_ENABLED */
-
- if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
- return(NULL);
-
- prop = node->properties;
- while (prop != NULL) {
- /*
- * One need to have
- * - same attribute names
- * - and the attribute carrying that namespace
- */
- if (xmlStrEqual(prop->name, name)) {
- if (((prop->ns != NULL) &&
- (xmlStrEqual(prop->ns->href, nameSpace))) ||
- ((prop->ns == NULL) && (nameSpace == NULL))) {
- return(prop);
- }
- }
- prop = prop->next;
- }
- if (!xmlCheckDTD) return(NULL);
-
-#ifdef LIBXML_TREE_ENABLED
- /*
- * Check if there is a default declaration in the internal
- * or external subsets
- */
- doc = node->doc;
- if (doc != NULL) {
- if (doc->intSubset != NULL) {
- xmlAttributePtr attrDecl = NULL;
- xmlNsPtr *nsList, *cur;
- xmlChar *ename;
- nsList = xmlGetNsList(node->doc, node);
- if (nsList == NULL)
- return(NULL);
- if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
- ename = xmlStrdup(node->ns->prefix);
- ename = xmlStrcat(ename, BAD_CAST ":");
- ename = xmlStrcat(ename, node->name);
- } else {
- ename = xmlStrdup(node->name);
- }
- if (ename == NULL) {
- xmlFree(nsList);
- return(NULL);
- }
-
- if (nameSpace == NULL) {
- attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
- name, NULL);
- if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
- attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
- name, NULL);
- }
- } else {
- cur = nsList;
- while (*cur != NULL) {
- if (xmlStrEqual((*cur)->href, nameSpace)) {
- attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
- name, (*cur)->prefix);
- if ((attrDecl == NULL) && (doc->extSubset != NULL))
- attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
- name, (*cur)->prefix);
- }
- cur++;
- }
- }
- xmlFree(nsList);
- xmlFree(ename);
- return((xmlAttrPtr) attrDecl);
- }
- }
-#endif /* LIBXML_TREE_ENABLED */
- return(NULL);
+ return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
}
/**
@@ -6120,46 +6210,12 @@ xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
*/
xmlChar *
xmlGetProp(xmlNodePtr node, const xmlChar *name) {
- xmlAttrPtr prop;
- xmlDocPtr doc;
-
- if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
- return(NULL);
+ xmlAttrPtr prop;
- /*
- * Check on the properties attached to the node
- */
- prop = node->properties;
- while (prop != NULL) {
- if (xmlStrEqual(prop->name, name)) {
- xmlChar *ret;
-
- ret = xmlNodeListGetString(node->doc, prop->children, 1);
- if (ret == NULL) return(xmlStrdup((xmlChar *)""));
- return(ret);
- }
- prop = prop->next;
- }
- if (!xmlCheckDTD) return(NULL);
-
- /*
- * Check if there is a default declaration in the internal
- * or external subsets
- */
- doc = node->doc;
- if (doc != NULL) {
- xmlAttributePtr attrDecl;
- if (doc->intSubset != NULL) {
- attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
- if ((attrDecl == NULL) && (doc->extSubset != NULL))
- attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
- if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
- /* return attribute declaration only if a default value is given
- (that includes #FIXED declarations) */
- return(xmlStrdup(attrDecl->defaultValue));
- }
- }
- return(NULL);
+ prop = xmlHasProp(node, name);
+ if (prop == NULL)
+ return(NULL);
+ return(xmlGetPropNodeValueInternal(prop));
}
/**
@@ -6180,44 +6236,11 @@ xmlGetProp(xmlNodePtr node, const xmlChar *name) {
xmlChar *
xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
xmlAttrPtr prop;
- xmlDocPtr doc;
-
- if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
+
+ prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
+ if (prop == NULL)
return(NULL);
- /*
- * Check on the properties attached to the node
- */
- prop = node->properties;
- while (prop != NULL) {
- if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
- xmlChar *ret;
-
- ret = xmlNodeListGetString(node->doc, prop->children, 1);
- if (ret == NULL) return(xmlStrdup((xmlChar *)""));
- return(ret);
- }
- prop = prop->next;
- }
- if (!xmlCheckDTD) return(NULL);
-
- /*
- * Check if there is a default declaration in the internal
- * or external subsets
- */
- doc = node->doc;
- if (doc != NULL) {
- xmlAttributePtr attrDecl;
- if (doc->intSubset != NULL) {
- attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
- if ((attrDecl == NULL) && (doc->extSubset != NULL))
- attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
- if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
- /* return attribute declaration only if a default value is given
- (that includes #FIXED declarations) */
- return(xmlStrdup(attrDecl->defaultValue));
- }
- }
- return(NULL);
+ return(xmlGetPropNodeValueInternal(prop));
}
/**
@@ -6238,58 +6261,11 @@ xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
xmlChar *
xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
xmlAttrPtr prop;
- xmlDocPtr doc;
- xmlNsPtr ns;
- if ((node == NULL) || (node->type != XML_ELEMENT_NODE))
+ prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
+ if (prop == NULL)
return(NULL);
-
- prop = node->properties;
- if (nameSpace == NULL)
- return(xmlGetNoNsProp(node, name));
- while (prop != NULL) {
- /*
- * One need to have
- * - same attribute names
- * - and the attribute carrying that namespace
- */
- if ((xmlStrEqual(prop->name, name)) &&
- ((prop->ns != NULL) &&
- (xmlStrEqual(prop->ns->href, nameSpace)))) {
- xmlChar *ret;
-
- ret = xmlNodeListGetString(node->doc, prop->children, 1);
- if (ret == NULL) return(xmlStrdup((xmlChar *)""));
- return(ret);
- }
- prop = prop->next;
- }
- if (!xmlCheckDTD) return(NULL);
-
- /*
- * Check if there is a default declaration in the internal
- * or external subsets
- */
- doc = node->doc;
- if (doc != NULL) {
- if (doc->intSubset != NULL) {
- xmlAttributePtr attrDecl;
-
- attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
- if ((attrDecl == NULL) && (doc->extSubset != NULL))
- attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
-
- if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
- /*
- * The DTD declaration only allows a prefix search
- */
- ns = xmlSearchNs(doc, node, attrDecl->prefix);
- if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
- return(xmlStrdup(attrDecl->defaultValue));
- }
- }
- }
- return(NULL);
+ return(xmlGetPropNodeValueInternal(prop));
}
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
@@ -6299,25 +6275,19 @@ xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
* @name: the attribute name
*
* Remove an attribute carried by a node.
+ * This handles only attributes in no namespace.
* Returns 0 if successful, -1 if not found
*/
int
xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
xmlAttrPtr prop;
- if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
+ prop = xmlGetPropNodeInternal(node, name, NULL, 0);
+ if (prop == NULL)
return(-1);
- prop = node->properties;
- while (prop != NULL) {
- if ((xmlStrEqual(prop->name, name)) &&
- (prop->ns == NULL)) {
- xmlUnlinkNode((xmlNodePtr) prop);
- xmlFreeProp(prop);
- return(0);
- }
- prop = prop->next;
- }
- return(-1);
+ xmlUnlinkNode((xmlNodePtr) prop);
+ xmlFreeProp(prop);
+ return(0);
}
/**
@@ -6332,24 +6302,13 @@ xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
int
xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
xmlAttrPtr prop;
-
- if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
- return(-1);
- prop = node->properties;
- if (ns == NULL)
- return(xmlUnsetProp(node, name));
- if (ns->href == NULL)
+
+ prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
+ if (prop == NULL)
return(-1);
- while (prop != NULL) {
- if ((xmlStrEqual(prop->name, name)) &&
- (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
- xmlUnlinkNode((xmlNodePtr) prop);
- xmlFreeProp(prop);
- return(0);
- }
- prop = prop->next;
- }
- return(-1);
+ xmlUnlinkNode((xmlNodePtr) prop);
+ xmlFreeProp(prop);
+ return(0);
}
#endif
@@ -6357,16 +6316,19 @@ xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
/**
* xmlSetProp:
* @node: the node
- * @name: the attribute name
+ * @name: the attribute name (a QName)
* @value: the attribute value
*
* Set (or reset) an attribute carried by a node.
+ * If @name has a prefix, then the corresponding
+ * namespace-binding will be used, if in scope; it is an
+ * error it there's no such ns-binding for the prefix in
+ * scope.
* Returns the attribute pointer.
+ *
*/
xmlAttrPtr
xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
- xmlAttrPtr prop;
- xmlDocPtr doc;
int len;
const xmlChar *nqname;
@@ -6385,48 +6347,15 @@ xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
xmlFree(prefix);
if (ns != NULL)
return(xmlSetNsProp(node, ns, nqname, value));
+ /*
+ * If we get a QName and the prefix has no namespace-
+ * binding in scope, then this is an error.
+ * TODO: Previously this falled-back to non-ns handling.
+ * Should we revert this?
+ */
+ return(NULL);
}
-
- doc = node->doc;
- prop = node->properties;
- while (prop != NULL) {
- if ((xmlStrEqual(prop->name, name)) &&
- (prop->ns == NULL)){
- xmlNodePtr oldprop = prop->children;
- int id = xmlIsID(node->doc, node, prop);
-
- if (id == 1)
- xmlRemoveID(node->doc, prop);
- prop->children = NULL;
- prop->last = NULL;
- if (value != NULL) {
- xmlChar *buffer;
- xmlNodePtr tmp;
-
- buffer = xmlEncodeEntitiesReentrant(node->doc, value);
- prop->children = xmlStringGetNodeList(node->doc, buffer);
- prop->last = NULL;
- prop->doc = doc;
- tmp = prop->children;
- while (tmp != NULL) {
- tmp->parent = (xmlNodePtr) prop;
- tmp->doc = doc;
- if (tmp->next == NULL)
- prop->last = tmp;
- tmp = tmp->next;
- }
- xmlFree(buffer);
- }
- if (oldprop != NULL)
- xmlFreeNodeList(oldprop);
- if (id)
- xmlAddID(NULL, node->doc, value, prop);
- return(prop);
- }
- prop = prop->next;
- }
- prop = xmlNewProp(node, name, value);
- return(prop);
+ return(xmlSetNsProp(node, NULL, name, value));
}
/**
@@ -6437,65 +6366,56 @@ xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
* @value: the attribute value
*
* Set (or reset) an attribute carried by a node.
- * The ns structure must be in scope, this is not checked.
+ * The ns structure must be in scope, this is not checked
*
* Returns the attribute pointer.
*/
xmlAttrPtr
xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
- const xmlChar *value) {
+ const xmlChar *value)
+{
xmlAttrPtr prop;
- if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
- return(NULL);
-
- if (ns == NULL)
- return(xmlSetProp(node, name, value));
- if (ns->href == NULL)
+ if (ns && (ns->href == NULL))
return(NULL);
- prop = node->properties;
-
- while (prop != NULL) {
+ prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
+ if (prop != NULL) {
/*
- * One need to have
- * - same attribute names
- * - and the attribute carrying that namespace
- */
- if ((xmlStrEqual(prop->name, name)) &&
- (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
- int id = xmlIsID(node->doc, node, prop);
-
- if (id == 1)
- xmlRemoveID(node->doc, prop);
- if (prop->children != NULL)
- xmlFreeNodeList(prop->children);
- prop->children = NULL;
+ * Modify the attribute's value.
+ */
+ if (prop->atype == XML_ATTRIBUTE_ID) {
+ xmlRemoveID(node->doc, prop);
+ prop->atype = XML_ATTRIBUTE_ID;
+ }
+ if (prop->children != NULL)
+ xmlFreeNodeList(prop->children);
+ prop->children = NULL;
+ prop->last = NULL;
+ prop->ns = ns;
+ if (value != NULL) {
+ xmlChar *buffer;
+ xmlNodePtr tmp;
+
+ buffer = xmlEncodeEntitiesReentrant(node->doc, value);
+ prop->children = xmlStringGetNodeList(node->doc, buffer);
prop->last = NULL;
- prop->ns = ns;
- if (value != NULL) {
- xmlChar *buffer;
- xmlNodePtr tmp;
-
- buffer = xmlEncodeEntitiesReentrant(node->doc, value);
- prop->children = xmlStringGetNodeList(node->doc, buffer);
- prop->last = NULL;
- tmp = prop->children;
- while (tmp != NULL) {
- tmp->parent = (xmlNodePtr) prop;
- if (tmp->next == NULL)
- prop->last = tmp;
- tmp = tmp->next;
- }
- xmlFree(buffer);
- }
- if (id)
- xmlAddID(NULL, node->doc, value, prop);
- return(prop);
- }
- prop = prop->next;
+ tmp = prop->children;
+ while (tmp != NULL) {
+ tmp->parent = (xmlNodePtr) prop;
+ if (tmp->next == NULL)
+ prop->last = tmp;
+ tmp = tmp->next;
+ }
+ xmlFree(buffer);
+ }
+ if (prop->atype == XML_ATTRIBUTE_ID)
+ xmlAddID(NULL, node->doc, value, prop);
+ return(prop);
}
- prop = xmlNewNsProp(node, ns, name, value);
- return(prop);
+ /*
+ * No equal attr found; create a new one.
+ */
+ return(xmlNewPropInternal(node, ns, name, value, 0));
}
#endif /* LIBXML_TREE_ENABLED */
@@ -7291,72 +7211,138 @@ struct xmlNsMapItem {
* depth:
* >= 0 == @node's ns-decls
* -1 == @parent's ns-decls
- * -2 == @parent's out-of-scope ns-decls
- * -3 == the doc->oldNs XML ns-decl
- * -4 == the doc->oldNs storage ns-decls
+ * -2 == the doc->oldNs XML ns-decl
+ * -3 == the doc->oldNs storage ns-decls
+ * -4 == ns-decls provided via custom ns-handling
*/
int depth;
};
+typedef struct xmlNsMap *xmlNsMapPtr;
+struct xmlNsMap {
+ xmlNsMapItemPtr first;
+ xmlNsMapItemPtr last;
+ xmlNsMapItemPtr pool;
+};
+
+#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
+#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
+#define XML_NSMAP_POP(m, i) \
+ i = (m)->last; \
+ (m)->last = (i)->prev; \
+ if ((m)->last == NULL) \
+ (m)->first = NULL; \
+ else \
+ (m)->last->next = NULL; \
+ (i)->next = (m)->pool; \
+ (m)->pool = i;
+
/*
-* xmlTreeAddNsMapItem:
+* xmlDOMWrapNsMapFree:
+* @map: the ns-map
+*
+* Frees the ns-map
+*/
+static void
+xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
+{
+ xmlNsMapItemPtr cur, tmp;
+
+ if (nsmap == NULL)
+ return;
+ cur = nsmap->pool;
+ while (cur != NULL) {
+ tmp = cur;
+ cur = cur->next;
+ xmlFree(tmp);
+ }
+ cur = nsmap->first;
+ while (cur != NULL) {
+ tmp = cur;
+ cur = cur->next;
+ xmlFree(tmp);
+ }
+ xmlFree(nsmap);
+}
+
+/*
+* xmlDOMWrapNsMapAddItem:
* @map: the ns-map
* @cur: the current map entry to append a new entry to
* @oldNs: the old ns-struct
* @newNs: the new ns-struct
* @depth: depth and ns-kind information
*
-* Frees the ns-map
+* Adds an ns-mapping item.
*/
static xmlNsMapItemPtr
-xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map,
- xmlNsMapItemPtr *cur,
- xmlNsPtr oldNs,
- xmlNsPtr newNs,
- int depth)
+xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, /* xmlNsMapItemPtr *cur, */
+ xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
{
xmlNsMapItemPtr ret;
-
- if ((cur != NULL) && (*cur != NULL) && ((*cur)->next != NULL)) {
+ xmlNsMapPtr map;
+
+ if (nsmap == NULL)
+ return(NULL);
+ if ((position != -1) && (position != 0))
+ return(NULL);
+ map = *nsmap;
+
+ if (map == NULL) {
/*
- * Reuse.
+ * Create the ns-map.
*/
- ret = (*cur)->next;
- *cur = ret;
+ map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
+ if (map == NULL) {
+ xmlTreeErrMemory("allocating namespace map");
+ return (NULL);
+ }
+ memset(map, 0, sizeof(struct xmlNsMap));
+ *nsmap = map;
+ }
+
+ if (map->pool != NULL) {
+ /*
+ * Reuse an item from the pool.
+ */
+ ret = map->pool;
+ map->pool = ret->next;
+ memset(ret, 0, sizeof(struct xmlNsMapItem));
} else {
+ /*
+ * Create a new item.
+ */
ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
if (ret == NULL) {
xmlTreeErrMemory("allocating namespace map item");
return (NULL);
}
memset(ret, 0, sizeof(struct xmlNsMapItem));
- if (*map == NULL) {
- /*
- * First ever.
- */
- *map = ret;
- ret->prev = ret;
- if (cur != NULL)
- *cur = ret;
- } else {
- if (cur) {
- /*
- * Append.
- */
- (*cur)->next = ret;
- ret->prev = *cur;
- *cur = ret;
- } else {
- /*
- * Set on first position.
- */
- ret->next = (*map);
- ret->prev = (*map)->prev;
- (*map)->prev = ret;
- *map = ret;
- }
- }
}
+
+ if (map->first == NULL) {
+ /*
+ * First ever.
+ */
+ map->first = ret;
+ map->last = ret;
+ } else if (position == -1) {
+ /*
+ * Append.
+ */
+ ret->prev = map->last;
+ map->last->next = ret;
+ map->last = ret;
+ } else if (position == 0) {
+ /*
+ * Set on first position.
+ */
+ map->first->prev = ret;
+ ret->next = map->first;
+ map->first = ret;
+ } else
+ return(NULL);
+
ret->oldNs = oldNs;
ret->newNs = newNs;
ret->shadowDepth = -1;
@@ -7365,24 +7351,6 @@ xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map,
}
/*
-* xmlTreeFreeNsMap:
-* @map: the ns-map
-*
-* Frees the ns-map
-*/
-static void
-xmlDOMWrapNSNormFreeNsMap(xmlNsMapItemPtr map)
-{
- xmlNsMapItemPtr mi = map, miprev;
-
- while (mi != NULL) {
- miprev = mi;
- mi = mi->next;
- xmlFree(miprev);
- }
-}
-
-/*
* xmlTreeEnsureXMLDecl:
* @doc: the doc
*
@@ -7488,7 +7456,7 @@ xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
/*
*
-* xmlTreeGetInScopeNamespaces:
+* xmlDOMWrapNSNormGatherInScopeNs:
* @map: the namespace map
* @node: the node to start with
*
@@ -7497,7 +7465,7 @@ xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
* Returns 0 on success, -1 on API or internal errors.
*/
static int
-xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
+xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
xmlNodePtr node)
{
xmlNodePtr cur;
@@ -7517,11 +7485,11 @@ xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
ns = cur->nsDef;
do {
shadowed = 0;
- if (*map != NULL) {
+ if (XML_NSMAP_NOTEMPTY(*map)) {
/*
* Skip shadowed prefixes.
*/
- for (mi = *map; mi != NULL; mi = mi->next) {
+ XML_NSMAP_FOREACH(*map, mi) {
if ((ns->prefix == mi->newNs->prefix) ||
xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
shadowed = 1;
@@ -7532,7 +7500,7 @@ xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
/*
* Insert mapping.
*/
- mi = xmlDOMWrapNSNormAddNsMapItem(map, NULL, NULL,
+ mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
ns, XML_TREE_NSMAP_PARENT);
if (mi == NULL)
return (-1);
@@ -7750,7 +7718,7 @@ internal_error:
}
/*
-* xmlSearchNsByHrefStrict:
+* xmlSearchNsByNamespaceStrict:
* @doc: the document
* @node: the start node
* @nsName: the searched namespace name
@@ -7764,8 +7732,9 @@ internal_error:
* and internal errors.
*/
static int
-xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName,
- xmlNsPtr *retNs, int prefixed)
+xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
+ const xmlChar* nsName,
+ xmlNsPtr *retNs, int prefixed)
{
xmlNodePtr cur, prev = NULL, out = NULL;
xmlNsPtr ns, prevns;
@@ -7841,9 +7810,72 @@ xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName,
out = prev;
prev = cur;
}
- } else if ((node->type == XML_ENTITY_REF_NODE) ||
- (node->type == XML_ENTITY_NODE) ||
- (node->type == XML_ENTITY_DECL))
+ } else if ((cur->type == XML_ENTITY_NODE) ||
+ (cur->type == XML_ENTITY_DECL))
+ return (0);
+ cur = cur->parent;
+ } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
+ return (0);
+}
+
+/*
+* xmlSearchNsByPrefixStrict:
+* @doc: the document
+* @node: the start node
+* @prefix: the searched namespace prefix
+* @retNs: the resulting ns-decl
+* @prefixed: if the found ns-decl must have a prefix (for attributes)
+*
+* Dynamically searches for a ns-declaration which matches
+* the given @nsName in the ancestor-or-self axis of @node.
+*
+* Returns 1 if a ns-decl was found, 0 if not and -1 on API
+* and internal errors.
+*/
+static int
+xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
+ const xmlChar* prefix,
+ xmlNsPtr *retNs)
+{
+ xmlNodePtr cur;
+ xmlNsPtr ns;
+
+ if ((doc == NULL) || (node == NULL))
+ return (-1);
+
+ if (retNs)
+ *retNs = NULL;
+ if (IS_STR_XML(prefix)) {
+ if (retNs) {
+ *retNs = xmlTreeEnsureXMLDecl(doc);
+ if (*retNs == NULL)
+ return (-1);
+ }
+ return (1);
+ }
+ cur = node;
+ do {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (cur->nsDef != NULL) {
+ ns = cur->nsDef;
+ do {
+ if ((prefix == ns->prefix) ||
+ xmlStrEqual(prefix, ns->prefix))
+ {
+ /*
+ * Disabled namespaces, e.g. xmlns:abc="".
+ */
+ if (ns->href == NULL)
+ return(0);
+ if (retNs)
+ *retNs = ns;
+ return (1);
+ }
+ ns = ns->next;
+ } while (ns != NULL);
+ }
+ } else if ((cur->type == XML_ENTITY_NODE) ||
+ (cur->type == XML_ENTITY_DECL))
return (0);
cur = cur->parent;
} while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
@@ -7893,7 +7925,7 @@ xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
/*
* Does it shadow ancestor ns-decls?
*/
- if (xmlSearchNs(doc, elem->parent, pref) != NULL)
+ if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
goto ns_next_prefix;
}
ret = xmlNewNs(NULL, nsName, pref);
@@ -7947,8 +7979,8 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
xmlNodePtr elem,
xmlNsPtr ns,
xmlNsPtr *retNs,
- xmlNsMapItemPtr *nsMap,
- xmlNsMapItemPtr *topmi,
+ xmlNsMapPtr *nsMap,
+
int depth,
int ancestorsOnly,
int prefixed)
@@ -7956,18 +7988,14 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
xmlNsMapItemPtr mi;
if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
- (nsMap == NULL) || (topmi == NULL))
+ (nsMap == NULL))
return (-1);
*retNs = NULL;
/*
* Handle XML namespace.
*/
- if ((ns->prefix) &&
- (ns->prefix[0] == 'x') &&
- (ns->prefix[1] == 'm') &&
- (ns->prefix[2] == 'l') &&
- (ns->prefix[3] == 0)) {
+ if (IS_STR_XML(ns->prefix)) {
/*
* Insert XML namespace mapping.
*/
@@ -7980,20 +8008,18 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
* If the search should be done in ancestors only and no
* @elem (the first ancestor) was specified, then skip the search.
*/
- if ((! (ancestorsOnly && (elem == NULL))) &&
- (*nsMap != NULL)) {
-
+ if ((! (ancestorsOnly && (elem == NULL))) && (XML_NSMAP_NOTEMPTY(*nsMap)))
+ {
/*
* Try to find an equal ns-name in in-scope ns-decls.
*/
- for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
-
+ XML_NSMAP_FOREACH(*nsMap, mi) {
if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
/*
- * This should be turned on to gain speed, if one knows
- * that the branch itself was already ns-wellformed and no
- * stale references existed. I.e. it searches in the ancestor
- * axis only.
+ * ancestorsOnly: This should be turned on to gain speed,
+ * if one knows that the branch itself was already
+ * ns-wellformed and no stale references existed.
+ * I.e. it searches in the ancestor axis only.
*/
((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
/* Skip shadowed prefixes. */
@@ -8028,7 +8054,7 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
/*
* Insert mapping.
*/
- if (xmlDOMWrapNSNormAddNsMapItem(nsMap, NULL, ns,
+ if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
tmpns, XML_TREE_NSMAP_DOC) == NULL) {
xmlFreeNs(tmpns);
return (-1);
@@ -8045,8 +8071,8 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
if (*nsMap != NULL) {
/*
* Does it shadow ancestor ns-decls?
- */
- for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
+ */
+ XML_NSMAP_FOREACH(*nsMap, mi) {
if ((mi->depth < depth) &&
(mi->shadowDepth == -1) &&
((ns->prefix == mi->newNs->prefix) ||
@@ -8059,8 +8085,7 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
}
}
}
- if (xmlDOMWrapNSNormAddNsMapItem(nsMap, topmi, ns,
- tmpns, depth) == NULL) {
+ if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
xmlFreeNs(tmpns);
return (-1);
}
@@ -8069,6 +8094,10 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
return (0);
}
+typedef enum {
+ XML_DOM_RECONNS_REMOVEREDUND = 1<<0
+} xmlDOMReconcileNSOptions;
+
/*
* xmlDOMWrapReconcileNamespaces:
* @ctxt: DOM wrapper context, unused at the moment
@@ -8083,19 +8112,25 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
* WARNING: This function is in a experimental state.
*
* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
-*/
+*/
+
int
xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
xmlNodePtr elem,
- int options ATTRIBUTE_UNUSED)
+ int options)
{
int depth = -1, adoptns = 0, parnsdone = 0;
- xmlNsPtr ns;
+ xmlNsPtr ns, prevns;
xmlDocPtr doc;
xmlNodePtr cur, curElem = NULL;
- xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
+ xmlNsMapPtr nsMap = NULL;
+ xmlNsMapItemPtr /* topmi = NULL, */ mi;
/* @ancestorsOnly should be set by an option flag. */
int ancestorsOnly = 0;
+ int optRemoveDedundantNS =
+ ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
+ xmlNsPtr *listRedund = NULL;
+ int sizeRedund = 0, nbRedund = 0, ret, i, j;
if ((elem == NULL) || (elem->doc == NULL) ||
(elem->type != XML_ELEMENT_NODE))
@@ -8113,7 +8148,9 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
* Namespace declarations.
*/
if (cur->nsDef != NULL) {
- for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
+ prevns = NULL;
+ ns = cur->nsDef;
+ while (ns != NULL) {
if (! parnsdone) {
if ((elem->parent) &&
((xmlNodePtr) elem->parent->doc != elem->parent)) {
@@ -8123,11 +8160,41 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
elem->parent) == -1)
goto internal_error;
- if (nsMap != NULL)
- topmi = nsMap->prev;
}
parnsdone = 1;
}
+
+ /*
+ * Lookup the ns ancestor-axis for equal ns-decls in scope.
+ */
+ if (optRemoveDedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
+ XML_NSMAP_FOREACH(nsMap, mi) {
+ if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
+ (mi->shadowDepth == -1) &&
+ ((ns->prefix == mi->newNs->prefix) ||
+ xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
+ ((ns->href == mi->newNs->href) ||
+ xmlStrEqual(ns->href, mi->newNs->href)))
+ {
+ /*
+ * A redundant ns-decl was found.
+ * Add it to the list of redundant ns-decls.
+ */
+ if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
+ &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
+ goto internal_error;
+ /*
+ * Remove the ns-decl from the element-node.
+ */
+ if (prevns)
+ prevns->next = ns->next;
+ else
+ cur->nsDef = ns->next;
+ goto next_ns_decl;
+ }
+ }
+ }
+
/*
* Skip ns-references handling if the referenced
* ns-decl is declared on the same element.
@@ -8137,8 +8204,8 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
/*
* Does it shadow any ns-decl?
*/
- if (nsMap) {
- for (mi = nsMap; mi != topmi->next; mi = mi->next) {
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
+ XML_NSMAP_FOREACH(nsMap, mi) {
if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
(mi->shadowDepth == -1) &&
((ns->prefix == mi->newNs->prefix) ||
@@ -8151,37 +8218,51 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
/*
* Push mapping.
*/
- if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, ns, ns,
+ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
depth) == NULL)
- goto internal_error;
+ goto internal_error;
+
+ prevns = ns;
+next_ns_decl:
+ ns = ns->next;
}
}
if (! adoptns)
goto ns_end;
-
/* No break on purpose. */
case XML_ATTRIBUTE_NODE:
+ /* No ns, no fun. */
if (cur->ns == NULL)
goto ns_end;
+
if (! parnsdone) {
if ((elem->parent) &&
((xmlNodePtr) elem->parent->doc != elem->parent)) {
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
elem->parent) == -1)
goto internal_error;
- if (nsMap != NULL)
- topmi = nsMap->prev;
}
parnsdone = 1;
}
/*
+ * Adjust the reference if this was a redundant ns-decl.
+ */
+ if (listRedund) {
+ for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
+ if (cur->ns == listRedund[j]) {
+ cur->ns = listRedund[++j];
+ break;
+ }
+ }
+ }
+ /*
* Adopt ns-references.
*/
- if (nsMap != NULL) {
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
/*
* Search for a mapping.
*/
- for (mi = nsMap; mi != topmi->next; mi = mi->next) {
+ XML_NSMAP_FOREACH(nsMap, mi) {
if ((mi->shadowDepth == -1) &&
(cur->ns == mi->oldNs)) {
@@ -8195,7 +8276,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
*/
if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
cur->ns, &ns,
- &nsMap, &topmi, depth,
+ &nsMap, depth,
ancestorsOnly,
(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
goto internal_error;
@@ -8214,6 +8295,7 @@ ns_end:
default:
goto next_sibling;
}
+into_content:
if ((cur->type == XML_ELEMENT_NODE) &&
(cur->children != NULL)) {
/*
@@ -8226,36 +8308,51 @@ next_sibling:
if (cur == elem)
break;
if (cur->type == XML_ELEMENT_NODE) {
- if (nsMap != NULL) {
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
/*
* Pop mappings.
*/
- while ((topmi->depth >= 0) && (topmi->depth >= depth))
- topmi = topmi->prev;
+ while ((nsMap->last != NULL) &&
+ (nsMap->last->depth >= depth))
+ {
+ XML_NSMAP_POP(nsMap, mi)
+ }
/*
* Unshadow.
*/
- for (mi = nsMap; mi != topmi->next; mi = mi->next)
+ XML_NSMAP_FOREACH(nsMap, mi) {
if (mi->shadowDepth >= depth)
mi->shadowDepth = -1;
- }
+ }
+ }
depth--;
}
if (cur->next != NULL)
cur = cur->next;
else {
+ if (cur->type == XML_ATTRIBUTE_NODE) {
+ cur = cur->parent;
+ goto into_content;
+ }
cur = cur->parent;
goto next_sibling;
}
} while (cur != NULL);
-
- if (nsMap != NULL)
- xmlDOMWrapNSNormFreeNsMap(nsMap);
- return (0);
+
+ ret = 0;
+ goto exit;
internal_error:
+ ret = -1;
+exit:
+ if (listRedund) {
+ for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
+ xmlFreeNs(listRedund[j]);
+ }
+ xmlFree(listRedund);
+ }
if (nsMap != NULL)
- xmlDOMWrapNSNormFreeNsMap(nsMap);
- return (-1);
+ xmlDOMWrapNsMapFree(nsMap);
+ return (ret);
}
/*
@@ -8264,7 +8361,7 @@ internal_error:
* @sourceDoc: the optional sourceDoc
* @node: the element-node to start with
* @destDoc: the destination doc for adoption
-* @parent: the optional new parent of @node in @destDoc
+* @destParent: the optional new parent of @node in @destDoc
* @options: option flags
*
* Ensures that ns-references point to @destDoc: either to
@@ -8288,8 +8385,9 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
{
int ret = 0;
xmlNodePtr cur, curElem = NULL;
- xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
- xmlNsPtr ns;
+ xmlNsMapPtr nsMap = NULL;
+ xmlNsMapItemPtr mi;
+ xmlNsPtr ns = NULL;
int depth = -1, adoptStr = 1;
/* gather @parent's ns-decls. */
int parnsdone = 0;
@@ -8348,9 +8446,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
*/
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
destParent) == -1)
- goto internal_error;
- if (nsMap != NULL)
- topmi = nsMap->prev;
+ goto internal_error;
}
parnsdone = 1;
}
@@ -8363,9 +8459,8 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
/*
* Does it shadow any ns-decl?
*/
- if (nsMap) {
- for (mi = nsMap; mi != topmi->next;
- mi = mi->next) {
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
+ XML_NSMAP_FOREACH(nsMap, mi) {
if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
(mi->shadowDepth == -1) &&
((ns->prefix == mi->newNs->prefix) ||
@@ -8379,7 +8474,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
/*
* Push mapping.
*/
- if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
+ if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
ns, ns, depth) == NULL)
goto internal_error;
}
@@ -8393,20 +8488,18 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
if (destParent && (ctxt == NULL)) {
if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
destParent) == -1)
- goto internal_error;
- if (nsMap != NULL)
- topmi = nsMap->prev;
+ goto internal_error;
}
parnsdone = 1;
}
/*
* Adopt ns-references.
*/
- if (nsMap != NULL) {
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
/*
* Search for a mapping.
*/
- for (mi = nsMap; mi != topmi->next; mi = mi->next) {
+ XML_NSMAP_FOREACH(nsMap, mi) {
if ((mi->shadowDepth == -1) &&
(cur->ns == mi->oldNs)) {
@@ -8429,7 +8522,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
* Insert mapping if ns is available; it's the users fault
* if not.
*/
- if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
+ if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
goto internal_error;
cur->ns = ns;
@@ -8441,7 +8534,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
/* ns-decls on curElem or on destDoc->oldNs */
destParent ? curElem : NULL,
cur->ns, &ns,
- &nsMap, &topmi, depth,
+ &nsMap, depth,
ancestorsOnly,
/* ns-decls must be prefixed for attributes. */
(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
@@ -8533,18 +8626,22 @@ leave_node:
/*
* TODO: Do we expect nsDefs on XML_XINCLUDE_START?
*/
- if (nsMap != NULL) {
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
/*
* Pop mappings.
*/
- while (topmi->depth >= depth)
- topmi = topmi->prev;
+ while ((nsMap->last != NULL) &&
+ (nsMap->last->depth >= depth))
+ {
+ XML_NSMAP_POP(nsMap, mi)
+ }
/*
* Unshadow.
*/
- for (mi = nsMap; mi != topmi->next; mi = mi->next)
+ XML_NSMAP_FOREACH(nsMap, mi) {
if (mi->shadowDepth >= depth)
mi->shadowDepth = -1;
+ }
}
depth--;
}
@@ -8555,16 +8652,522 @@ leave_node:
goto leave_node;
}
}
+
+ goto exit;
+
+internal_error:
+ ret = -1;
+
+exit:
/*
* Cleanup.
*/
if (nsMap != NULL)
- xmlDOMWrapNSNormFreeNsMap(nsMap);
- return (ret);
+ xmlDOMWrapNsMapFree(nsMap);
+ return(ret);
+}
+
+/*
+* xmlDOMWrapCloneNode:
+* @ctxt: the optional context for custom processing
+* @sourceDoc: the optional sourceDoc
+* @node: the node to start with
+* @resNode: the clone of the given @node
+* @destDoc: the destination doc
+* @destParent: the optional new parent of @node in @destDoc
+* @deep: descend into child if set
+* @options: option flags
+*
+* References of out-of scope ns-decls are remapped to point to @destDoc:
+* 1) If @destParent is given, then nsDef entries on element-nodes are used
+* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
+* This is the case when you have an unliked node and just want to move it
+* to the context of
+*
+* If @destParent is given, it ensures that the tree is namespace
+* wellformed by creating additional ns-decls where needed.
+* Note that, since prefixes of already existent ns-decls can be
+* shadowed by this process, it could break QNames in attribute
+* values or element content.
+* TODO:
+* 1) Support dicts
+* Optimize string adoption for equal or none dicts.
+* 2) XInclude
+* WARNING: This function is in a experimental state and should only be currently
+* only be used to test it.
+*
+* Returns 0 if the operation succeeded,
+* 1 if a node of unsupported (or not yet supported) type was given,
+* -1 on API/internal errors.
+*/
+
+int
+xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
+ xmlDocPtr sourceDoc,
+ xmlNodePtr node,
+ xmlNodePtr *resNode,
+ xmlDocPtr destDoc,
+ xmlNodePtr destParent,
+ int deep,
+ int options ATTRIBUTE_UNUSED)
+{
+ int ret = 0;
+ xmlNodePtr cur, curElem = NULL;
+ xmlNsMapPtr nsMap = NULL;
+ xmlNsMapItemPtr mi;
+ xmlNsPtr ns;
+ int depth = -1;
+ /* int adoptStr = 1; */
+ /* gather @parent's ns-decls. */
+ int parnsdone = 0;
+ /* @ancestorsOnly should be set per option. */
+ int ancestorsOnly = 0;
+ xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
+ xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
+
+ if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
+ return(-1);
+ /*
+ * TODO: Initially we support only element-nodes.
+ */
+ if (node->type != XML_ELEMENT_NODE)
+ return(1);
+ /*
+ * Check node->doc sanity.
+ */
+ if ((node->doc != NULL) && (sourceDoc != NULL) &&
+ (node->doc != sourceDoc)) {
+ /*
+ * Might be an XIncluded node.
+ */
+ return (-1);
+ }
+ if (sourceDoc == NULL)
+ sourceDoc = node->doc;
+ if (sourceDoc == NULL)
+ return (-1);
+
+ *resNode = NULL;
+
+ cur = node;
+ while (cur != NULL) {
+ if (cur->doc != sourceDoc) {
+ /*
+ * We'll assume XIncluded nodes if the doc differs.
+ * TODO: Do we need to reconciliate XIncluded nodes?
+ * TODO: This here returns -1 in this case.
+ */
+ goto internal_error;
+ }
+ /*
+ * Create a new node.
+ */
+ switch (cur->type) {
+ case XML_XINCLUDE_START:
+ case XML_XINCLUDE_END:
+ /* TODO: What to do with XInclude? */
+ goto internal_error;
+ break;
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_ELEMENT_NODE:
+ case XML_DOCUMENT_FRAG_NODE:
+ case XML_ENTITY_REF_NODE:
+ case XML_ENTITY_NODE:
+ case XML_PI_NODE:
+ case XML_COMMENT_NODE:
+ /*
+ * Nodes of xmlNode structure.
+ */
+ clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+ if (clone == NULL) {
+ xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating a node");
+ goto internal_error;
+ }
+ memset(clone, 0, sizeof(xmlNode));
+ /*
+ * Set hierachical links.
+ */
+ if (resultClone != NULL) {
+ clone->parent = parentClone;
+ if (prevClone) {
+ prevClone->next = clone;
+ clone->prev = prevClone;
+ } else
+ parentClone->children = clone;
+ } else
+ resultClone = clone;
+
+ break;
+ case XML_ATTRIBUTE_NODE:
+ /*
+ * Attributes (xmlAttr).
+ */
+ clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
+ if (clone == NULL) {
+ xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating an attr-node");
+ goto internal_error;
+ }
+ memset(clone, 0, sizeof(xmlAttr));
+ /*
+ * Set hierachical links.
+ */
+ if (resultClone != NULL) {
+ clone->parent = parentClone;
+ if (prevClone) {
+ prevClone->next = clone;
+ clone->prev = prevClone;
+ } else
+ parentClone->properties = (xmlAttrPtr) clone;
+ } else
+ resultClone = clone;
+ break;
+ default:
+ /* TODO */
+ goto internal_error;
+ }
+
+ clone->type = cur->type;
+ clone->doc = destDoc;
+
+ if (cur->name == xmlStringText)
+ clone->name = xmlStringText;
+ else if (cur->name == xmlStringTextNoenc)
+ /*
+ * TODO: xmlStringTextNoenc is never assigned to a node
+ * in tree.c.
+ */
+ clone->name = xmlStringTextNoenc;
+ else if (cur->name == xmlStringComment)
+ clone->name = xmlStringComment;
+ else if (cur->name != NULL) {
+ if ((destDoc != NULL) && (destDoc->dict != NULL))
+ clone->name = xmlDictLookup(destDoc->dict, cur->name, -1);
+ else
+ clone->name = xmlStrdup(cur->name);
+ }
+
+ switch (cur->type) {
+ case XML_XINCLUDE_START:
+ case XML_XINCLUDE_END:
+ /*
+ * TODO
+ */
+ return (-1);
+ case XML_ELEMENT_NODE:
+ curElem = cur;
+ depth++;
+ /*
+ * Namespace declarations.
+ */
+ if (cur->nsDef != NULL) {
+ if (! parnsdone) {
+ if (destParent && (ctxt == NULL)) {
+ /*
+ * Gather @parent's in-scope ns-decls.
+ */
+ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
+ destParent) == -1)
+ goto internal_error;
+ }
+ parnsdone = 1;
+ }
+ /*
+ * Clone namespace declarations.
+ */
+ cloneNsDefSlot = &(clone->nsDef);
+ for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
+ /*
+ * Create a new xmlNs.
+ */
+ cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+ if (cloneNs == NULL) {
+ xmlTreeErrMemory("xmlDOMWrapCloneBranch(): "
+ "allocating namespace");
+ return(-1);
+ }
+ memset(cloneNs, 0, sizeof(xmlNs));
+ cloneNs->type = XML_LOCAL_NAMESPACE;
+
+ if (ns->href != NULL)
+ cloneNs->href = xmlStrdup(ns->href);
+ if (ns->prefix != NULL)
+ cloneNs->prefix = xmlStrdup(ns->prefix);
+
+ *cloneNsDefSlot = cloneNs;
+ cloneNsDefSlot = &(cloneNs->next);
+
+ if (ctxt == NULL) {
+ /*
+ * Does it shadow any ns-decl?
+ */
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
+ XML_NSMAP_FOREACH(nsMap, mi) {
+ if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
+ (mi->shadowDepth == -1) &&
+ ((ns->prefix == mi->newNs->prefix) ||
+ xmlStrEqual(ns->prefix,
+ mi->newNs->prefix))) {
+ /*
+ * Mark as shadowed at the current
+ * depth.
+ */
+ mi->shadowDepth = depth;
+ }
+ }
+ }
+ /*
+ * Push mapping.
+ */
+ if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
+ ns, cloneNs, depth) == NULL)
+ goto internal_error;
+ }
+ }
+ }
+ /* cur->ns will be processed further down. */
+ break;
+ case XML_ATTRIBUTE_NODE:
+ /* IDs will be processed further down. */
+ /* cur->ns will be processed further down. */
+ break;
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ if (cur->content)
+ clone->content = xmlStrdup(cur->content);
+ goto leave_node;
+ case XML_ENTITY_NODE:
+ /* TODO: What to do here? */
+ goto leave_node;
+ case XML_ENTITY_REF_NODE:
+ if (sourceDoc != destDoc) {
+ if ((destDoc->intSubset) || (destDoc->extSubset)) {
+ xmlEntityPtr ent;
+ /*
+ * Different doc: Assign new entity-node if available.
+ */
+ ent = xmlGetDocEntity(destDoc, cur->name);
+ if (ent != NULL) {
+ clone->content = ent->content;
+ clone->children = (xmlNodePtr) ent;
+ clone->last = (xmlNodePtr) ent;
+ }
+ }
+ } else {
+ /*
+ * Same doc: Use the current node's entity declaration
+ * and value.
+ */
+ clone->content = cur->content;
+ clone->children = cur->children;
+ clone->last = cur->last;
+ }
+ goto leave_node;
+ case XML_PI_NODE:
+ if (cur->content)
+ clone->content = xmlStrdup(cur->content);
+ goto leave_node;
+ case XML_COMMENT_NODE:
+ if (cur->content)
+ clone->content = xmlStrdup(cur->content);
+ goto leave_node;
+ default:
+ goto internal_error;
+ }
+
+ if (cur->ns == NULL)
+ goto end_ns_reference;
+
+/* handle_ns_reference: */
+ /*
+ ** The following will take care of references to ns-decls ********
+ ** and is intended only for element- and attribute-nodes.
+ **
+ */
+ if (! parnsdone) {
+ if (destParent && (ctxt == NULL)) {
+ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
+ goto internal_error;
+ }
+ parnsdone = 1;
+ }
+ /*
+ * Adopt ns-references.
+ */
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
+ /*
+ * Search for a mapping.
+ */
+ XML_NSMAP_FOREACH(nsMap, mi) {
+ if ((mi->shadowDepth == -1) &&
+ (cur->ns == mi->oldNs)) {
+ /*
+ * This is the nice case: a mapping was found.
+ */
+ clone->ns = mi->newNs;
+ goto end_ns_reference;
+ }
+ }
+ }
+ /*
+ * Start searching for an in-scope ns-decl.
+ */
+ if (ctxt != NULL) {
+ /*
+ * User-defined behaviour.
+ */
+#if 0
+ ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
+#endif
+ /*
+ * Add user's mapping.
+ */
+ if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
+ cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
+ goto internal_error;
+ clone->ns = ns;
+ } else {
+ /*
+ * Aquire a normalized ns-decl and add it to the map.
+ */
+ if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
+ /* ns-decls on curElem or on destDoc->oldNs */
+ destParent ? curElem : NULL,
+ cur->ns, &ns,
+ &nsMap, depth,
+ ancestorsOnly,
+ /* ns-decls must be prefixed for attributes. */
+ (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
+ goto internal_error;
+ clone->ns = ns;
+ }
+
+end_ns_reference:
+
+ /*
+ * Some post-processing.
+ *
+ * Handle ID attributes.
+ */
+ if ((clone->type == XML_ATTRIBUTE_NODE) &&
+ (clone->parent != NULL)) {
+ if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
+
+ xmlChar *idVal;
+
+ idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
+ if (idVal != NULL) {
+ if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
+ /* TODO: error message. */
+ xmlFree(idVal);
+ goto internal_error;
+ }
+ xmlFree(idVal);
+ }
+ }
+ }
+ /*
+ **
+ ** The following will traversing the tree ************************
+ **
+ *
+ * Walk the element's attributes before descending into child-nodes.
+ */
+ if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
+ prevClone = NULL;
+ parentClone = clone;
+ cur = (xmlNodePtr) cur->properties;
+ continue;
+ }
+into_content:
+ /*
+ * Descend into child-nodes.
+ */
+ if (cur->children != NULL) {
+ if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
+ prevClone = NULL;
+ parentClone = clone;
+ cur = cur->children;
+ continue;
+ }
+ }
+
+leave_node:
+ /*
+ * At this point we are done with the node, its content
+ * and an element-nodes's attribute-nodes.
+ */
+ if (cur == node)
+ break;
+ if ((cur->type == XML_ELEMENT_NODE) ||
+ (cur->type == XML_XINCLUDE_START) ||
+ (cur->type == XML_XINCLUDE_END)) {
+ /*
+ * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
+ */
+ if (XML_NSMAP_NOTEMPTY(nsMap)) {
+ /*
+ * Pop mappings.
+ */
+ while ((nsMap->last != NULL) &&
+ (nsMap->last->depth >= depth))
+ {
+ XML_NSMAP_POP(nsMap, mi)
+ }
+ /*
+ * Unshadow.
+ */
+ XML_NSMAP_FOREACH(nsMap, mi) {
+ if (mi->shadowDepth >= depth)
+ mi->shadowDepth = -1;
+ }
+ }
+ depth--;
+ }
+ if (cur->next != NULL) {
+ prevClone = clone;
+ cur = cur->next;
+ } else if (cur->type != XML_ATTRIBUTE_NODE) {
+ /*
+ * Set clone->last.
+ */
+ if (clone->parent != NULL)
+ clone->parent->last = clone;
+ clone = clone->parent;
+ parentClone = clone->parent;
+ /*
+ * Process parent --> next;
+ */
+ cur = cur->parent;
+ goto leave_node;
+ } else {
+ /* This is for attributes only. */
+ clone = clone->parent;
+ parentClone = clone->parent;
+ /*
+ * Process parent-element --> children.
+ */
+ cur = cur->parent;
+ goto into_content;
+ }
+ }
+ goto exit;
+
internal_error:
+ ret = -1;
+
+exit:
+ /*
+ * Cleanup.
+ */
if (nsMap != NULL)
- xmlDOMWrapNSNormFreeNsMap(nsMap);
- return (-1);
+ xmlDOMWrapNsMapFree(nsMap);
+ /*
+ * TODO: Should we try a cleanup of the cloned node in case of a
+ * fatal error?
+ */
+ *resNode = resultClone;
+ return (ret);
}
/*
@@ -8605,8 +9208,7 @@ xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
/* TODO: User defined. */
}
/* XML Namespace. */
- if ((attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') &&
- (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) {
+ if (IS_STR_XML(attr->ns->prefix)) {
ns = xmlTreeEnsureXMLDecl(destDoc);
} else if (destParent == NULL) {
/*
@@ -8617,7 +9219,7 @@ xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
/*
* Declare on @destParent.
*/
- if (xmlSearchNsByHrefStrict(destDoc, destParent, attr->ns->href,
+ if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
&ns, 1) == -1)
goto internal_error;
if (ns == NULL) {
@@ -8697,9 +9299,12 @@ internal_error:
* @destParent: the optional new parent of @node in @destDoc
* @options: option flags
*
-* Ensures that ns-references point to @destDoc: either to
-* elements->nsDef entries if @destParent is given, or to
-* @destDoc->oldNs otherwise.
+* References of out-of scope ns-decls are remapped to point to @destDoc:
+* 1) If @destParent is given, then nsDef entries on element-nodes are used
+* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
+* This is the case when you have an unliked node and just want to move it
+* to the context of
+*
* If @destParent is given, it ensures that the tree is namespace
* wellformed by creating additional ns-decls where needed.
* Note that, since prefixes of already existent ns-decls can be
@@ -8707,7 +9312,10 @@ internal_error:
* values or element content.
* WARNING: This function is in a experimental state.
*
-* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
+* Returns 0 if the operation succeeded,
+* 1 if a node of unsupported type was given,
+* 2 if a node of not yet supported type was given and
+* -1 on API/internal errors.
*/
int
xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
@@ -8716,7 +9324,7 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
xmlDocPtr destDoc,
xmlNodePtr destParent,
int options)
-{
+{
if ((node == NULL) || (destDoc == NULL) ||
((destParent != NULL) && (destParent->doc != destDoc)))
return(-1);
@@ -8744,6 +9352,7 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
case XML_COMMENT_NODE:
break;
case XML_DOCUMENT_FRAG_NODE:
+ /* TODO: Support document-fragment-nodes. */
return (2);
default:
return (1);
@@ -8809,6 +9418,5 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
return (0);
}
-
#define bottom_tree
#include "elfgcchack.h"