diff --git a/ChangeLog b/ChangeLog index 15040f5b..b40957ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Fri Nov 27 01:36:54 EST 1998 Daniel Veillard + + * entities.[ch], tree.[ch], tester.c: added copy interfaces + for node/trees/documents/... Biggest problem is namespace + support when copying subtrees. + Sun Nov 15 19:59:47 EST 1998 Daniel Veillard * parser.c, entities.c: improve entities and char ref encoding, diff --git a/entities.c b/entities.c index 28a35826..30506cb4 100644 --- a/entities.c +++ b/entities.c @@ -31,6 +31,9 @@ xmlEntitiesTablePtr xmlPredefinedEntities = NULL; /* * A buffer used for converting entities to their equivalent and back. + * + * TODO: remove this, this helps performances but forbid reentrancy in a + * stupid way. */ static int buffer_size = 0; static CHAR *buffer = NULL; @@ -47,7 +50,6 @@ void growBuffer(void) { /* * xmlFreeEntity : clean-up an entity record. */ - void xmlFreeEntity(xmlEntityPtr entity) { if (entity == NULL) return; @@ -63,12 +65,13 @@ void xmlFreeEntity(xmlEntityPtr entity) { } /* - * xmlAddDocEntity : register a new entity for an entities table. + * xmlAddEntity : register a new entity for an entities table. * * TODO !!! We should check here that the combination of type * ExternalID and SystemID is valid. */ -static void xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type, +static void +xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type, const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) { int i; xmlEntityPtr cur; @@ -116,8 +119,10 @@ static void xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type, table->nb_entities++; } -/* - * Set up xmlPredefinedEntities from xmlPredefinedEntityValues. +/** + * xmlInitializePredefinedEntities: + * + * Set up the predefined entities. */ void xmlInitializePredefinedEntities(void) { int i; @@ -165,12 +170,19 @@ xmlGetPredefinedEntity(const CHAR *name) { return(NULL); } - - -/* - * xmlAddDtdEntity : register a new entity for this DTD. +/** + * xmlAddDtdEntity: + * @doc: the document + * @name: the entity name + * @type: the entity type XML_xxx_yyy_ENTITY + * @ExternalID: the entity external ID if available + * @SystemID: the entity system ID if available + * @content: the entity content + * + * Register a new entity for this document DTD. */ -void xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type, +void +xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type, const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) { xmlEntitiesTablePtr table; @@ -186,10 +198,19 @@ void xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type, xmlAddEntity(table, name, type, ExternalID, SystemID, content); } -/* - * xmlAddDocEntity : register a new entity for this document. +/** + * xmlAddDocEntity: + * @doc: the document + * @name: the entity name + * @type: the entity type XML_xxx_yyy_ENTITY + * @ExternalID: the entity external ID if available + * @SystemID: the entity system ID if available + * @content: the entity content + * + * Register a new entity for this document. */ -void xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type, +void +xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type, const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) { xmlEntitiesTablePtr table; @@ -201,11 +222,18 @@ void xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type, xmlAddEntity(doc->entities, name, type, ExternalID, SystemID, content); } -/* - * xmlGetDtdEntity : do an entity lookup in the Dtd entity hash table and - * returns the corrsponding entity, if found, NULL otherwise. +/** + * xmlGetDtdEntity: + * @doc: the document referencing the entity + * @name: the entity name + * + * Do an entity lookup in the Dtd entity hash table and + * returns the corresponding entity, if found. + * + * return values: A pointer to the entity structure or NULL if not found. */ -xmlEntityPtr xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) { +xmlEntityPtr +xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) { int i; xmlEntityPtr cur; xmlEntitiesTablePtr table; @@ -220,12 +248,19 @@ xmlEntityPtr xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) { return(NULL); } -/* - * xmlGetDocEntity : do an entity lookup in the document entity hash table and - * returns the corrsponding entity, otherwise a lookup is done - * in the predefined entities too. +/** + * xmlGetDocEntity: + * @doc: the document referencing the entity + * @name: the entity name + * + * Do an entity lookup in the document entity hash table and + * returns the corrsponding entity, otherwise a lookup is done + * in the predefined entities too. + * + * return values: A pointer to the entity structure or NULL if not found. */ -xmlEntityPtr xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) { +xmlEntityPtr +xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) { int i; xmlEntityPtr cur; xmlEntitiesTablePtr table; @@ -257,15 +292,24 @@ xmlEntityPtr xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) { (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \ (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF))) -/* - * xmlEncodeEntities : do a global encoding of a string, replacing the - * predefined entities and non ASCII values with their - * entities and CharRef counterparts. +/** + * xmlEncodeEntities: + * @doc: the document containing the string + * @input: A string to convert to XML. + * + * Do a global encoding of a string, replacing the predefined entities + * and non ASCII values with their entities and CharRef counterparts. + * * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii * get erroneous. + * + * TODO This routine is not reentrant and this will be changed, the interface + * should not be modified though. + * + * return values: A newly allocated string with the substitution done. */ - -CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) { +CHAR * +xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) { const CHAR *cur = input; CHAR *out = buffer; @@ -363,10 +407,15 @@ CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) { return(buffer); } -/* - * xmlCreateEntitiesTable : create and initialize an enmpty hash table +/** + * xmlCreateEntitiesTable: + * + * create and initialize an empty entities hash table. + * + * return values: the xmlEntitiesTablePtr just created or NULL in case of error. */ -xmlEntitiesTablePtr xmlCreateEntitiesTable(void) { +xmlEntitiesTablePtr +xmlCreateEntitiesTable(void) { xmlEntitiesTablePtr ret; ret = (xmlEntitiesTablePtr) @@ -389,10 +438,14 @@ xmlEntitiesTablePtr xmlCreateEntitiesTable(void) { return(ret); } -/* - * xmlFreeEntitiesTable : clean up and free an entities hash table. +/** + * xmlFreeEntitiesTable: + * @table: An entity table + * + * Deallocate the memory used by an entities hash table. */ -void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) { +void +xmlFreeEntitiesTable(xmlEntitiesTablePtr table) { int i; if (table == NULL) return; @@ -404,10 +457,70 @@ void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) { free(table); } -/* - * Dump the content of an entity table to the document output. +/** + * xmlCopyEntitiesTable: + * @table: An entity table + * + * Build a copy of an entity table. + * + * return values: the new xmlEntitiesTablePtr or NULL in case of error. */ -void xmlDumpEntitiesTable(xmlEntitiesTablePtr table) { +xmlEntitiesTablePtr +xmlCopyEntitiesTable(xmlEntitiesTablePtr table) { + xmlEntitiesTablePtr ret; + xmlEntityPtr cur, ent; + int i; + + ret = (xmlEntitiesTablePtr) malloc(sizeof(xmlEntitiesTable)); + if (ret == NULL) { + fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n"); + return(NULL); + } + ret->table = (xmlEntityPtr) malloc(table->max_entities * + sizeof(xmlEntity)); + if (ret->table == NULL) { + fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n"); + free(ret); + return(NULL); + } + ret->max_entities = table->max_entities; + ret->nb_entities = table->nb_entities; + for (i = 0;i < ret->nb_entities;i++) { + cur = &ret->table[i]; + ent = &table->table[i]; + cur->len = ent->len; + cur->type = ent->type; + if (ent->name != NULL) + cur->name = xmlStrdup(ent->name); + else + cur->name = NULL; + if (ent->ExternalID != NULL) + cur->ExternalID = xmlStrdup(ent->ExternalID); + else + cur->ExternalID = NULL; + if (ent->SystemID != NULL) + cur->SystemID = xmlStrdup(ent->SystemID); + else + cur->SystemID = NULL; + if (ent->content != NULL) + cur->content = xmlStrdup(ent->content); + else + cur->content = NULL; + } + return(ret); +} + +/** + * xmlDumpEntitiesTable: + * @table: An entity table + * + * This will dump the content of the entity table as an XML DTD definition + * + * NOTE: TODO an extra parameter allowing a reentant implementation will + * be added. + */ +void +xmlDumpEntitiesTable(xmlEntitiesTablePtr table) { int i; xmlEntityPtr cur; diff --git a/entities.h b/entities.h index f6b03c3e..0830101e 100644 --- a/entities.h +++ b/entities.h @@ -46,7 +46,7 @@ typedef struct xmlEntity { typedef struct xmlEntitiesTable { int nb_entities; /* number of elements stored */ int max_entities; /* maximum number of elements */ - xmlEntityPtr table; /* the table of entities */ + xmlEntityPtr table; /* the table of entities */ } xmlEntitiesTable, *xmlEntitiesTablePtr; @@ -63,10 +63,12 @@ extern xmlEntityPtr xmlGetDocEntity(xmlDocPtr doc, const CHAR *name); extern xmlEntityPtr xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name); extern CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input); extern xmlEntitiesTablePtr xmlCreateEntitiesTable(void); +extern xmlEntitiesTablePtr xmlCopyEntitiesTable(xmlEntitiesTablePtr table); extern void xmlFreeEntitiesTable(xmlEntitiesTablePtr table); extern void xmlDumpEntitiesTable(xmlEntitiesTablePtr table); extern xmlParserInputPtr xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity); +extern xmlEntitiesTablePtr xmlCopyEntitiesTable(xmlEntitiesTablePtr table); #ifdef __cplusplus } diff --git a/include/libxml/entities.h b/include/libxml/entities.h index f6b03c3e..0830101e 100644 --- a/include/libxml/entities.h +++ b/include/libxml/entities.h @@ -46,7 +46,7 @@ typedef struct xmlEntity { typedef struct xmlEntitiesTable { int nb_entities; /* number of elements stored */ int max_entities; /* maximum number of elements */ - xmlEntityPtr table; /* the table of entities */ + xmlEntityPtr table; /* the table of entities */ } xmlEntitiesTable, *xmlEntitiesTablePtr; @@ -63,10 +63,12 @@ extern xmlEntityPtr xmlGetDocEntity(xmlDocPtr doc, const CHAR *name); extern xmlEntityPtr xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name); extern CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input); extern xmlEntitiesTablePtr xmlCreateEntitiesTable(void); +extern xmlEntitiesTablePtr xmlCopyEntitiesTable(xmlEntitiesTablePtr table); extern void xmlFreeEntitiesTable(xmlEntitiesTablePtr table); extern void xmlDumpEntitiesTable(xmlEntitiesTablePtr table); extern xmlParserInputPtr xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity); +extern xmlEntitiesTablePtr xmlCopyEntitiesTable(xmlEntitiesTablePtr table); #ifdef __cplusplus } diff --git a/include/libxml/tree.h b/include/libxml/tree.h index e3764d8b..3921f7ea 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -155,7 +155,7 @@ typedef struct xmlDoc { int standalone; /* standalone document (no external refs) */ struct xmlDtd *dtd; /* the document DTD if available */ struct xmlNs *oldNs; /* Global namespace, the old way */ - void *entities; /* Hash table for general entities if any */ + void *entities; /* Hash table for general entities if any */ struct xmlNode *root; /* the document tree */ } xmlDoc, *xmlDocPtr; @@ -183,6 +183,10 @@ extern xmlAttrPtr xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value); extern void xmlFreePropList(xmlAttrPtr cur); extern void xmlFreeProp(xmlAttrPtr cur); +extern xmlAttrPtr xmlCopyProp(xmlAttrPtr cur); +extern xmlAttrPtr xmlCopyPropList(xmlAttrPtr cur); +extern xmlDtdPtr xmlCopyDtd(xmlDtdPtr dtd); +extern xmlDocPtr xmlCopyDoc(xmlDocPtr doc, int recursive); /* * Creating new nodes @@ -199,6 +203,8 @@ extern xmlNodePtr xmlNewTextLen(const CHAR *content, int len); extern xmlNodePtr xmlNewDocComment(xmlDocPtr doc, CHAR *content); extern xmlNodePtr xmlNewComment(CHAR *content); extern xmlNodePtr xmlNewReference(xmlDocPtr doc, const CHAR *name); +extern xmlNodePtr xmlCopyNode(xmlNodePtr node, int recursive); +extern xmlNodePtr xmlCopyNodeList(xmlNodePtr node); /* * Navigating @@ -226,6 +232,8 @@ extern xmlNsPtr xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, extern xmlNsPtr xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href); extern void xmlSetNs(xmlNodePtr node, xmlNsPtr ns); +extern xmlNsPtr xmlCopyNamespace(xmlNsPtr cur); +extern xmlNsPtr xmlCopyNamespaceList(xmlNsPtr cur); /* * Changing the content. diff --git a/tester.c b/tester.c index 56d74bea..6830917d 100644 --- a/tester.c +++ b/tester.c @@ -31,6 +31,7 @@ #include "debugXML.h" static int debug = 0; +static int copy = 0; /* * Note: there is a couple of errors introduced on purpose. @@ -63,12 +64,12 @@ static CHAR buffer[] = ************************************************************************/ int treeTest(void) { + xmlDocPtr doc, tmp; + xmlNodePtr tree, subtree; + /* * build a fake XML document */ - xmlDocPtr doc; - xmlNodePtr tree, subtree; - doc = xmlNewDoc("1.0"); doc->root = xmlNewDocNode(doc, NULL, "EXAMPLE", NULL); xmlSetProp(doc->root, "prop1", "gnome is great"); @@ -81,6 +82,15 @@ int treeTest(void) { subtree = xmlNewChild(tree, NULL, "image", NULL); xmlSetProp(subtree, "href", "linus.gif"); + /* + * test intermediate copy if needed. + */ + if (copy) { + tmp = doc; + doc = xmlCopyDoc(doc, 1); + xmlFreeDoc(tmp); + } + /* * print it. */ @@ -94,13 +104,22 @@ int treeTest(void) { } void parseAndPrintFile(char *filename) { - xmlDocPtr doc; + xmlDocPtr doc, tmp; /* * build an XML tree from a string; */ doc = xmlParseFile(filename); + /* + * test intermediate copy if needed. + */ + if (copy) { + tmp = doc; + doc = xmlCopyDoc(doc, 1); + xmlFreeDoc(tmp); + } + /* * print it. */ @@ -116,13 +135,22 @@ void parseAndPrintFile(char *filename) { } void parseAndPrintBuffer(CHAR *buf) { - xmlDocPtr doc; + xmlDocPtr doc, tmp; /* * build an XML tree from a string; */ doc = xmlParseDoc(buf); + /* + * test intermediate copy if needed. + */ + if (copy) { + tmp = doc; + doc = xmlCopyDoc(doc, 1); + xmlFreeDoc(tmp); + } + /* * print it. */ @@ -139,15 +167,21 @@ void parseAndPrintBuffer(CHAR *buf) { int main(int argc, char **argv) { int i; + int files = 0; - if (argc > 1) { - for (i = 1; i < argc ; i++) { - if ((strcmp(argv[i], "-debug")) && (strcmp(argv[i], "--debug"))) - parseAndPrintFile(argv[i]); - else - debug++; + for (i = 1; i < argc ; i++) { + if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug"))) + debug++; + else if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy"))) + copy++; + } + for (i = 1; i < argc ; i++) { + if (argv[i][0] != '-') { + parseAndPrintFile(argv[i]); + files ++; } - } else { + } + if (files == 0) { printf("\nFirst test for the parser, with errors\n"); parseAndPrintBuffer(buffer); printf("\nBuilding a tree from scratch and printing it\n"); diff --git a/tree.c b/tree.c index 9e71b4df..82517752 100644 --- a/tree.c +++ b/tree.c @@ -133,7 +133,7 @@ xmlNewGlobalNs(xmlDocPtr doc, const CHAR *href, const CHAR *prefix) { */ cur = (xmlNsPtr) malloc(sizeof(xmlNs)); if (cur == NULL) { - fprintf(stderr, "xmlNewNs : malloc failed\n"); + fprintf(stderr, "xmlNewGlobalNs : malloc failed\n"); return(NULL); } @@ -234,7 +234,7 @@ xmlNewDtd(xmlDocPtr doc, const CHAR *name, const CHAR *ExternalID, const CHAR *SystemID) { xmlDtdPtr cur; - if (doc->dtd != NULL) { + if ((doc != NULL) && (doc->dtd != NULL)) { fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n", /* !!! */ (char *) name, doc->name, /* !!! */ (char *)doc->dtd->name); } @@ -244,7 +244,7 @@ xmlNewDtd(xmlDocPtr doc, const CHAR *name, */ cur = (xmlDtdPtr) malloc(sizeof(xmlDtd)); if (cur == NULL) { - fprintf(stderr, "xmlNewNs : malloc failed\n"); + fprintf(stderr, "xmlNewDtd : malloc failed\n"); return(NULL); } @@ -262,7 +262,8 @@ xmlNewDtd(xmlDocPtr doc, const CHAR *name, cur->SystemID = NULL; cur->elements = NULL; cur->entities = NULL; - doc->dtd = cur; + if (doc != NULL) + doc->dtd = cur; return(cur); } @@ -349,6 +350,7 @@ xmlFreeDoc(xmlDocPtr cur) { if (cur->encoding != NULL) free((char *) cur->encoding); if (cur->root != NULL) xmlFreeNode(cur->root); if (cur->dtd != NULL) xmlFreeDtd(cur->dtd); + if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs); if (cur->entities != NULL) xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities); memset(cur, -1, sizeof(xmlDoc)); @@ -1270,6 +1272,347 @@ xmlUnlinkNode(xmlNodePtr cur) { cur->parent = NULL; } +/************************************************************************ + * * + * Copy operations * + * * + ************************************************************************/ + +/** + * xmlCopyNamespace: + * @cur: the namespace + * + * Do a copy of the namespace. + * + * Returns: a new xmlNsPtr, or NULL in case of error. + */ +xmlNsPtr +xmlCopyNamespace(xmlNsPtr cur) { + xmlNsPtr ret; + + if (cur == NULL) return(NULL); + switch (cur->type) { + case XML_GLOBAL_NAMESPACE: + ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix); + break; + case XML_LOCAL_NAMESPACE: + ret = xmlNewNs(NULL, cur->href, cur->prefix); + break; + default: + fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type); + return(NULL); + } + return(ret); +} + +/** + * xmlCopyNamespaceList: + * @cur: the first namespace + * + * Do a copy of an namespace list. + * + * Returns: a new xmlNsPtr, or NULL in case of error. + */ +xmlNsPtr +xmlCopyNamespaceList(xmlNsPtr cur) { + xmlNsPtr ret = NULL; + xmlNsPtr p = NULL,q; + + while (cur != NULL) { + q = xmlCopyNamespace(cur); + if (p == NULL) { + ret = p = q; + } else { + p->next = q; + p = q; + } + cur = cur->next; + } + return(ret); +} + +/** + * xmlCopyProp: + * @cur: the attribute + * + * Do a copy of the attribute. + * + * Returns: a new xmlAttrPtr, or NULL in case of error. + */ +xmlAttrPtr +xmlCopyProp(xmlAttrPtr cur) { + xmlAttrPtr ret; + + if (cur == NULL) return(NULL); + if (cur->val != NULL) + ret = xmlNewDocProp(cur->val->doc, cur->name, NULL); + else + ret = xmlNewDocProp(NULL, cur->name, NULL); + if (ret == NULL) return(NULL); + if (cur->val != NULL) + ret->val = xmlCopyNodeList(cur->val); + return(ret); +} + +/** + * xmlCopyPropList: + * @cur: the first attribute + * + * Do a copy of an attribute list. + * + * Returns: a new xmlAttrPtr, or NULL in case of error. + */ +xmlAttrPtr +xmlCopyPropList(xmlAttrPtr cur) { + xmlAttrPtr ret = NULL; + xmlAttrPtr p = NULL,q; + + while (cur != NULL) { + q = xmlCopyProp(cur); + if (p == NULL) { + ret = p = q; + } else { + p->next = q; + p = q; + } + cur = cur->next; + } + return(ret); +} + +/* + * NOTE about the CopyNode operations ! + * + * They are splitted into external and internal parts for one + * tricky reason: namespaces. Doing a direct copy of a node + * say RPM:Copyright without changing the namespace pointer to + * something else can produce stale links. One way to do it is + * to keep a reference counter but this doesn't work as soon + * as one move the element or the subtree out of the scope of + * the existing namespace. The actual solution seems to add + * a copy of the namespace at the top of the copied tree if + * not available in the subtree. + * Hence two functions, the public front-end call the inner ones + */ + +static xmlNodePtr +xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent); + +static xmlNodePtr +xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, + int recursive) { + xmlNodePtr ret; + + if (node == NULL) return(NULL); + /* + * Allocate a new node and fill the fields. + */ + ret = (xmlNodePtr) malloc(sizeof(xmlNode)); + if (ret == NULL) { + fprintf(stderr, "xmlStaticCopyNode : malloc failed\n"); + return(NULL); + } + + ret->type = node->type; + ret->doc = doc; + ret->parent = parent; + ret->next = NULL; + ret->prev = NULL; + ret->childs = NULL; + ret->properties = NULL; + if (node->name != NULL) + ret->name = xmlStrdup(node->name); + else + ret->name = NULL; + ret->ns = NULL; + ret->nsDef = NULL; + if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) + ret->content = xmlStrdup(node->content); + else + ret->content = NULL; +#ifndef WITHOUT_CORBA + ret->_private = NULL; + ret->vepv = NULL; +#endif + if (parent != NULL) + xmlAddChild(parent, ret); + + if (!recursive) return(ret); + if (node->properties != NULL) + ret->properties = xmlCopyPropList(node->properties); + if (node->nsDef != NULL) + ret->nsDef = xmlCopyNamespaceList(node->nsDef); + + if (node->ns != NULL) { + xmlNsPtr ns; + + ns = xmlSearchNs(doc, ret, node->ns->prefix); + if (ns == NULL) { + /* + * Humm, we are copying an element whose namespace is defined + * out of the new tree scope. Search it in the original tree + * and add it at the top of the new tree + */ + ns = xmlSearchNs(node->doc, node, node->ns->prefix); + if (ns != NULL) { + xmlNodePtr root = ret; + + while (root->parent != NULL) root = root->parent; + xmlNewNs(root, ns->href, ns->prefix); + } + } else { + /* + * reference the existing namespace definition in our own tree. + */ + ret->ns = ns; + } + } + if (node->childs != NULL) + ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret); + return(ret); +} + +static xmlNodePtr +xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { + xmlNodePtr ret = NULL; + xmlNodePtr p = NULL,q; + + while (node != NULL) { + q = xmlStaticCopyNode(node, doc, parent, 1); + if (parent == NULL) { + if (ret == NULL) ret = q; + } else { + if (ret == NULL) { + q->prev = NULL; + ret = p = q; + } else { + p->next = q; + q->prev = p; + p = q; + } + } + node = node->next; + } + return(ret); +} + +/** + * xmlCopyNode: + * @node: the node + * @recursive: if 1 do a recursive copy. + * + * Do a copy of the node. + * + * Returns: a new xmlNodePtr, or NULL in case of error. + */ +xmlNodePtr +xmlCopyNode(xmlNodePtr node, int recursive) { + xmlNodePtr ret; + + ret = xmlStaticCopyNode(node, NULL, NULL, recursive); + return(ret); +} + +/** + * xmlCopyNodeList: + * @node: the first node in the list. + * + * Do a recursive copy of the node list. + * + * Returns: a new xmlNodePtr, or NULL in case of error. + */ +xmlNodePtr xmlCopyNodeList(xmlNodePtr node) { + xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL); + return(ret); +} + +/** + * xmlCopyElement: + * @elem: the element + * + * Do a copy of the element definition. + * + * Returns: a new xmlElementPtr, or NULL in case of error. +xmlElementPtr +xmlCopyElement(xmlElementPtr elem) { + xmlElementPtr ret; + + if (elem == NULL) return(NULL); + ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content); + if (ret == NULL) return(NULL); + if (!recursive) return(ret); + if (elem->properties != NULL) + ret->properties = xmlCopyPropList(elem->properties); + + if (elem->nsDef != NULL) + ret->nsDef = xmlCopyNamespaceList(elem->nsDef); + if (elem->childs != NULL) + ret->childs = xmlCopyElementList(elem->childs); + return(ret); +} + */ + +/** + * xmlCopyDtd: + * @dtd: the dtd + * + * Do a copy of the dtd. + * + * Returns: a new xmlDtdPtr, or NULL in case of error. + */ +xmlDtdPtr +xmlCopyDtd(xmlDtdPtr dtd) { + xmlDtdPtr ret; + + if (dtd == NULL) return(NULL); + ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID); + if (ret == NULL) return(NULL); + if (dtd->entities != NULL) + ret->entities = (void *) xmlCopyEntitiesTable( + (xmlEntitiesTablePtr) dtd->entities); + /* + * TODO: support for Element definitions. + */ + return(ret); +} + +/** + * xmlCopyDoc: + * @doc: the document + * @recursive: if 1 do a recursive copy. + * + * Do a copy of the document info. If recursive, the content tree will + * be copied too as well as Dtd, namespaces and entities. + * + * Returns: a new xmlDocPtr, or NULL in case of error. + */ +xmlDocPtr +xmlCopyDoc(xmlDocPtr doc, int recursive) { + xmlDocPtr ret; + + if (doc == NULL) return(NULL); + ret = xmlNewDoc(doc->version); + if (ret == NULL) return(NULL); + if (doc->name != NULL) + ret->name = strdup(doc->name); + if (doc->encoding != NULL) + ret->encoding = xmlStrdup(doc->encoding); + ret->compression = doc->compression; + ret->standalone = doc->standalone; + if (!recursive) return(ret); + + if (doc->dtd != NULL) + ret->dtd = xmlCopyDtd(doc->dtd); + if (doc->entities != NULL) + ret->entities = (void *) xmlCopyEntitiesTable( + (xmlEntitiesTablePtr) doc->entities); + if (doc->oldNs != NULL) + ret->oldNs = xmlCopyNamespaceList(doc->oldNs); + if (doc->root != NULL) + ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL); + return(ret); +} + /************************************************************************ * * * Content access functions * diff --git a/tree.h b/tree.h index e3764d8b..3921f7ea 100644 --- a/tree.h +++ b/tree.h @@ -155,7 +155,7 @@ typedef struct xmlDoc { int standalone; /* standalone document (no external refs) */ struct xmlDtd *dtd; /* the document DTD if available */ struct xmlNs *oldNs; /* Global namespace, the old way */ - void *entities; /* Hash table for general entities if any */ + void *entities; /* Hash table for general entities if any */ struct xmlNode *root; /* the document tree */ } xmlDoc, *xmlDocPtr; @@ -183,6 +183,10 @@ extern xmlAttrPtr xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value); extern void xmlFreePropList(xmlAttrPtr cur); extern void xmlFreeProp(xmlAttrPtr cur); +extern xmlAttrPtr xmlCopyProp(xmlAttrPtr cur); +extern xmlAttrPtr xmlCopyPropList(xmlAttrPtr cur); +extern xmlDtdPtr xmlCopyDtd(xmlDtdPtr dtd); +extern xmlDocPtr xmlCopyDoc(xmlDocPtr doc, int recursive); /* * Creating new nodes @@ -199,6 +203,8 @@ extern xmlNodePtr xmlNewTextLen(const CHAR *content, int len); extern xmlNodePtr xmlNewDocComment(xmlDocPtr doc, CHAR *content); extern xmlNodePtr xmlNewComment(CHAR *content); extern xmlNodePtr xmlNewReference(xmlDocPtr doc, const CHAR *name); +extern xmlNodePtr xmlCopyNode(xmlNodePtr node, int recursive); +extern xmlNodePtr xmlCopyNodeList(xmlNodePtr node); /* * Navigating @@ -226,6 +232,8 @@ extern xmlNsPtr xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, extern xmlNsPtr xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href); extern void xmlSetNs(xmlNodePtr node, xmlNsPtr ns); +extern xmlNsPtr xmlCopyNamespace(xmlNsPtr cur); +extern xmlNsPtr xmlCopyNamespaceList(xmlNsPtr cur); /* * Changing the content.