From c5f05ada4014d6b22266c0ba6f8b72e0979c2383 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Sun, 10 Feb 2002 11:57:22 +0000 Subject: [PATCH] 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 --- ChangeLog | 8 + result/VC/ElementValid4 | 2 +- result/XInclude/docids.xml | 19 ++ test/XInclude/docs/docids.xml | 15 ++ test/XInclude/ents/ids.xml | 10 + tree.c | 15 ++ valid.c | 3 +- xinclude.c | 383 ++++++++++++++++++++++++++++++++-- 8 files changed, 440 insertions(+), 15 deletions(-) create mode 100644 result/XInclude/docids.xml create mode 100644 test/XInclude/docs/docids.xml create mode 100644 test/XInclude/ents/ids.xml diff --git a/ChangeLog b/ChangeLog index 58a823fb..3bc0f47f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Sun Feb 10 12:02:59 CET 2002 Daniel Veillard + + * 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 * python/Makefile.am: seems some version of automake didn't diff --git a/result/VC/ElementValid4 b/result/VC/ElementValid4 index 9190854b..e7a9734a 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 This seems Ok but this was not declared ^ diff --git a/result/XInclude/docids.xml b/result/XInclude/docids.xml new file mode 100644 index 00000000..a383e7fa --- /dev/null +++ b/result/XInclude/docids.xml @@ -0,0 +1,19 @@ + + + + + +]> + + + + + + + + + + + + diff --git a/test/XInclude/docs/docids.xml b/test/XInclude/docs/docids.xml new file mode 100644 index 00000000..77916202 --- /dev/null +++ b/test/XInclude/docs/docids.xml @@ -0,0 +1,15 @@ + + + + +]> + + + + + + + + diff --git a/test/XInclude/ents/ids.xml b/test/XInclude/ents/ids.xml new file mode 100644 index 00000000..81932317 --- /dev/null +++ b/test/XInclude/ents/ids.xml @@ -0,0 +1,10 @@ + + + +]> + + + + + diff --git a/tree.c b/tree.c index 4d86c7e1..c871dbbe 100644 --- a/tree.c +++ b/tree.c @@ -2845,6 +2845,21 @@ xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { 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 7643aa51..a6434c22 100644 --- a/valid.c +++ b/valid.c @@ -1859,7 +1859,8 @@ xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, /* * 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 3f38b623..dfd90abd 100644 --- a/xinclude.c +++ b/xinclude.c @@ -330,6 +330,371 @@ xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) { ctxt->txtNr++; } +/************************************************************************ + * * + * 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 @@ loaded: * 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 @@ loaded: } } } - ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr); + ctxt->repTab[nr] = xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr); xmlXPathFreeObject(xptr); xmlXPathFreeContext(xptrctxt); xmlFree(fragment); @@ -835,6 +1190,8 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { xmlAddPrevSibling(end, cur); } + + return(0); }