mirror of
https://github.com/GNOME/libxml2.git
synced 2025-04-06 19:20:23 +08:00
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
This commit is contained in:
parent
1c18e30b46
commit
c5f05ada40
@ -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
|
||||
|
@ -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>
|
||||
^
|
||||
|
19
result/XInclude/docids.xml
Normal file
19
result/XInclude/docids.xml
Normal file
@ -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>
|
15
test/XInclude/docs/docids.xml
Normal file
15
test/XInclude/docs/docids.xml
Normal file
@ -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>
|
10
test/XInclude/ents/ids.xml
Normal file
10
test/XInclude/ents/ids.xml
Normal file
@ -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>
|
15
tree.c
15
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);
|
||||
}
|
||||
|
||||
|
3
valid.c
3
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);
|
||||
}
|
||||
|
383
xinclude.c
383
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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user