fix #68882, cleanup the XInclude copying of node, merge back IDs in the

* tree.c valid.c xinclude.c: fix #68882, cleanup the XInclude
  copying of node, merge back IDs in the target document.
* result/XInclude/docids.xml test/XInclude/docs/docids.xml
  test/XInclude/ents/ids.xml: test case
* result/VC/ElementValid4: output changed due to a typo fix
Daniel
diff --git a/xinclude.c b/xinclude.c
index 3f38b62..dfd90ab 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -332,6 +332,371 @@
 
 /************************************************************************
  *									*
+ *			Node copy with specific semantic		*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXIncludeCopyNode:
+ * @ctxt:  the XInclude context
+ * @target:  the document target
+ * @source:  the document source
+ * @elem:  the element
+ * 
+ * Make a copy of the node while preserving the XInclude semantic
+ * of the Infoset copy
+ */
+static xmlNodePtr
+xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
+	            xmlDocPtr source, xmlNodePtr elem) {
+    xmlNodePtr result = NULL;
+
+    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
+	(elem == NULL))
+	return(NULL);
+    if (elem->type == XML_DTD_NODE)
+	return(NULL);
+    result = xmlDocCopyNode(elem, target, 1);
+    return(result);
+}
+
+/**
+ * xmlXIncludeCopyNodeList:
+ * @ctxt:  the XInclude context
+ * @target:  the document target
+ * @source:  the document source
+ * @elem:  the element list
+ * 
+ * Make a copy of the node list while preserving the XInclude semantic
+ * of the Infoset copy
+ */
+static xmlNodePtr
+xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
+	                xmlDocPtr source, xmlNodePtr elem) {
+    xmlNodePtr cur, res, result = NULL, last = NULL;
+
+    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
+	(elem == NULL))
+	return(NULL);
+    cur = elem;
+    while (cur != NULL) {
+	res = xmlXIncludeCopyNode(ctxt, target, source, cur);
+	if (res != NULL) {
+	    if (result == NULL) {
+		result = last = res;
+	    } else {
+		last->next = res;
+		res->prev = last;
+		last = res;
+	    }
+	}
+	cur = cur->next;
+    }
+    return(result);
+}
+
+/**
+ * xmlXInclueGetNthChild:
+ * @cur:  the node
+ * @no:  the child number
+ *
+ * Returns the @no'th element child of @cur or NULL
+ */
+static xmlNodePtr
+xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
+    int i;
+    if (cur == NULL) 
+	return(cur);
+    cur = cur->children;
+    for (i = 0;i <= no;cur = cur->next) {
+	if (cur == NULL) 
+	    return(cur);
+	if ((cur->type == XML_ELEMENT_NODE) ||
+	    (cur->type == XML_DOCUMENT_NODE) ||
+	    (cur->type == XML_HTML_DOCUMENT_NODE)) {
+	    i++;
+	    if (i == no)
+		break;
+	}
+    }
+    return(cur);
+}
+
+xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
+
+/**
+ * xmlXIncludeCopyRange:
+ * @ctxt:  the XInclude context
+ * @target:  the document target
+ * @source:  the document source
+ * @obj:  the XPointer result from the evaluation.
+ *
+ * Build a node list tree copy of the XPointer result.
+ *
+ * Returns an xmlNodePtr list or NULL.
+ *         the caller has to free the node tree.
+ */
+static xmlNodePtr
+xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
+	                xmlDocPtr source, xmlXPathObjectPtr range) {
+    /* pointers to generated nodes */
+    xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
+    /* pointers to traversal nodes */
+    xmlNodePtr start, cur, end;
+    int index1, index2;
+
+    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
+	(range == NULL))
+	return(NULL);
+    if (range->type != XPATH_RANGE)
+	return(NULL);
+    start = (xmlNodePtr) range->user;
+
+    if (start == NULL)
+	return(NULL);
+    end = range->user2;
+    if (end == NULL)
+	return(xmlDocCopyNode(start, target, 1));
+
+    cur = start;
+    index1 = range->index;
+    index2 = range->index2;
+    while (cur != NULL) {
+	if (cur == end) {
+	    if (cur->type == XML_TEXT_NODE) {
+		const xmlChar *content = cur->content;
+		int len;
+
+		if (content == NULL) {
+		    tmp = xmlNewTextLen(NULL, 0);
+		} else {
+		    len = index2;
+		    if ((cur == start) && (index1 > 1)) {
+			content += (index1 - 1);
+			len -= (index1 - 1);
+			index1 = 0;
+		    } else {
+			len = index2;
+		    }
+		    tmp = xmlNewTextLen(content, len);
+		}
+		/* single sub text node selection */
+		if (list == NULL)
+		    return(tmp);
+		/* prune and return full set */
+		if (last != NULL)
+		    xmlAddNextSibling(last, tmp);
+		else 
+		    xmlAddChild(parent, tmp);
+		return(list);
+	    } else {
+		tmp = xmlDocCopyNode(cur, target, 0);
+		if (list == NULL)
+		    list = tmp;
+		else {
+		    if (last != NULL)
+			xmlAddNextSibling(last, tmp);
+		    else
+			xmlAddChild(parent, tmp);
+		}
+		last = NULL;
+		parent = tmp;
+
+		if (index2 > 1) {
+		    end = xmlXIncludeGetNthChild(cur, index2 - 1);
+		    index2 = 0;
+		}
+		if ((cur == start) && (index1 > 1)) {
+		    cur = xmlXIncludeGetNthChild(cur, index1 - 1);
+		    index1 = 0;
+		} else {
+		    cur = cur->children;
+		}
+		/*
+		 * Now gather the remaining nodes from cur to end
+		 */
+		continue; /* while */
+	    }
+	} else if ((cur == start) &&
+		   (list == NULL) /* looks superfluous but ... */ ) {
+	    if ((cur->type == XML_TEXT_NODE) ||
+		(cur->type == XML_CDATA_SECTION_NODE)) {
+		const xmlChar *content = cur->content;
+
+		if (content == NULL) {
+		    tmp = xmlNewTextLen(NULL, 0);
+		} else {
+		    if (index1 > 1) {
+			content += (index1 - 1);
+		    }
+		    tmp = xmlNewText(content);
+		}
+		last = list = tmp;
+	    } else {
+		if ((cur == start) && (index1 > 1)) {
+		    tmp = xmlDocCopyNode(cur, target, 0);
+		    list = tmp;
+		    parent = tmp;
+		    last = NULL;
+		    cur = xmlXIncludeGetNthChild(cur, index1 - 1);
+		    index1 = 0;
+		    /*
+		     * Now gather the remaining nodes from cur to end
+		     */
+		    continue; /* while */
+		}
+		tmp = xmlDocCopyNode(cur, target, 1);
+		list = tmp;
+		parent = NULL;
+		last = tmp;
+	    }
+	} else {
+	    tmp = NULL;
+	    switch (cur->type) {
+		case XML_DTD_NODE:
+		case XML_ELEMENT_DECL:
+		case XML_ATTRIBUTE_DECL:
+		case XML_ENTITY_NODE:
+		    /* Do not copy DTD informations */
+		    break;
+		case XML_ENTITY_DECL:
+		    /* handle crossing entities -> stack needed */
+		    break;
+		case XML_XINCLUDE_START:
+		case XML_XINCLUDE_END:
+		    /* don't consider it part of the tree content */
+		    break;
+		case XML_ATTRIBUTE_NODE:
+		    /* Humm, should not happen ! */
+		    break;
+		default:
+		    tmp = xmlDocCopyNode(cur, target, 1);
+		    break;
+	    }
+	    if (tmp != NULL) {
+		if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
+		    return(NULL);
+		}
+		if (last != NULL)
+		    xmlAddNextSibling(last, tmp);
+		else {
+		    xmlAddChild(parent, tmp);
+		    last = tmp;
+		}
+	    }
+	}
+	/*
+	 * Skip to next node in document order
+	 */
+	if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
+	    return(NULL);
+	}
+	cur = xmlXPtrAdvanceNode(cur);
+    }
+    return(list);
+}
+
+/**
+ * xmlXIncludeBuildNodeList:
+ * @ctxt:  the XInclude context
+ * @target:  the document target
+ * @source:  the document source
+ * @obj:  the XPointer result from the evaluation.
+ *
+ * Build a node list tree copy of the XPointer result.
+ * This will drop Attributes and Namespace declarations.
+ *
+ * Returns an xmlNodePtr list or NULL.
+ *         the caller has to free the node tree.
+ */
+static xmlNodePtr
+xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
+	                xmlDocPtr source, xmlXPathObjectPtr obj) {
+    xmlNodePtr list = NULL, last = NULL;
+    int i;
+
+    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
+	(obj == NULL))
+	return(NULL);
+    switch (obj->type) {
+        case XPATH_NODESET: {
+	    xmlNodeSetPtr set = obj->nodesetval;
+	    if (set == NULL)
+		return(NULL);
+	    for (i = 0;i < set->nodeNr;i++) {
+		if (set->nodeTab[i] == NULL)
+		    continue;
+		switch (set->nodeTab[i]->type) {
+		    case XML_TEXT_NODE:
+		    case XML_CDATA_SECTION_NODE:
+		    case XML_ELEMENT_NODE:
+		    case XML_ENTITY_REF_NODE:
+		    case XML_ENTITY_NODE:
+		    case XML_PI_NODE:
+		    case XML_COMMENT_NODE:
+		    case XML_DOCUMENT_NODE:
+		    case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_DOCB_ENABLED
+		    case XML_DOCB_DOCUMENT_NODE:
+#endif
+		    case XML_XINCLUDE_START:
+		    case XML_XINCLUDE_END:
+			break;
+		    case XML_ATTRIBUTE_NODE:
+		    case XML_NAMESPACE_DECL:
+		    case XML_DOCUMENT_TYPE_NODE:
+		    case XML_DOCUMENT_FRAG_NODE:
+		    case XML_NOTATION_NODE:
+		    case XML_DTD_NODE:
+		    case XML_ELEMENT_DECL:
+		    case XML_ATTRIBUTE_DECL:
+		    case XML_ENTITY_DECL:
+			continue; /* for */
+		}
+		if (last == NULL)
+		    list = last = xmlXIncludeCopyNode(ctxt, target, source,
+			                              set->nodeTab[i]);
+		else {
+		    xmlAddNextSibling(last,
+			    xmlXIncludeCopyNode(ctxt, target, source,
+				                set->nodeTab[i]));
+		    if (last->next != NULL)
+			last = last->next;
+		}
+	    }
+	    break;
+	}
+	case XPATH_LOCATIONSET: {
+	    xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
+	    if (set == NULL)
+		return(NULL);
+	    for (i = 0;i < set->locNr;i++) {
+		if (last == NULL)
+		    list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
+			                                  set->locTab[i]);
+		else
+		    xmlAddNextSibling(last,
+			    xmlXIncludeCopyXPointer(ctxt, target, source,
+				                    set->locTab[i]));
+		if (last != NULL) {
+		    while (last->next != NULL)
+			last = last->next;
+		}
+	    }
+	    break;
+	}
+	case XPATH_RANGE:
+	    return(xmlXIncludeCopyRange(ctxt, target, source, obj));
+	case XPATH_POINT:
+	    /* points are ignored in XInclude */
+	    break;
+	default:
+	    break;
+    }
+    return(list);
+}
+/************************************************************************
+ *									*
  *			XInclude I/O handling				*
  *									*
  ************************************************************************/
@@ -417,18 +782,8 @@
 	     * the same document */
 	    ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
 	} else {
-	    /* DTD declarations can't be copied from included files */
-	    xmlNodePtr node = doc->children;
-	    while (node != NULL)
-	    {
-		if (node->type == XML_DTD_NODE)
-		{
-		    xmlUnlinkNode(node);
-		    xmlFreeNode(node);
-		}
-		node = node->next;
-	    }
-	    ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
+	    ctxt->repTab[nr] = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
+		                                       doc, doc->children);
 	}
     } else {
 	/*
@@ -530,7 +885,7 @@
 		}
 	    }
 	}
-	ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
+	ctxt->repTab[nr] = xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
 	xmlXPathFreeObject(xptr);
 	xmlXPathFreeContext(xptrctxt);
 	xmlFree(fragment);
@@ -835,6 +1190,8 @@
 
         xmlAddPrevSibling(end, cur);
     }
+
+    
     return(0);
 }