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/ChangeLog b/ChangeLog
index 58a823f..3bc0f47 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Sun Feb 10 12:02:59 CET 2002 Daniel Veillard <daniel@veillard.com>
+
+ * 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
+
Sat Feb 9 23:15:04 CET 2002 Daniel Veillard <daniel@veillard.com>
* python/Makefile.am: seems some version of automake didn't
diff --git a/result/VC/ElementValid4 b/result/VC/ElementValid4
index 9190854..e7a9734 100644
--- a/result/VC/ElementValid4
+++ b/result/VC/ElementValid4
@@ -1,3 +1,3 @@
-./test/VC/ElementValid4:7: validity error: Element c is not declared in doc list of possible childs
+./test/VC/ElementValid4:7: validity error: Element c is not declared in doc list of possible children
<doc> This <b>seems</b> Ok <a/> but this <c>was not declared</c></doc>
^
diff --git a/result/XInclude/docids.xml b/result/XInclude/docids.xml
new file mode 100644
index 0000000..a383e7f
--- /dev/null
+++ b/result/XInclude/docids.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE book [
+<!ELEMENT book (doc)*>
+<!ELEMENT doc (isid)*>
+<!ELEMENT isid EMPTY>
+<!ATTLIST isid myid ID #IMPLIED>
+]>
+<book>
+<doc>
+<isid myid="mine"/>
+<isid myid="dup"/>
+</doc>
+<!-- including another XML document with IDs -->
+<doc>
+<isid myid="dup"/>
+<isid myid="foo"/>
+<isid myid="bar"/>
+</doc>
+</book>
diff --git a/test/XInclude/docs/docids.xml b/test/XInclude/docs/docids.xml
new file mode 100644
index 0000000..7791620
--- /dev/null
+++ b/test/XInclude/docs/docids.xml
@@ -0,0 +1,15 @@
+<!DOCTYPE book [
+<!ELEMENT book (doc*)>
+<!ELEMENT doc (isid*)>
+<!ELEMENT isid EMPTY>
+<!ATTLIST isid myid ID #IMPLIED>
+]>
+<book>
+<doc>
+<isid myid="mine"/>
+<isid myid="dup"/>
+</doc>
+<!-- including another XML document with IDs -->
+<xinclude:include xmlns:xinclude="http://www.w3.org/2001/XInclude"
+ href="../ents/ids.xml"/>
+</book>
diff --git a/test/XInclude/ents/ids.xml b/test/XInclude/ents/ids.xml
new file mode 100644
index 0000000..8193231
--- /dev/null
+++ b/test/XInclude/ents/ids.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (isid*)>
+<!ELEMENT isid EMPTY>
+<!ATTLIST isid myid ID #IMPLIED>
+]>
+<doc>
+<isid myid="dup"/>
+<isid myid="foo"/>
+<isid myid="bar"/>
+</doc>
diff --git a/tree.c b/tree.c
index 4d86c7e..c871dbb 100644
--- a/tree.c
+++ b/tree.c
@@ -2845,6 +2845,21 @@
tmp = tmp->next;
}
}
+ /*
+ * Try to handle IDs
+ */
+ if ((target->doc != NULL) && (cur->doc != NULL) &&
+ (cur->doc->ids != NULL) && (cur->parent != NULL)) {
+ if (xmlIsID(cur->doc, cur->parent, cur)) {
+ xmlChar *id;
+
+ id = xmlNodeListGetString(cur->doc, cur->children, 1);
+ if (id != NULL) {
+ xmlAddID(NULL, target->doc, id, ret);
+ xmlFree(id);
+ }
+ }
+ }
return(ret);
}
diff --git a/valid.c b/valid.c
index 7643aa5..a6434c2 100644
--- a/valid.c
+++ b/valid.c
@@ -1859,7 +1859,8 @@
/*
* The id is already defined in this DTD.
*/
- VERROR(ctxt->userData, "ID %s already defined\n", value);
+ if (ctxt != NULL)
+ VERROR(ctxt->userData, "ID %s already defined\n", value);
xmlFreeID(ret);
return(NULL);
}
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);
}