blob: 0d36ca996e624a94cae418844fd79a6bc1fe53bb [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
12 */
13
Daniel Veillard34ce8be2002-03-18 19:37:11 +000014#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000015#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000016
Owen Taylor3473f882001-02-23 17:55:21 +000017#include <string.h> /* for memset() only ! */
18
19#ifdef HAVE_CTYPE_H
20#include <ctype.h>
21#endif
22#ifdef HAVE_STDLIB_H
23#include <stdlib.h>
24#endif
25#ifdef HAVE_ZLIB_H
26#include <zlib.h>
27#endif
28
29#include <libxml/xmlmemory.h>
30#include <libxml/tree.h>
31#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000032#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000033#include <libxml/entities.h>
34#include <libxml/valid.h>
35#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000036#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000037#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000038
Daniel Veillard56a4cb82001-03-24 17:00:36 +000039xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
40
41/************************************************************************
42 * *
43 * A few static variables and macros *
44 * *
45 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000046/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000047const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000050 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000051/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000052const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
53
Owen Taylor3473f882001-02-23 17:55:21 +000054static int xmlCompressMode = 0;
55static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000056
Owen Taylor3473f882001-02-23 17:55:21 +000057#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
58 xmlNodePtr ulccur = (n)->children; \
59 if (ulccur == NULL) { \
60 (n)->last = NULL; \
61 } else { \
62 while (ulccur->next != NULL) { \
63 ulccur->parent = (n); \
64 ulccur = ulccur->next; \
65 } \
66 ulccur->parent = (n); \
67 (n)->last = ulccur; \
68}}
69
70/* #define DEBUG_BUFFER */
71/* #define DEBUG_TREE */
72
73/************************************************************************
74 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000075 * Functions to move to entities.c once the *
76 * API freeze is smoothen and they can be made public. *
77 * *
78 ************************************************************************/
79#include <libxml/hash.h>
80
81/**
82 * xmlGetEntityFromDtd:
83 * @dtd: A pointer to the DTD to search
84 * @name: The entity name
85 *
86 * Do an entity lookup in the DTD entity hash table and
87 * return the corresponding entity, if found.
88 *
89 * Returns A pointer to the entity structure or NULL if not found.
90 */
91static xmlEntityPtr
92xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
93 xmlEntitiesTablePtr table;
94
95 if((dtd != NULL) && (dtd->entities != NULL)) {
96 table = (xmlEntitiesTablePtr) dtd->entities;
97 return((xmlEntityPtr) xmlHashLookup(table, name));
98 /* return(xmlGetEntityFromTable(table, name)); */
99 }
100 return(NULL);
101}
102/**
103 * xmlGetParameterEntityFromDtd:
104 * @dtd: A pointer to the DTD to search
105 * @name: The entity name
106 *
107 * Do an entity lookup in the DTD pararmeter entity hash table and
108 * return the corresponding entity, if found.
109 *
110 * Returns A pointer to the entity structure or NULL if not found.
111 */
112static xmlEntityPtr
113xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
114 xmlEntitiesTablePtr table;
115
116 if ((dtd != NULL) && (dtd->pentities != NULL)) {
117 table = (xmlEntitiesTablePtr) dtd->pentities;
118 return((xmlEntityPtr) xmlHashLookup(table, name));
119 /* return(xmlGetEntityFromTable(table, name)); */
120 }
121 return(NULL);
122}
123
124/************************************************************************
125 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000126 * Allocation and deallocation of basic structures *
127 * *
128 ************************************************************************/
129
130/**
131 * xmlSetBufferAllocationScheme:
132 * @scheme: allocation method to use
133 *
134 * Set the buffer allocation method. Types are
135 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
136 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
137 * improves performance
138 */
139void
140xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
141 xmlBufferAllocScheme = scheme;
142}
143
144/**
145 * xmlGetBufferAllocationScheme:
146 *
147 * Types are
148 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
149 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
150 * improves performance
151 *
152 * Returns the current allocation scheme
153 */
154xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000155xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000156 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000157}
158
159/**
160 * xmlNewNs:
161 * @node: the element carrying the namespace
162 * @href: the URI associated
163 * @prefix: the prefix for the namespace
164 *
165 * Creation of a new Namespace. This function will refuse to create
166 * a namespace with a similar prefix than an existing one present on this
167 * node.
168 * We use href==NULL in the case of an element creation where the namespace
169 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000170 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000171 */
172xmlNsPtr
173xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
174 xmlNsPtr cur;
175
176 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
177 return(NULL);
178
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000179 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
180 return(NULL);
181
Owen Taylor3473f882001-02-23 17:55:21 +0000182 /*
183 * Allocate a new Namespace and fill the fields.
184 */
185 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
186 if (cur == NULL) {
187 xmlGenericError(xmlGenericErrorContext,
188 "xmlNewNs : malloc failed\n");
189 return(NULL);
190 }
191 memset(cur, 0, sizeof(xmlNs));
192 cur->type = XML_LOCAL_NAMESPACE;
193
194 if (href != NULL)
195 cur->href = xmlStrdup(href);
196 if (prefix != NULL)
197 cur->prefix = xmlStrdup(prefix);
198
199 /*
200 * Add it at the end to preserve parsing order ...
201 * and checks for existing use of the prefix
202 */
203 if (node != NULL) {
204 if (node->nsDef == NULL) {
205 node->nsDef = cur;
206 } else {
207 xmlNsPtr prev = node->nsDef;
208
209 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
210 (xmlStrEqual(prev->prefix, cur->prefix))) {
211 xmlFreeNs(cur);
212 return(NULL);
213 }
214 while (prev->next != NULL) {
215 prev = prev->next;
216 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
217 (xmlStrEqual(prev->prefix, cur->prefix))) {
218 xmlFreeNs(cur);
219 return(NULL);
220 }
221 }
222 prev->next = cur;
223 }
224 }
225 return(cur);
226}
227
228/**
229 * xmlSetNs:
230 * @node: a node in the document
231 * @ns: a namespace pointer
232 *
233 * Associate a namespace to a node, a posteriori.
234 */
235void
236xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
237 if (node == NULL) {
238#ifdef DEBUG_TREE
239 xmlGenericError(xmlGenericErrorContext,
240 "xmlSetNs: node == NULL\n");
241#endif
242 return;
243 }
244 node->ns = ns;
245}
246
247/**
248 * xmlFreeNs:
249 * @cur: the namespace pointer
250 *
251 * Free up the structures associated to a namespace
252 */
253void
254xmlFreeNs(xmlNsPtr cur) {
255 if (cur == NULL) {
256#ifdef DEBUG_TREE
257 xmlGenericError(xmlGenericErrorContext,
258 "xmlFreeNs : ns == NULL\n");
259#endif
260 return;
261 }
262 if (cur->href != NULL) xmlFree((char *) cur->href);
263 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000264 xmlFree(cur);
265}
266
267/**
268 * xmlFreeNsList:
269 * @cur: the first namespace pointer
270 *
271 * Free up all the structures associated to the chained namespaces.
272 */
273void
274xmlFreeNsList(xmlNsPtr cur) {
275 xmlNsPtr next;
276 if (cur == NULL) {
277#ifdef DEBUG_TREE
278 xmlGenericError(xmlGenericErrorContext,
279 "xmlFreeNsList : ns == NULL\n");
280#endif
281 return;
282 }
283 while (cur != NULL) {
284 next = cur->next;
285 xmlFreeNs(cur);
286 cur = next;
287 }
288}
289
290/**
291 * xmlNewDtd:
292 * @doc: the document pointer
293 * @name: the DTD name
294 * @ExternalID: the external ID
295 * @SystemID: the system ID
296 *
297 * Creation of a new DTD for the external subset. To create an
298 * internal subset, use xmlCreateIntSubset().
299 *
300 * Returns a pointer to the new DTD structure
301 */
302xmlDtdPtr
303xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
304 const xmlChar *ExternalID, const xmlChar *SystemID) {
305 xmlDtdPtr cur;
306
307 if ((doc != NULL) && (doc->extSubset != NULL)) {
308#ifdef DEBUG_TREE
309 xmlGenericError(xmlGenericErrorContext,
310 "xmlNewDtd(%s): document %s already have a DTD %s\n",
311 /* !!! */ (char *) name, doc->name,
312 /* !!! */ (char *)doc->extSubset->name);
313#endif
314 return(NULL);
315 }
316
317 /*
318 * Allocate a new DTD and fill the fields.
319 */
320 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
321 if (cur == NULL) {
322 xmlGenericError(xmlGenericErrorContext,
323 "xmlNewDtd : malloc failed\n");
324 return(NULL);
325 }
326 memset(cur, 0 , sizeof(xmlDtd));
327 cur->type = XML_DTD_NODE;
328
329 if (name != NULL)
330 cur->name = xmlStrdup(name);
331 if (ExternalID != NULL)
332 cur->ExternalID = xmlStrdup(ExternalID);
333 if (SystemID != NULL)
334 cur->SystemID = xmlStrdup(SystemID);
335 if (doc != NULL)
336 doc->extSubset = cur;
337 cur->doc = doc;
338
339 return(cur);
340}
341
342/**
343 * xmlGetIntSubset:
344 * @doc: the document pointer
345 *
346 * Get the internal subset of a document
347 * Returns a pointer to the DTD structure or NULL if not found
348 */
349
350xmlDtdPtr
351xmlGetIntSubset(xmlDocPtr doc) {
352 xmlNodePtr cur;
353
354 if (doc == NULL)
355 return(NULL);
356 cur = doc->children;
357 while (cur != NULL) {
358 if (cur->type == XML_DTD_NODE)
359 return((xmlDtdPtr) cur);
360 cur = cur->next;
361 }
362 return((xmlDtdPtr) doc->intSubset);
363}
364
365/**
366 * xmlCreateIntSubset:
367 * @doc: the document pointer
368 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000369 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000370 * @SystemID: the system ID
371 *
372 * Create the internal subset of a document
373 * Returns a pointer to the new DTD structure
374 */
375xmlDtdPtr
376xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
377 const xmlChar *ExternalID, const xmlChar *SystemID) {
378 xmlDtdPtr cur;
379
380 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
381#ifdef DEBUG_TREE
382 xmlGenericError(xmlGenericErrorContext,
383
384 "xmlCreateIntSubset(): document %s already have an internal subset\n",
385 doc->name);
386#endif
387 return(NULL);
388 }
389
390 /*
391 * Allocate a new DTD and fill the fields.
392 */
393 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
394 if (cur == NULL) {
395 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000396 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000397 return(NULL);
398 }
399 memset(cur, 0, sizeof(xmlDtd));
400 cur->type = XML_DTD_NODE;
401
402 if (name != NULL)
403 cur->name = xmlStrdup(name);
404 if (ExternalID != NULL)
405 cur->ExternalID = xmlStrdup(ExternalID);
406 if (SystemID != NULL)
407 cur->SystemID = xmlStrdup(SystemID);
408 if (doc != NULL) {
409 doc->intSubset = cur;
410 cur->parent = doc;
411 cur->doc = doc;
412 if (doc->children == NULL) {
413 doc->children = (xmlNodePtr) cur;
414 doc->last = (xmlNodePtr) cur;
415 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000416 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000417 xmlNodePtr prev;
418
Owen Taylor3473f882001-02-23 17:55:21 +0000419 prev = doc->children;
420 prev->prev = (xmlNodePtr) cur;
421 cur->next = prev;
422 doc->children = (xmlNodePtr) cur;
423 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000424 xmlNodePtr next;
425
426 next = doc->children;
427 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
428 next = next->next;
429 if (next == NULL) {
430 cur->prev = doc->last;
431 cur->prev->next = (xmlNodePtr) cur;
432 cur->next = NULL;
433 doc->last = (xmlNodePtr) cur;
434 } else {
435 cur->next = next;
436 cur->prev = next->prev;
437 if (cur->prev == NULL)
438 doc->children = (xmlNodePtr) cur;
439 else
440 cur->prev->next = (xmlNodePtr) cur;
441 next->prev = (xmlNodePtr) cur;
442 }
Owen Taylor3473f882001-02-23 17:55:21 +0000443 }
444 }
445 }
446 return(cur);
447}
448
449/**
450 * xmlFreeDtd:
451 * @cur: the DTD structure to free up
452 *
453 * Free a DTD structure.
454 */
455void
456xmlFreeDtd(xmlDtdPtr cur) {
457 if (cur == NULL) {
458#ifdef DEBUG_TREE
459 xmlGenericError(xmlGenericErrorContext,
460 "xmlFreeDtd : DTD == NULL\n");
461#endif
462 return;
463 }
464 if (cur->children != NULL) {
465 xmlNodePtr next, c = cur->children;
466
467 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000468 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000469 * indexes.
470 */
471 while (c != NULL) {
472 next = c->next;
473 if (c->type == XML_COMMENT_NODE) {
474 xmlUnlinkNode(c);
475 xmlFreeNode(c);
476 }
477 c = next;
478 }
479 }
480 if (cur->name != NULL) xmlFree((char *) cur->name);
481 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
482 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
483 /* TODO !!! */
484 if (cur->notations != NULL)
485 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
486
487 if (cur->elements != NULL)
488 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
489 if (cur->attributes != NULL)
490 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
491 if (cur->entities != NULL)
492 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
493 if (cur->pentities != NULL)
494 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
495
Owen Taylor3473f882001-02-23 17:55:21 +0000496 xmlFree(cur);
497}
498
499/**
500 * xmlNewDoc:
501 * @version: xmlChar string giving the version of XML "1.0"
502 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000503 * Creates a new XML document
504 *
Owen Taylor3473f882001-02-23 17:55:21 +0000505 * Returns a new document
506 */
507xmlDocPtr
508xmlNewDoc(const xmlChar *version) {
509 xmlDocPtr cur;
510
511 if (version == NULL)
512 version = (const xmlChar *) "1.0";
513
514 /*
515 * Allocate a new document and fill the fields.
516 */
517 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
518 if (cur == NULL) {
519 xmlGenericError(xmlGenericErrorContext,
520 "xmlNewDoc : malloc failed\n");
521 return(NULL);
522 }
523 memset(cur, 0, sizeof(xmlDoc));
524 cur->type = XML_DOCUMENT_NODE;
525
526 cur->version = xmlStrdup(version);
527 cur->standalone = -1;
528 cur->compression = -1; /* not initialized */
529 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000530 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000531 return(cur);
532}
533
534/**
535 * xmlFreeDoc:
536 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000537 *
538 * Free up all the structures used by a document, tree included.
539 */
540void
541xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000542 xmlDtdPtr extSubset, intSubset;
543
Owen Taylor3473f882001-02-23 17:55:21 +0000544 if (cur == NULL) {
545#ifdef DEBUG_TREE
546 xmlGenericError(xmlGenericErrorContext,
547 "xmlFreeDoc : document == NULL\n");
548#endif
549 return;
550 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000551 /*
552 * Do this before freeing the children list to avoid ID lookups
553 */
554 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
555 cur->ids = NULL;
556 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
557 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000558 extSubset = cur->extSubset;
559 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000560 if (intSubset == extSubset)
561 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000562 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000563 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000564 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000565 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000567 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000569 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000570 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000571 }
572
573 if (cur->children != NULL) xmlFreeNodeList(cur->children);
574
Owen Taylor3473f882001-02-23 17:55:21 +0000575 if (cur->version != NULL) xmlFree((char *) cur->version);
576 if (cur->name != NULL) xmlFree((char *) cur->name);
577 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000578 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000579 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000580 xmlFree(cur);
581}
582
583/**
584 * xmlStringLenGetNodeList:
585 * @doc: the document
586 * @value: the value of the text
587 * @len: the length of the string value
588 *
589 * Parse the value string and build the node list associated. Should
590 * produce a flat tree with only TEXTs and ENTITY_REFs.
591 * Returns a pointer to the first child
592 */
593xmlNodePtr
594xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
595 xmlNodePtr ret = NULL, last = NULL;
596 xmlNodePtr node;
597 xmlChar *val;
598 const xmlChar *cur = value;
599 const xmlChar *q;
600 xmlEntityPtr ent;
601
602 if (value == NULL) return(NULL);
603
604 q = cur;
605 while ((*cur != 0) && (cur - value < len)) {
606 if (*cur == '&') {
607 /*
608 * Save the current text.
609 */
610 if (cur != q) {
611 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
612 xmlNodeAddContentLen(last, q, cur - q);
613 } else {
614 node = xmlNewDocTextLen(doc, q, cur - q);
615 if (node == NULL) return(ret);
616 if (last == NULL)
617 last = ret = node;
618 else {
619 last->next = node;
620 node->prev = last;
621 last = node;
622 }
623 }
624 }
625 /*
626 * Read the entity string
627 */
628 cur++;
629 q = cur;
630 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
631 if ((*cur == 0) || (cur - value >= len)) {
632#ifdef DEBUG_TREE
633 xmlGenericError(xmlGenericErrorContext,
634 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
635#endif
636 return(ret);
637 }
638 if (cur != q) {
639 /*
640 * Predefined entities don't generate nodes
641 */
642 val = xmlStrndup(q, cur - q);
643 ent = xmlGetDocEntity(doc, val);
644 if ((ent != NULL) &&
645 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
646 if (last == NULL) {
647 node = xmlNewDocText(doc, ent->content);
648 last = ret = node;
649 } else
650 xmlNodeAddContent(last, ent->content);
651
652 } else {
653 /*
654 * Create a new REFERENCE_REF node
655 */
656 node = xmlNewReference(doc, val);
657 if (node == NULL) {
658 if (val != NULL) xmlFree(val);
659 return(ret);
660 }
661 if (last == NULL)
662 last = ret = node;
663 else {
664 last->next = node;
665 node->prev = last;
666 last = node;
667 }
668 }
669 xmlFree(val);
670 }
671 cur++;
672 q = cur;
673 } else
674 cur++;
675 }
676 if (cur != q) {
677 /*
678 * Handle the last piece of text.
679 */
680 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
681 xmlNodeAddContentLen(last, q, cur - q);
682 } else {
683 node = xmlNewDocTextLen(doc, q, cur - q);
684 if (node == NULL) return(ret);
685 if (last == NULL)
686 last = ret = node;
687 else {
688 last->next = node;
689 node->prev = last;
690 last = node;
691 }
692 }
693 }
694 return(ret);
695}
696
697/**
698 * xmlStringGetNodeList:
699 * @doc: the document
700 * @value: the value of the attribute
701 *
702 * Parse the value string and build the node list associated. Should
703 * produce a flat tree with only TEXTs and ENTITY_REFs.
704 * Returns a pointer to the first child
705 */
706xmlNodePtr
707xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
708 xmlNodePtr ret = NULL, last = NULL;
709 xmlNodePtr node;
710 xmlChar *val;
711 const xmlChar *cur = value;
712 const xmlChar *q;
713 xmlEntityPtr ent;
714
715 if (value == NULL) return(NULL);
716
717 q = cur;
718 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000719 if (cur[0] == '&') {
720 int charval = 0;
721 xmlChar tmp;
722
Owen Taylor3473f882001-02-23 17:55:21 +0000723 /*
724 * Save the current text.
725 */
726 if (cur != q) {
727 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
728 xmlNodeAddContentLen(last, q, cur - q);
729 } else {
730 node = xmlNewDocTextLen(doc, q, cur - q);
731 if (node == NULL) return(ret);
732 if (last == NULL)
733 last = ret = node;
734 else {
735 last->next = node;
736 node->prev = last;
737 last = node;
738 }
739 }
740 }
Owen Taylor3473f882001-02-23 17:55:21 +0000741 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000742 if ((cur[1] == '#') && (cur[2] == 'x')) {
743 cur += 3;
744 tmp = *cur;
745 while (tmp != ';') { /* Non input consuming loop */
746 if ((tmp >= '0') && (tmp <= '9'))
747 charval = charval * 16 + (tmp - '0');
748 else if ((tmp >= 'a') && (tmp <= 'f'))
749 charval = charval * 16 + (tmp - 'a') + 10;
750 else if ((tmp >= 'A') && (tmp <= 'F'))
751 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000752 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000753 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000754 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000755 charval = 0;
756 break;
757 }
758 cur++;
759 tmp = *cur;
760 }
761 if (tmp == ';')
762 cur++;
763 q = cur;
764 } else if (cur[1] == '#') {
765 cur += 2;
766 tmp = *cur;
767 while (tmp != ';') { /* Non input consuming loops */
768 if ((tmp >= '0') && (tmp <= '9'))
769 charval = charval * 10 + (tmp - '0');
770 else {
771 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000772 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000773 charval = 0;
774 break;
775 }
776 cur++;
777 tmp = *cur;
778 }
779 if (tmp == ';')
780 cur++;
781 q = cur;
782 } else {
783 /*
784 * Read the entity string
785 */
786 cur++;
787 q = cur;
788 while ((*cur != 0) && (*cur != ';')) cur++;
789 if (*cur == 0) {
790#ifdef DEBUG_TREE
791 xmlGenericError(xmlGenericErrorContext,
792 "xmlStringGetNodeList: unterminated entity %30s\n", q);
793#endif
794 return(ret);
795 }
796 if (cur != q) {
797 /*
798 * Predefined entities don't generate nodes
799 */
800 val = xmlStrndup(q, cur - q);
801 ent = xmlGetDocEntity(doc, val);
802 if ((ent != NULL) &&
803 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
804 if (last == NULL) {
805 node = xmlNewDocText(doc, ent->content);
806 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000807 } else if (last->type != XML_TEXT_NODE) {
808 node = xmlNewDocText(doc, ent->content);
809 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000810 } else
811 xmlNodeAddContent(last, ent->content);
812
813 } else {
814 /*
815 * Create a new REFERENCE_REF node
816 */
817 node = xmlNewReference(doc, val);
818 if (node == NULL) {
819 if (val != NULL) xmlFree(val);
820 return(ret);
821 }
822 if (last == NULL) {
823 last = ret = node;
824 } else {
825 last = xmlAddNextSibling(last, node);
826 }
827 }
828 xmlFree(val);
829 }
830 cur++;
831 q = cur;
832 }
833 if (charval != 0) {
834 xmlChar buf[10];
835 int len;
836
837 len = xmlCopyCharMultiByte(buf, charval);
838 buf[len] = 0;
839 node = xmlNewDocText(doc, buf);
840 if (node != NULL) {
841 if (last == NULL) {
842 last = ret = node;
843 } else {
844 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000845 }
846 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000847
848 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000849 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000850 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000851 cur++;
852 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000853 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000854 /*
855 * Handle the last piece of text.
856 */
857 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
858 xmlNodeAddContentLen(last, q, cur - q);
859 } else {
860 node = xmlNewDocTextLen(doc, q, cur - q);
861 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000862 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000863 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000864 } else {
865 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000866 }
867 }
868 }
869 return(ret);
870}
871
872/**
873 * xmlNodeListGetString:
874 * @doc: the document
875 * @list: a Node list
876 * @inLine: should we replace entity contents or show their external form
877 *
878 * Returns the string equivalent to the text contained in the Node list
879 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000880 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000881 */
882xmlChar *
883xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
884 xmlNodePtr node = list;
885 xmlChar *ret = NULL;
886 xmlEntityPtr ent;
887
888 if (list == NULL) return(NULL);
889
890 while (node != NULL) {
891 if ((node->type == XML_TEXT_NODE) ||
892 (node->type == XML_CDATA_SECTION_NODE)) {
893 if (inLine) {
Owen Taylor3473f882001-02-23 17:55:21 +0000894 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000895 } else {
896 xmlChar *buffer;
897
Owen Taylor3473f882001-02-23 17:55:21 +0000898 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000899 if (buffer != NULL) {
900 ret = xmlStrcat(ret, buffer);
901 xmlFree(buffer);
902 }
903 }
904 } else if (node->type == XML_ENTITY_REF_NODE) {
905 if (inLine) {
906 ent = xmlGetDocEntity(doc, node->name);
907 if (ent != NULL)
908 ret = xmlStrcat(ret, ent->content);
909 else {
Owen Taylor3473f882001-02-23 17:55:21 +0000910 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000911 }
912 } else {
913 xmlChar buf[2];
914 buf[0] = '&'; buf[1] = 0;
915 ret = xmlStrncat(ret, buf, 1);
916 ret = xmlStrcat(ret, node->name);
917 buf[0] = ';'; buf[1] = 0;
918 ret = xmlStrncat(ret, buf, 1);
919 }
920 }
921#if 0
922 else {
923 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000924 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000925 node->type);
926 }
927#endif
928 node = node->next;
929 }
930 return(ret);
931}
932
933/**
934 * xmlNodeListGetRawString:
935 * @doc: the document
936 * @list: a Node list
937 * @inLine: should we replace entity contents or show their external form
938 *
939 * Returns the string equivalent to the text contained in the Node list
940 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
941 * this function doesn't do any character encoding handling.
942 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000943 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000944 */
945xmlChar *
946xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
947 xmlNodePtr node = list;
948 xmlChar *ret = NULL;
949 xmlEntityPtr ent;
950
951 if (list == NULL) return(NULL);
952
953 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000954 if ((node->type == XML_TEXT_NODE) ||
955 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000956 if (inLine) {
Owen Taylor3473f882001-02-23 17:55:21 +0000957 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000958 } else {
959 xmlChar *buffer;
960
Owen Taylor3473f882001-02-23 17:55:21 +0000961 buffer = xmlEncodeSpecialChars(doc, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000962 if (buffer != NULL) {
963 ret = xmlStrcat(ret, buffer);
964 xmlFree(buffer);
965 }
966 }
967 } else if (node->type == XML_ENTITY_REF_NODE) {
968 if (inLine) {
969 ent = xmlGetDocEntity(doc, node->name);
970 if (ent != NULL)
971 ret = xmlStrcat(ret, ent->content);
972 else {
Owen Taylor3473f882001-02-23 17:55:21 +0000973 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000974 }
975 } else {
976 xmlChar buf[2];
977 buf[0] = '&'; buf[1] = 0;
978 ret = xmlStrncat(ret, buf, 1);
979 ret = xmlStrcat(ret, node->name);
980 buf[0] = ';'; buf[1] = 0;
981 ret = xmlStrncat(ret, buf, 1);
982 }
983 }
984#if 0
985 else {
986 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000987 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000988 node->type);
989 }
990#endif
991 node = node->next;
992 }
993 return(ret);
994}
995
996/**
997 * xmlNewProp:
998 * @node: the holding node
999 * @name: the name of the attribute
1000 * @value: the value of the attribute
1001 *
1002 * Create a new property carried by a node.
1003 * Returns a pointer to the attribute
1004 */
1005xmlAttrPtr
1006xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1007 xmlAttrPtr cur;
1008 xmlDocPtr doc = NULL;
1009
1010 if (name == NULL) {
1011#ifdef DEBUG_TREE
1012 xmlGenericError(xmlGenericErrorContext,
1013 "xmlNewProp : name == NULL\n");
1014#endif
1015 return(NULL);
1016 }
1017
1018 /*
1019 * Allocate a new property and fill the fields.
1020 */
1021 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1022 if (cur == NULL) {
1023 xmlGenericError(xmlGenericErrorContext,
1024 "xmlNewProp : malloc failed\n");
1025 return(NULL);
1026 }
1027 memset(cur, 0, sizeof(xmlAttr));
1028 cur->type = XML_ATTRIBUTE_NODE;
1029
1030 cur->parent = node;
1031 if (node != NULL) {
1032 doc = node->doc;
1033 cur->doc = doc;
1034 }
1035 cur->name = xmlStrdup(name);
1036 if (value != NULL) {
1037 xmlChar *buffer;
1038 xmlNodePtr tmp;
1039
1040 buffer = xmlEncodeEntitiesReentrant(doc, value);
1041 cur->children = xmlStringGetNodeList(doc, buffer);
1042 cur->last = NULL;
1043 tmp = cur->children;
1044 while (tmp != NULL) {
1045 tmp->parent = (xmlNodePtr) cur;
1046 tmp->doc = doc;
1047 if (tmp->next == NULL)
1048 cur->last = tmp;
1049 tmp = tmp->next;
1050 }
1051 xmlFree(buffer);
1052 }
1053
1054 /*
1055 * Add it at the end to preserve parsing order ...
1056 */
1057 if (node != NULL) {
1058 if (node->properties == NULL) {
1059 node->properties = cur;
1060 } else {
1061 xmlAttrPtr prev = node->properties;
1062
1063 while (prev->next != NULL) prev = prev->next;
1064 prev->next = cur;
1065 cur->prev = prev;
1066 }
1067 }
1068 return(cur);
1069}
1070
1071/**
1072 * xmlNewNsProp:
1073 * @node: the holding node
1074 * @ns: the namespace
1075 * @name: the name of the attribute
1076 * @value: the value of the attribute
1077 *
1078 * Create a new property tagged with a namespace and carried by a node.
1079 * Returns a pointer to the attribute
1080 */
1081xmlAttrPtr
1082xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1083 const xmlChar *value) {
1084 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001085 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001086
1087 if (name == NULL) {
1088#ifdef DEBUG_TREE
1089 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001090 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001091#endif
1092 return(NULL);
1093 }
1094
1095 /*
1096 * Allocate a new property and fill the fields.
1097 */
1098 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1099 if (cur == NULL) {
1100 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001101 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001102 return(NULL);
1103 }
1104 memset(cur, 0, sizeof(xmlAttr));
1105 cur->type = XML_ATTRIBUTE_NODE;
1106
1107 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001108 if (node != NULL) {
1109 doc = node->doc;
1110 cur->doc = doc;
1111 }
Owen Taylor3473f882001-02-23 17:55:21 +00001112 cur->ns = ns;
1113 cur->name = xmlStrdup(name);
1114 if (value != NULL) {
1115 xmlChar *buffer;
1116 xmlNodePtr tmp;
1117
Daniel Veillarda682b212001-06-07 19:59:42 +00001118 buffer = xmlEncodeEntitiesReentrant(doc, value);
1119 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001120 cur->last = NULL;
1121 tmp = cur->children;
1122 while (tmp != NULL) {
1123 tmp->parent = (xmlNodePtr) cur;
1124 if (tmp->next == NULL)
1125 cur->last = tmp;
1126 tmp = tmp->next;
1127 }
1128 xmlFree(buffer);
1129 }
1130
1131 /*
1132 * Add it at the end to preserve parsing order ...
1133 */
1134 if (node != NULL) {
1135 if (node->properties == NULL) {
1136 node->properties = cur;
1137 } else {
1138 xmlAttrPtr prev = node->properties;
1139
1140 while (prev->next != NULL) prev = prev->next;
1141 prev->next = cur;
1142 cur->prev = prev;
1143 }
1144 }
1145 return(cur);
1146}
1147
1148/**
1149 * xmlNewDocProp:
1150 * @doc: the document
1151 * @name: the name of the attribute
1152 * @value: the value of the attribute
1153 *
1154 * Create a new property carried by a document.
1155 * Returns a pointer to the attribute
1156 */
1157xmlAttrPtr
1158xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1159 xmlAttrPtr cur;
1160
1161 if (name == NULL) {
1162#ifdef DEBUG_TREE
1163 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001164 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001165#endif
1166 return(NULL);
1167 }
1168
1169 /*
1170 * Allocate a new property and fill the fields.
1171 */
1172 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1173 if (cur == NULL) {
1174 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001175 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001176 return(NULL);
1177 }
1178 memset(cur, 0, sizeof(xmlAttr));
1179 cur->type = XML_ATTRIBUTE_NODE;
1180
1181 cur->name = xmlStrdup(name);
1182 cur->doc = doc;
1183 if (value != NULL) {
1184 xmlNodePtr tmp;
1185
1186 cur->children = xmlStringGetNodeList(doc, value);
1187 cur->last = NULL;
1188
1189 tmp = cur->children;
1190 while (tmp != NULL) {
1191 tmp->parent = (xmlNodePtr) cur;
1192 if (tmp->next == NULL)
1193 cur->last = tmp;
1194 tmp = tmp->next;
1195 }
1196 }
1197 return(cur);
1198}
1199
1200/**
1201 * xmlFreePropList:
1202 * @cur: the first property in the list
1203 *
1204 * Free a property and all its siblings, all the children are freed too.
1205 */
1206void
1207xmlFreePropList(xmlAttrPtr cur) {
1208 xmlAttrPtr next;
1209 if (cur == NULL) {
1210#ifdef DEBUG_TREE
1211 xmlGenericError(xmlGenericErrorContext,
1212 "xmlFreePropList : property == NULL\n");
1213#endif
1214 return;
1215 }
1216 while (cur != NULL) {
1217 next = cur->next;
1218 xmlFreeProp(cur);
1219 cur = next;
1220 }
1221}
1222
1223/**
1224 * xmlFreeProp:
1225 * @cur: an attribute
1226 *
1227 * Free one attribute, all the content is freed too
1228 */
1229void
1230xmlFreeProp(xmlAttrPtr cur) {
1231 if (cur == NULL) {
1232#ifdef DEBUG_TREE
1233 xmlGenericError(xmlGenericErrorContext,
1234 "xmlFreeProp : property == NULL\n");
1235#endif
1236 return;
1237 }
1238 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001239 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1240 ((cur->parent->doc->intSubset != NULL) ||
1241 (cur->parent->doc->extSubset != NULL))) {
1242 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1243 xmlRemoveID(cur->parent->doc, cur);
1244 }
Owen Taylor3473f882001-02-23 17:55:21 +00001245 if (cur->name != NULL) xmlFree((char *) cur->name);
1246 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001247 xmlFree(cur);
1248}
1249
1250/**
1251 * xmlRemoveProp:
1252 * @cur: an attribute
1253 *
1254 * Unlink and free one attribute, all the content is freed too
1255 * Note this doesn't work for namespace definition attributes
1256 *
1257 * Returns 0 if success and -1 in case of error.
1258 */
1259int
1260xmlRemoveProp(xmlAttrPtr cur) {
1261 xmlAttrPtr tmp;
1262 if (cur == NULL) {
1263#ifdef DEBUG_TREE
1264 xmlGenericError(xmlGenericErrorContext,
1265 "xmlRemoveProp : cur == NULL\n");
1266#endif
1267 return(-1);
1268 }
1269 if (cur->parent == NULL) {
1270#ifdef DEBUG_TREE
1271 xmlGenericError(xmlGenericErrorContext,
1272 "xmlRemoveProp : cur->parent == NULL\n");
1273#endif
1274 return(-1);
1275 }
1276 tmp = cur->parent->properties;
1277 if (tmp == cur) {
1278 cur->parent->properties = cur->next;
1279 xmlFreeProp(cur);
1280 return(0);
1281 }
1282 while (tmp != NULL) {
1283 if (tmp->next == cur) {
1284 tmp->next = cur->next;
1285 if (tmp->next != NULL)
1286 tmp->next->prev = tmp;
1287 xmlFreeProp(cur);
1288 return(0);
1289 }
1290 tmp = tmp->next;
1291 }
1292#ifdef DEBUG_TREE
1293 xmlGenericError(xmlGenericErrorContext,
1294 "xmlRemoveProp : attribute not owned by its node\n");
1295#endif
1296 return(-1);
1297}
1298
1299/**
1300 * xmlNewPI:
1301 * @name: the processing instruction name
1302 * @content: the PI content
1303 *
1304 * Creation of a processing instruction element.
1305 * Returns a pointer to the new node object.
1306 */
1307xmlNodePtr
1308xmlNewPI(const xmlChar *name, const xmlChar *content) {
1309 xmlNodePtr cur;
1310
1311 if (name == NULL) {
1312#ifdef DEBUG_TREE
1313 xmlGenericError(xmlGenericErrorContext,
1314 "xmlNewPI : name == NULL\n");
1315#endif
1316 return(NULL);
1317 }
1318
1319 /*
1320 * Allocate a new node and fill the fields.
1321 */
1322 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1323 if (cur == NULL) {
1324 xmlGenericError(xmlGenericErrorContext,
1325 "xmlNewPI : malloc failed\n");
1326 return(NULL);
1327 }
1328 memset(cur, 0, sizeof(xmlNode));
1329 cur->type = XML_PI_NODE;
1330
1331 cur->name = xmlStrdup(name);
1332 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001333 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001334 }
1335 return(cur);
1336}
1337
1338/**
1339 * xmlNewNode:
1340 * @ns: namespace if any
1341 * @name: the node name
1342 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001343 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001344 *
1345 * Returns a pointer to the new node object.
1346 */
1347xmlNodePtr
1348xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1349 xmlNodePtr cur;
1350
1351 if (name == NULL) {
1352#ifdef DEBUG_TREE
1353 xmlGenericError(xmlGenericErrorContext,
1354 "xmlNewNode : name == NULL\n");
1355#endif
1356 return(NULL);
1357 }
1358
1359 /*
1360 * Allocate a new node and fill the fields.
1361 */
1362 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1363 if (cur == NULL) {
1364 xmlGenericError(xmlGenericErrorContext,
1365 "xmlNewNode : malloc failed\n");
1366 return(NULL);
1367 }
1368 memset(cur, 0, sizeof(xmlNode));
1369 cur->type = XML_ELEMENT_NODE;
1370
1371 cur->name = xmlStrdup(name);
1372 cur->ns = ns;
1373 return(cur);
1374}
1375
1376/**
1377 * xmlNewDocNode:
1378 * @doc: the document
1379 * @ns: namespace if any
1380 * @name: the node name
1381 * @content: the XML text content if any
1382 *
1383 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001384 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001385 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1386 * references, but XML special chars need to be escaped first by using
1387 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1388 * need entities support.
1389 *
1390 * Returns a pointer to the new node object.
1391 */
1392xmlNodePtr
1393xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1394 const xmlChar *name, const xmlChar *content) {
1395 xmlNodePtr cur;
1396
1397 cur = xmlNewNode(ns, name);
1398 if (cur != NULL) {
1399 cur->doc = doc;
1400 if (content != NULL) {
1401 cur->children = xmlStringGetNodeList(doc, content);
1402 UPDATE_LAST_CHILD_AND_PARENT(cur)
1403 }
1404 }
1405 return(cur);
1406}
1407
1408
1409/**
1410 * xmlNewDocRawNode:
1411 * @doc: the document
1412 * @ns: namespace if any
1413 * @name: the node name
1414 * @content: the text content if any
1415 *
1416 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001417 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001418 *
1419 * Returns a pointer to the new node object.
1420 */
1421xmlNodePtr
1422xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1423 const xmlChar *name, const xmlChar *content) {
1424 xmlNodePtr cur;
1425
1426 cur = xmlNewNode(ns, name);
1427 if (cur != NULL) {
1428 cur->doc = doc;
1429 if (content != NULL) {
1430 cur->children = xmlNewDocText(doc, content);
1431 UPDATE_LAST_CHILD_AND_PARENT(cur)
1432 }
1433 }
1434 return(cur);
1435}
1436
1437/**
1438 * xmlNewDocFragment:
1439 * @doc: the document owning the fragment
1440 *
1441 * Creation of a new Fragment node.
1442 * Returns a pointer to the new node object.
1443 */
1444xmlNodePtr
1445xmlNewDocFragment(xmlDocPtr doc) {
1446 xmlNodePtr cur;
1447
1448 /*
1449 * Allocate a new DocumentFragment node and fill the fields.
1450 */
1451 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1452 if (cur == NULL) {
1453 xmlGenericError(xmlGenericErrorContext,
1454 "xmlNewDocFragment : malloc failed\n");
1455 return(NULL);
1456 }
1457 memset(cur, 0, sizeof(xmlNode));
1458 cur->type = XML_DOCUMENT_FRAG_NODE;
1459
1460 cur->doc = doc;
1461 return(cur);
1462}
1463
1464/**
1465 * xmlNewText:
1466 * @content: the text content
1467 *
1468 * Creation of a new text node.
1469 * Returns a pointer to the new node object.
1470 */
1471xmlNodePtr
1472xmlNewText(const xmlChar *content) {
1473 xmlNodePtr cur;
1474
1475 /*
1476 * Allocate a new node and fill the fields.
1477 */
1478 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1479 if (cur == NULL) {
1480 xmlGenericError(xmlGenericErrorContext,
1481 "xmlNewText : malloc failed\n");
1482 return(NULL);
1483 }
1484 memset(cur, 0, sizeof(xmlNode));
1485 cur->type = XML_TEXT_NODE;
1486
1487 cur->name = xmlStringText;
1488 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001489 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001490 }
1491 return(cur);
1492}
1493
1494/**
1495 * xmlNewTextChild:
1496 * @parent: the parent node
1497 * @ns: a namespace if any
1498 * @name: the name of the child
1499 * @content: the text content of the child if any.
1500 *
1501 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001502 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001503 * a child TEXT node will be created containing the string content.
1504 *
1505 * Returns a pointer to the new node object.
1506 */
1507xmlNodePtr
1508xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1509 const xmlChar *name, const xmlChar *content) {
1510 xmlNodePtr cur, prev;
1511
1512 if (parent == NULL) {
1513#ifdef DEBUG_TREE
1514 xmlGenericError(xmlGenericErrorContext,
1515 "xmlNewTextChild : parent == NULL\n");
1516#endif
1517 return(NULL);
1518 }
1519
1520 if (name == NULL) {
1521#ifdef DEBUG_TREE
1522 xmlGenericError(xmlGenericErrorContext,
1523 "xmlNewTextChild : name == NULL\n");
1524#endif
1525 return(NULL);
1526 }
1527
1528 /*
1529 * Allocate a new node
1530 */
1531 if (ns == NULL)
1532 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1533 else
1534 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1535 if (cur == NULL) return(NULL);
1536
1537 /*
1538 * add the new element at the end of the children list.
1539 */
1540 cur->type = XML_ELEMENT_NODE;
1541 cur->parent = parent;
1542 cur->doc = parent->doc;
1543 if (parent->children == NULL) {
1544 parent->children = cur;
1545 parent->last = cur;
1546 } else {
1547 prev = parent->last;
1548 prev->next = cur;
1549 cur->prev = prev;
1550 parent->last = cur;
1551 }
1552
1553 return(cur);
1554}
1555
1556/**
1557 * xmlNewCharRef:
1558 * @doc: the document
1559 * @name: the char ref string, starting with # or "&# ... ;"
1560 *
1561 * Creation of a new character reference node.
1562 * Returns a pointer to the new node object.
1563 */
1564xmlNodePtr
1565xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1566 xmlNodePtr cur;
1567
1568 /*
1569 * Allocate a new node and fill the fields.
1570 */
1571 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1572 if (cur == NULL) {
1573 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001574 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001575 return(NULL);
1576 }
1577 memset(cur, 0, sizeof(xmlNode));
1578 cur->type = XML_ENTITY_REF_NODE;
1579
1580 cur->doc = doc;
1581 if (name[0] == '&') {
1582 int len;
1583 name++;
1584 len = xmlStrlen(name);
1585 if (name[len - 1] == ';')
1586 cur->name = xmlStrndup(name, len - 1);
1587 else
1588 cur->name = xmlStrndup(name, len);
1589 } else
1590 cur->name = xmlStrdup(name);
1591 return(cur);
1592}
1593
1594/**
1595 * xmlNewReference:
1596 * @doc: the document
1597 * @name: the reference name, or the reference string with & and ;
1598 *
1599 * Creation of a new reference node.
1600 * Returns a pointer to the new node object.
1601 */
1602xmlNodePtr
1603xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1604 xmlNodePtr cur;
1605 xmlEntityPtr ent;
1606
1607 /*
1608 * Allocate a new node and fill the fields.
1609 */
1610 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1611 if (cur == NULL) {
1612 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001613 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001614 return(NULL);
1615 }
1616 memset(cur, 0, sizeof(xmlNode));
1617 cur->type = XML_ENTITY_REF_NODE;
1618
1619 cur->doc = doc;
1620 if (name[0] == '&') {
1621 int len;
1622 name++;
1623 len = xmlStrlen(name);
1624 if (name[len - 1] == ';')
1625 cur->name = xmlStrndup(name, len - 1);
1626 else
1627 cur->name = xmlStrndup(name, len);
1628 } else
1629 cur->name = xmlStrdup(name);
1630
1631 ent = xmlGetDocEntity(doc, cur->name);
1632 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001633 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001634 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001635 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001636 * updated. Not sure if this is 100% correct.
1637 * -George
1638 */
1639 cur->children = (xmlNodePtr) ent;
1640 cur->last = (xmlNodePtr) ent;
1641 }
1642 return(cur);
1643}
1644
1645/**
1646 * xmlNewDocText:
1647 * @doc: the document
1648 * @content: the text content
1649 *
1650 * Creation of a new text node within a document.
1651 * Returns a pointer to the new node object.
1652 */
1653xmlNodePtr
1654xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1655 xmlNodePtr cur;
1656
1657 cur = xmlNewText(content);
1658 if (cur != NULL) cur->doc = doc;
1659 return(cur);
1660}
1661
1662/**
1663 * xmlNewTextLen:
1664 * @content: the text content
1665 * @len: the text len.
1666 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001667 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001668 * Returns a pointer to the new node object.
1669 */
1670xmlNodePtr
1671xmlNewTextLen(const xmlChar *content, int len) {
1672 xmlNodePtr cur;
1673
1674 /*
1675 * Allocate a new node and fill the fields.
1676 */
1677 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1678 if (cur == NULL) {
1679 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001680 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001681 return(NULL);
1682 }
1683 memset(cur, 0, sizeof(xmlNode));
1684 cur->type = XML_TEXT_NODE;
1685
1686 cur->name = xmlStringText;
1687 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001688 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001689 }
1690 return(cur);
1691}
1692
1693/**
1694 * xmlNewDocTextLen:
1695 * @doc: the document
1696 * @content: the text content
1697 * @len: the text len.
1698 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001699 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001700 * text node pertain to a given document.
1701 * Returns a pointer to the new node object.
1702 */
1703xmlNodePtr
1704xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1705 xmlNodePtr cur;
1706
1707 cur = xmlNewTextLen(content, len);
1708 if (cur != NULL) cur->doc = doc;
1709 return(cur);
1710}
1711
1712/**
1713 * xmlNewComment:
1714 * @content: the comment content
1715 *
1716 * Creation of a new node containing a comment.
1717 * Returns a pointer to the new node object.
1718 */
1719xmlNodePtr
1720xmlNewComment(const xmlChar *content) {
1721 xmlNodePtr cur;
1722
1723 /*
1724 * Allocate a new node and fill the fields.
1725 */
1726 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1727 if (cur == NULL) {
1728 xmlGenericError(xmlGenericErrorContext,
1729 "xmlNewComment : malloc failed\n");
1730 return(NULL);
1731 }
1732 memset(cur, 0, sizeof(xmlNode));
1733 cur->type = XML_COMMENT_NODE;
1734
1735 cur->name = xmlStringComment;
1736 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001737 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001738 }
1739 return(cur);
1740}
1741
1742/**
1743 * xmlNewCDataBlock:
1744 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001745 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001746 * @len: the length of the block
1747 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001748 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001749 * Returns a pointer to the new node object.
1750 */
1751xmlNodePtr
1752xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1753 xmlNodePtr cur;
1754
1755 /*
1756 * Allocate a new node and fill the fields.
1757 */
1758 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1759 if (cur == NULL) {
1760 xmlGenericError(xmlGenericErrorContext,
1761 "xmlNewCDataBlock : malloc failed\n");
1762 return(NULL);
1763 }
1764 memset(cur, 0, sizeof(xmlNode));
1765 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001766 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001767
1768 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001769 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001770 }
1771 return(cur);
1772}
1773
1774/**
1775 * xmlNewDocComment:
1776 * @doc: the document
1777 * @content: the comment content
1778 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001779 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001780 * Returns a pointer to the new node object.
1781 */
1782xmlNodePtr
1783xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1784 xmlNodePtr cur;
1785
1786 cur = xmlNewComment(content);
1787 if (cur != NULL) cur->doc = doc;
1788 return(cur);
1789}
1790
1791/**
1792 * xmlSetTreeDoc:
1793 * @tree: the top element
1794 * @doc: the document
1795 *
1796 * update all nodes under the tree to point to the right document
1797 */
1798void
1799xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001800 xmlAttrPtr prop;
1801
Owen Taylor3473f882001-02-23 17:55:21 +00001802 if (tree == NULL)
1803 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001804 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00001805 if(tree->type == XML_ELEMENT_NODE) {
1806 prop = tree->properties;
1807 while (prop != NULL) {
1808 prop->doc = doc;
1809 xmlSetListDoc(prop->children, doc);
1810 prop = prop->next;
1811 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00001812 }
Owen Taylor3473f882001-02-23 17:55:21 +00001813 if (tree->children != NULL)
1814 xmlSetListDoc(tree->children, doc);
1815 tree->doc = doc;
1816 }
1817}
1818
1819/**
1820 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001821 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001822 * @doc: the document
1823 *
1824 * update all nodes in the list to point to the right document
1825 */
1826void
1827xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1828 xmlNodePtr cur;
1829
1830 if (list == NULL)
1831 return;
1832 cur = list;
1833 while (cur != NULL) {
1834 if (cur->doc != doc)
1835 xmlSetTreeDoc(cur, doc);
1836 cur = cur->next;
1837 }
1838}
1839
1840
1841/**
1842 * xmlNewChild:
1843 * @parent: the parent node
1844 * @ns: a namespace if any
1845 * @name: the name of the child
1846 * @content: the XML content of the child if any.
1847 *
1848 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001849 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001850 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1851 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1852 * references, but XML special chars need to be escaped first by using
1853 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1854 * support is not needed.
1855 *
1856 * Returns a pointer to the new node object.
1857 */
1858xmlNodePtr
1859xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1860 const xmlChar *name, const xmlChar *content) {
1861 xmlNodePtr cur, prev;
1862
1863 if (parent == NULL) {
1864#ifdef DEBUG_TREE
1865 xmlGenericError(xmlGenericErrorContext,
1866 "xmlNewChild : parent == NULL\n");
1867#endif
1868 return(NULL);
1869 }
1870
1871 if (name == NULL) {
1872#ifdef DEBUG_TREE
1873 xmlGenericError(xmlGenericErrorContext,
1874 "xmlNewChild : name == NULL\n");
1875#endif
1876 return(NULL);
1877 }
1878
1879 /*
1880 * Allocate a new node
1881 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00001882 if (parent->type == XML_ELEMENT_NODE) {
1883 if (ns == NULL)
1884 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1885 else
1886 cur = xmlNewDocNode(parent->doc, ns, name, content);
1887 } else if ((parent->type == XML_DOCUMENT_NODE) ||
1888 (parent->type == XML_HTML_DOCUMENT_NODE)) {
1889 if (ns == NULL)
1890 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
1891 else
1892 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
1893 } else {
1894 return(NULL);
1895 }
Owen Taylor3473f882001-02-23 17:55:21 +00001896 if (cur == NULL) return(NULL);
1897
1898 /*
1899 * add the new element at the end of the children list.
1900 */
1901 cur->type = XML_ELEMENT_NODE;
1902 cur->parent = parent;
1903 cur->doc = parent->doc;
1904 if (parent->children == NULL) {
1905 parent->children = cur;
1906 parent->last = cur;
1907 } else {
1908 prev = parent->last;
1909 prev->next = cur;
1910 cur->prev = prev;
1911 parent->last = cur;
1912 }
1913
1914 return(cur);
1915}
1916
1917/**
1918 * xmlAddNextSibling:
1919 * @cur: the child node
1920 * @elem: the new node
1921 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001922 * Add a new node @elem as the next sibling of @cur
1923 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00001924 * first unlinked from its existing context.
1925 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001926 * If the new node is ATTRIBUTE, it is added into properties instead of children.
1927 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00001928 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001929 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001930 */
1931xmlNodePtr
1932xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1933 if (cur == NULL) {
1934#ifdef DEBUG_TREE
1935 xmlGenericError(xmlGenericErrorContext,
1936 "xmlAddNextSibling : cur == NULL\n");
1937#endif
1938 return(NULL);
1939 }
1940 if (elem == NULL) {
1941#ifdef DEBUG_TREE
1942 xmlGenericError(xmlGenericErrorContext,
1943 "xmlAddNextSibling : elem == NULL\n");
1944#endif
1945 return(NULL);
1946 }
1947
1948 xmlUnlinkNode(elem);
1949
1950 if (elem->type == XML_TEXT_NODE) {
1951 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00001952 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001953 xmlFreeNode(elem);
1954 return(cur);
1955 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001956 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1957 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001958 xmlChar *tmp;
1959
1960 tmp = xmlStrdup(elem->content);
1961 tmp = xmlStrcat(tmp, cur->next->content);
1962 xmlNodeSetContent(cur->next, tmp);
1963 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00001964 xmlFreeNode(elem);
1965 return(cur->next);
1966 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001967 } else if (elem->type == XML_ATTRIBUTE_NODE) {
1968 /* check if an attribute with the same name exists */
1969 xmlAttrPtr attr;
1970
1971 if (elem->ns == NULL)
1972 attr = xmlHasProp(cur->parent, elem->name);
1973 else
1974 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
1975 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
1976 /* different instance, destroy it (attributes must be unique) */
1977 xmlFreeProp(attr);
1978 }
Owen Taylor3473f882001-02-23 17:55:21 +00001979 }
1980
1981 if (elem->doc != cur->doc) {
1982 xmlSetTreeDoc(elem, cur->doc);
1983 }
1984 elem->parent = cur->parent;
1985 elem->prev = cur;
1986 elem->next = cur->next;
1987 cur->next = elem;
1988 if (elem->next != NULL)
1989 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001990 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00001991 elem->parent->last = elem;
1992 return(elem);
1993}
1994
1995/**
1996 * xmlAddPrevSibling:
1997 * @cur: the child node
1998 * @elem: the new node
1999 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002000 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002001 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002002 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002003 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002004 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2005 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002006 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002007 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002008 */
2009xmlNodePtr
2010xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2011 if (cur == NULL) {
2012#ifdef DEBUG_TREE
2013 xmlGenericError(xmlGenericErrorContext,
2014 "xmlAddPrevSibling : cur == NULL\n");
2015#endif
2016 return(NULL);
2017 }
2018 if (elem == NULL) {
2019#ifdef DEBUG_TREE
2020 xmlGenericError(xmlGenericErrorContext,
2021 "xmlAddPrevSibling : elem == NULL\n");
2022#endif
2023 return(NULL);
2024 }
2025
2026 xmlUnlinkNode(elem);
2027
2028 if (elem->type == XML_TEXT_NODE) {
2029 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002030 xmlChar *tmp;
2031
2032 tmp = xmlStrdup(elem->content);
2033 tmp = xmlStrcat(tmp, cur->content);
2034 xmlNodeSetContent(cur, tmp);
2035 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002036 xmlFreeNode(elem);
2037 return(cur);
2038 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002039 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2040 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002041 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002042 xmlFreeNode(elem);
2043 return(cur->prev);
2044 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002045 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2046 /* check if an attribute with the same name exists */
2047 xmlAttrPtr attr;
2048
2049 if (elem->ns == NULL)
2050 attr = xmlHasProp(cur->parent, elem->name);
2051 else
2052 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2053 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2054 /* different instance, destroy it (attributes must be unique) */
2055 xmlFreeProp(attr);
2056 }
Owen Taylor3473f882001-02-23 17:55:21 +00002057 }
2058
2059 if (elem->doc != cur->doc) {
2060 xmlSetTreeDoc(elem, cur->doc);
2061 }
2062 elem->parent = cur->parent;
2063 elem->next = cur;
2064 elem->prev = cur->prev;
2065 cur->prev = elem;
2066 if (elem->prev != NULL)
2067 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002068 if (elem->parent != NULL) {
2069 if (elem->type == XML_ATTRIBUTE_NODE) {
2070 if (elem->parent->properties == (xmlAttrPtr) cur) {
2071 elem->parent->properties = (xmlAttrPtr) elem;
2072 }
2073 } else {
2074 if (elem->parent->children == cur) {
2075 elem->parent->children = elem;
2076 }
2077 }
2078 }
Owen Taylor3473f882001-02-23 17:55:21 +00002079 return(elem);
2080}
2081
2082/**
2083 * xmlAddSibling:
2084 * @cur: the child node
2085 * @elem: the new node
2086 *
2087 * Add a new element @elem to the list of siblings of @cur
2088 * merging adjacent TEXT nodes (@elem may be freed)
2089 * If the new element was already inserted in a document it is
2090 * first unlinked from its existing context.
2091 *
2092 * Returns the new element or NULL in case of error.
2093 */
2094xmlNodePtr
2095xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2096 xmlNodePtr parent;
2097
2098 if (cur == NULL) {
2099#ifdef DEBUG_TREE
2100 xmlGenericError(xmlGenericErrorContext,
2101 "xmlAddSibling : cur == NULL\n");
2102#endif
2103 return(NULL);
2104 }
2105
2106 if (elem == NULL) {
2107#ifdef DEBUG_TREE
2108 xmlGenericError(xmlGenericErrorContext,
2109 "xmlAddSibling : elem == NULL\n");
2110#endif
2111 return(NULL);
2112 }
2113
2114 /*
2115 * Constant time is we can rely on the ->parent->last to find
2116 * the last sibling.
2117 */
2118 if ((cur->parent != NULL) &&
2119 (cur->parent->children != NULL) &&
2120 (cur->parent->last != NULL) &&
2121 (cur->parent->last->next == NULL)) {
2122 cur = cur->parent->last;
2123 } else {
2124 while (cur->next != NULL) cur = cur->next;
2125 }
2126
2127 xmlUnlinkNode(elem);
2128
2129 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002130 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002131 xmlFreeNode(elem);
2132 return(cur);
2133 }
2134
2135 if (elem->doc != cur->doc) {
2136 xmlSetTreeDoc(elem, cur->doc);
2137 }
2138 parent = cur->parent;
2139 elem->prev = cur;
2140 elem->next = NULL;
2141 elem->parent = parent;
2142 cur->next = elem;
2143 if (parent != NULL)
2144 parent->last = elem;
2145
2146 return(elem);
2147}
2148
2149/**
2150 * xmlAddChildList:
2151 * @parent: the parent node
2152 * @cur: the first node in the list
2153 *
2154 * Add a list of node at the end of the child list of the parent
2155 * merging adjacent TEXT nodes (@cur may be freed)
2156 *
2157 * Returns the last child or NULL in case of error.
2158 */
2159xmlNodePtr
2160xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2161 xmlNodePtr prev;
2162
2163 if (parent == NULL) {
2164#ifdef DEBUG_TREE
2165 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002166 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002167#endif
2168 return(NULL);
2169 }
2170
2171 if (cur == NULL) {
2172#ifdef DEBUG_TREE
2173 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002174 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002175#endif
2176 return(NULL);
2177 }
2178
2179 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2180 (cur->doc != parent->doc)) {
2181#ifdef DEBUG_TREE
2182 xmlGenericError(xmlGenericErrorContext,
2183 "Elements moved to a different document\n");
2184#endif
2185 }
2186
2187 /*
2188 * add the first element at the end of the children list.
2189 */
2190 if (parent->children == NULL) {
2191 parent->children = cur;
2192 } else {
2193 /*
2194 * If cur and parent->last both are TEXT nodes, then merge them.
2195 */
2196 if ((cur->type == XML_TEXT_NODE) &&
2197 (parent->last->type == XML_TEXT_NODE) &&
2198 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002199 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002200 /*
2201 * if it's the only child, nothing more to be done.
2202 */
2203 if (cur->next == NULL) {
2204 xmlFreeNode(cur);
2205 return(parent->last);
2206 }
2207 prev = cur;
2208 cur = cur->next;
2209 xmlFreeNode(prev);
2210 }
2211 prev = parent->last;
2212 prev->next = cur;
2213 cur->prev = prev;
2214 }
2215 while (cur->next != NULL) {
2216 cur->parent = parent;
2217 if (cur->doc != parent->doc) {
2218 xmlSetTreeDoc(cur, parent->doc);
2219 }
2220 cur = cur->next;
2221 }
2222 cur->parent = parent;
2223 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2224 parent->last = cur;
2225
2226 return(cur);
2227}
2228
2229/**
2230 * xmlAddChild:
2231 * @parent: the parent node
2232 * @cur: the child node
2233 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002234 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002235 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002236 * If the new node was already inserted in a document it is
2237 * first unlinked from its existing context.
2238 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2239 * If there is an attribute with equal name, it is first destroyed.
2240 *
Owen Taylor3473f882001-02-23 17:55:21 +00002241 * Returns the child or NULL in case of error.
2242 */
2243xmlNodePtr
2244xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2245 xmlNodePtr prev;
2246
2247 if (parent == NULL) {
2248#ifdef DEBUG_TREE
2249 xmlGenericError(xmlGenericErrorContext,
2250 "xmlAddChild : parent == NULL\n");
2251#endif
2252 return(NULL);
2253 }
2254
2255 if (cur == NULL) {
2256#ifdef DEBUG_TREE
2257 xmlGenericError(xmlGenericErrorContext,
2258 "xmlAddChild : child == NULL\n");
2259#endif
2260 return(NULL);
2261 }
2262
Owen Taylor3473f882001-02-23 17:55:21 +00002263 /*
2264 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002265 * cur is then freed.
2266 */
2267 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002268 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002269 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002270 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002271 xmlFreeNode(cur);
2272 return(parent);
2273 }
2274 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2275 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002276 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002277 xmlFreeNode(cur);
2278 return(parent->last);
2279 }
2280 }
2281
2282 /*
2283 * add the new element at the end of the children list.
2284 */
2285 cur->parent = parent;
2286 if (cur->doc != parent->doc) {
2287 xmlSetTreeDoc(cur, parent->doc);
2288 }
2289
2290 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002291 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002292 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002293 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002294 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002295 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002296 xmlFreeNode(cur);
2297 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002298 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002299 if (cur->type == XML_ATTRIBUTE_NODE) {
2300 if (parent->properties == NULL) {
2301 parent->properties = (xmlAttrPtr) cur;
2302 } else {
2303 /* check if an attribute with the same name exists */
2304 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002305
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002306 if (cur->ns == NULL)
2307 lastattr = xmlHasProp(parent, cur->name);
2308 else
2309 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2310 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2311 /* different instance, destroy it (attributes must be unique) */
2312 xmlFreeProp(lastattr);
2313 }
2314 /* find the end */
2315 lastattr = parent->properties;
2316 while (lastattr->next != NULL) {
2317 lastattr = lastattr->next;
2318 }
2319 lastattr->next = (xmlAttrPtr) cur;
2320 ((xmlAttrPtr) cur)->prev = lastattr;
2321 }
2322 } else {
2323 if (parent->children == NULL) {
2324 parent->children = cur;
2325 parent->last = cur;
2326 } else {
2327 prev = parent->last;
2328 prev->next = cur;
2329 cur->prev = prev;
2330 parent->last = cur;
2331 }
2332 }
Owen Taylor3473f882001-02-23 17:55:21 +00002333 return(cur);
2334}
2335
2336/**
2337 * xmlGetLastChild:
2338 * @parent: the parent node
2339 *
2340 * Search the last child of a node.
2341 * Returns the last child or NULL if none.
2342 */
2343xmlNodePtr
2344xmlGetLastChild(xmlNodePtr parent) {
2345 if (parent == NULL) {
2346#ifdef DEBUG_TREE
2347 xmlGenericError(xmlGenericErrorContext,
2348 "xmlGetLastChild : parent == NULL\n");
2349#endif
2350 return(NULL);
2351 }
2352 return(parent->last);
2353}
2354
2355/**
2356 * xmlFreeNodeList:
2357 * @cur: the first node in the list
2358 *
2359 * Free a node and all its siblings, this is a recursive behaviour, all
2360 * the children are freed too.
2361 */
2362void
2363xmlFreeNodeList(xmlNodePtr cur) {
2364 xmlNodePtr next;
2365 if (cur == NULL) {
2366#ifdef DEBUG_TREE
2367 xmlGenericError(xmlGenericErrorContext,
2368 "xmlFreeNodeList : node == NULL\n");
2369#endif
2370 return;
2371 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002372 if (cur->type == XML_NAMESPACE_DECL) {
2373 xmlFreeNsList((xmlNsPtr) cur);
2374 return;
2375 }
Owen Taylor3473f882001-02-23 17:55:21 +00002376 while (cur != NULL) {
2377 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002378 /* unroll to speed up freeing the document */
2379 if (cur->type != XML_DTD_NODE) {
2380 if ((cur->children != NULL) &&
2381 (cur->type != XML_ENTITY_REF_NODE))
2382 xmlFreeNodeList(cur->children);
2383 if (cur->properties != NULL)
2384 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002385 if ((cur->type != XML_ELEMENT_NODE) &&
2386 (cur->type != XML_XINCLUDE_START) &&
2387 (cur->type != XML_XINCLUDE_END) &&
2388 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002389 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002390 }
2391 if (((cur->type == XML_ELEMENT_NODE) ||
2392 (cur->type == XML_XINCLUDE_START) ||
2393 (cur->type == XML_XINCLUDE_END)) &&
2394 (cur->nsDef != NULL))
2395 xmlFreeNsList(cur->nsDef);
2396
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002397 /*
2398 * When a node is a text node or a comment, it uses a global static
2399 * variable for the name of the node.
2400 *
2401 * The xmlStrEqual comparisons need to be done when (happened with
2402 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002403 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002404 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002405 * the string addresses compare are not sufficient.
2406 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002407 if ((cur->name != NULL) &&
2408 (cur->name != xmlStringText) &&
2409 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002410 (cur->name != xmlStringComment)) {
2411 if (cur->type == XML_TEXT_NODE) {
2412 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2413 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2414 xmlFree((char *) cur->name);
2415 } else if (cur->type == XML_COMMENT_NODE) {
2416 if (!xmlStrEqual(cur->name, xmlStringComment))
2417 xmlFree((char *) cur->name);
2418 } else
2419 xmlFree((char *) cur->name);
2420 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002421 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002422 xmlFree(cur);
2423 }
Owen Taylor3473f882001-02-23 17:55:21 +00002424 cur = next;
2425 }
2426}
2427
2428/**
2429 * xmlFreeNode:
2430 * @cur: the node
2431 *
2432 * Free a node, this is a recursive behaviour, all the children are freed too.
2433 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2434 */
2435void
2436xmlFreeNode(xmlNodePtr cur) {
2437 if (cur == NULL) {
2438#ifdef DEBUG_TREE
2439 xmlGenericError(xmlGenericErrorContext,
2440 "xmlFreeNode : node == NULL\n");
2441#endif
2442 return;
2443 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002444 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002445 if (cur->type == XML_DTD_NODE) {
2446 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002447 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002448 }
2449 if (cur->type == XML_NAMESPACE_DECL) {
2450 xmlFreeNs((xmlNsPtr) cur);
2451 return;
2452 }
Owen Taylor3473f882001-02-23 17:55:21 +00002453 if ((cur->children != NULL) &&
2454 (cur->type != XML_ENTITY_REF_NODE))
2455 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002456 if (cur->properties != NULL)
2457 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002458 if ((cur->type != XML_ELEMENT_NODE) &&
2459 (cur->content != NULL) &&
2460 (cur->type != XML_ENTITY_REF_NODE) &&
2461 (cur->type != XML_XINCLUDE_END) &&
2462 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002463 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002464 }
2465
Daniel Veillardacd370f2001-06-09 17:17:51 +00002466 /*
2467 * When a node is a text node or a comment, it uses a global static
2468 * variable for the name of the node.
2469 *
2470 * The xmlStrEqual comparisons need to be done when (happened with
2471 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002472 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002473 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002474 * are not sufficient.
2475 */
Owen Taylor3473f882001-02-23 17:55:21 +00002476 if ((cur->name != NULL) &&
2477 (cur->name != xmlStringText) &&
2478 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002479 (cur->name != xmlStringComment)) {
2480 if (cur->type == XML_TEXT_NODE) {
2481 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2482 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2483 xmlFree((char *) cur->name);
2484 } else if (cur->type == XML_COMMENT_NODE) {
2485 if (!xmlStrEqual(cur->name, xmlStringComment))
2486 xmlFree((char *) cur->name);
2487 } else
2488 xmlFree((char *) cur->name);
2489 }
2490
Owen Taylor3473f882001-02-23 17:55:21 +00002491 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002492 xmlFree(cur);
2493}
2494
2495/**
2496 * xmlUnlinkNode:
2497 * @cur: the node
2498 *
2499 * Unlink a node from it's current context, the node is not freed
2500 */
2501void
2502xmlUnlinkNode(xmlNodePtr cur) {
2503 if (cur == NULL) {
2504#ifdef DEBUG_TREE
2505 xmlGenericError(xmlGenericErrorContext,
2506 "xmlUnlinkNode : node == NULL\n");
2507#endif
2508 return;
2509 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002510 if (cur->type == XML_DTD_NODE) {
2511 xmlDocPtr doc;
2512 doc = cur->doc;
2513 if (doc->intSubset == (xmlDtdPtr) cur)
2514 doc->intSubset = NULL;
2515 if (doc->extSubset == (xmlDtdPtr) cur)
2516 doc->extSubset = NULL;
2517 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002518 if (cur->parent != NULL) {
2519 xmlNodePtr parent;
2520 parent = cur->parent;
2521 if (cur->type == XML_ATTRIBUTE_NODE) {
2522 if (parent->properties == (xmlAttrPtr) cur)
2523 parent->properties = ((xmlAttrPtr) cur)->next;
2524 } else {
2525 if (parent->children == cur)
2526 parent->children = cur->next;
2527 if (parent->last == cur)
2528 parent->last = cur->prev;
2529 }
2530 cur->parent = NULL;
2531 }
Owen Taylor3473f882001-02-23 17:55:21 +00002532 if (cur->next != NULL)
2533 cur->next->prev = cur->prev;
2534 if (cur->prev != NULL)
2535 cur->prev->next = cur->next;
2536 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002537}
2538
2539/**
2540 * xmlReplaceNode:
2541 * @old: the old node
2542 * @cur: the node
2543 *
2544 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002545 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002546 * first unlinked from its existing context.
2547 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002548 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002549 */
2550xmlNodePtr
2551xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2552 if (old == NULL) {
2553#ifdef DEBUG_TREE
2554 xmlGenericError(xmlGenericErrorContext,
2555 "xmlReplaceNode : old == NULL\n");
2556#endif
2557 return(NULL);
2558 }
2559 if (cur == NULL) {
2560 xmlUnlinkNode(old);
2561 return(old);
2562 }
2563 if (cur == old) {
2564 return(old);
2565 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002566 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2567#ifdef DEBUG_TREE
2568 xmlGenericError(xmlGenericErrorContext,
2569 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2570#endif
2571 return(old);
2572 }
2573 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2574#ifdef DEBUG_TREE
2575 xmlGenericError(xmlGenericErrorContext,
2576 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2577#endif
2578 return(old);
2579 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002580 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2581#ifdef DEBUG_TREE
2582 xmlGenericError(xmlGenericErrorContext,
2583 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2584#endif
2585 return(old);
2586 }
2587 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2588#ifdef DEBUG_TREE
2589 xmlGenericError(xmlGenericErrorContext,
2590 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2591#endif
2592 return(old);
2593 }
Owen Taylor3473f882001-02-23 17:55:21 +00002594 xmlUnlinkNode(cur);
2595 cur->doc = old->doc;
2596 cur->parent = old->parent;
2597 cur->next = old->next;
2598 if (cur->next != NULL)
2599 cur->next->prev = cur;
2600 cur->prev = old->prev;
2601 if (cur->prev != NULL)
2602 cur->prev->next = cur;
2603 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002604 if (cur->type == XML_ATTRIBUTE_NODE) {
2605 if (cur->parent->properties == (xmlAttrPtr)old)
2606 cur->parent->properties = ((xmlAttrPtr) cur);
2607 } else {
2608 if (cur->parent->children == old)
2609 cur->parent->children = cur;
2610 if (cur->parent->last == old)
2611 cur->parent->last = cur;
2612 }
Owen Taylor3473f882001-02-23 17:55:21 +00002613 }
2614 old->next = old->prev = NULL;
2615 old->parent = NULL;
2616 return(old);
2617}
2618
2619/************************************************************************
2620 * *
2621 * Copy operations *
2622 * *
2623 ************************************************************************/
2624
2625/**
2626 * xmlCopyNamespace:
2627 * @cur: the namespace
2628 *
2629 * Do a copy of the namespace.
2630 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002631 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002632 */
2633xmlNsPtr
2634xmlCopyNamespace(xmlNsPtr cur) {
2635 xmlNsPtr ret;
2636
2637 if (cur == NULL) return(NULL);
2638 switch (cur->type) {
2639 case XML_LOCAL_NAMESPACE:
2640 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2641 break;
2642 default:
2643#ifdef DEBUG_TREE
2644 xmlGenericError(xmlGenericErrorContext,
2645 "xmlCopyNamespace: invalid type %d\n", cur->type);
2646#endif
2647 return(NULL);
2648 }
2649 return(ret);
2650}
2651
2652/**
2653 * xmlCopyNamespaceList:
2654 * @cur: the first namespace
2655 *
2656 * Do a copy of an namespace list.
2657 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002658 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002659 */
2660xmlNsPtr
2661xmlCopyNamespaceList(xmlNsPtr cur) {
2662 xmlNsPtr ret = NULL;
2663 xmlNsPtr p = NULL,q;
2664
2665 while (cur != NULL) {
2666 q = xmlCopyNamespace(cur);
2667 if (p == NULL) {
2668 ret = p = q;
2669 } else {
2670 p->next = q;
2671 p = q;
2672 }
2673 cur = cur->next;
2674 }
2675 return(ret);
2676}
2677
2678static xmlNodePtr
2679xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2680/**
2681 * xmlCopyProp:
2682 * @target: the element where the attribute will be grafted
2683 * @cur: the attribute
2684 *
2685 * Do a copy of the attribute.
2686 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002687 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002688 */
2689xmlAttrPtr
2690xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2691 xmlAttrPtr ret;
2692
2693 if (cur == NULL) return(NULL);
2694 if (target != NULL)
2695 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2696 else if (cur->parent != NULL)
2697 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2698 else if (cur->children != NULL)
2699 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2700 else
2701 ret = xmlNewDocProp(NULL, cur->name, NULL);
2702 if (ret == NULL) return(NULL);
2703 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002704
Owen Taylor3473f882001-02-23 17:55:21 +00002705 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002706 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002707/*
2708 * if (target->doc)
2709 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2710 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2711 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2712 * else
2713 * ns = NULL;
2714 * ret->ns = ns;
2715 */
2716 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2717 if (ns == NULL) {
2718 /*
2719 * Humm, we are copying an element whose namespace is defined
2720 * out of the new tree scope. Search it in the original tree
2721 * and add it at the top of the new tree
2722 */
2723 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2724 if (ns != NULL) {
2725 xmlNodePtr root = target;
2726 xmlNodePtr pred = NULL;
2727
2728 while (root->parent != NULL) {
2729 pred = root;
2730 root = root->parent;
2731 }
2732 if (root == (xmlNodePtr) target->doc) {
2733 /* correct possibly cycling above the document elt */
2734 root = pred;
2735 }
2736 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2737 }
2738 } else {
2739 /*
2740 * we have to find something appropriate here since
2741 * we cant be sure, that the namespce we found is identified
2742 * by the prefix
2743 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002744 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002745 /* this is the nice case */
2746 ret->ns = ns;
2747 } else {
2748 /*
2749 * we are in trouble: we need a new reconcilied namespace.
2750 * This is expensive
2751 */
2752 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2753 }
2754 }
2755
Owen Taylor3473f882001-02-23 17:55:21 +00002756 } else
2757 ret->ns = NULL;
2758
2759 if (cur->children != NULL) {
2760 xmlNodePtr tmp;
2761
2762 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2763 ret->last = NULL;
2764 tmp = ret->children;
2765 while (tmp != NULL) {
2766 /* tmp->parent = (xmlNodePtr)ret; */
2767 if (tmp->next == NULL)
2768 ret->last = tmp;
2769 tmp = tmp->next;
2770 }
2771 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002772 /*
2773 * Try to handle IDs
2774 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002775 if ((target!= NULL) && (cur!= NULL) &&
2776 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002777 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2778 if (xmlIsID(cur->doc, cur->parent, cur)) {
2779 xmlChar *id;
2780
2781 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2782 if (id != NULL) {
2783 xmlAddID(NULL, target->doc, id, ret);
2784 xmlFree(id);
2785 }
2786 }
2787 }
Owen Taylor3473f882001-02-23 17:55:21 +00002788 return(ret);
2789}
2790
2791/**
2792 * xmlCopyPropList:
2793 * @target: the element where the attributes will be grafted
2794 * @cur: the first attribute
2795 *
2796 * Do a copy of an attribute list.
2797 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002798 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002799 */
2800xmlAttrPtr
2801xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2802 xmlAttrPtr ret = NULL;
2803 xmlAttrPtr p = NULL,q;
2804
2805 while (cur != NULL) {
2806 q = xmlCopyProp(target, cur);
2807 if (p == NULL) {
2808 ret = p = q;
2809 } else {
2810 p->next = q;
2811 q->prev = p;
2812 p = q;
2813 }
2814 cur = cur->next;
2815 }
2816 return(ret);
2817}
2818
2819/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002820 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002821 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002822 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002823 * tricky reason: namespaces. Doing a direct copy of a node
2824 * say RPM:Copyright without changing the namespace pointer to
2825 * something else can produce stale links. One way to do it is
2826 * to keep a reference counter but this doesn't work as soon
2827 * as one move the element or the subtree out of the scope of
2828 * the existing namespace. The actual solution seems to add
2829 * a copy of the namespace at the top of the copied tree if
2830 * not available in the subtree.
2831 * Hence two functions, the public front-end call the inner ones
2832 */
2833
2834static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002835xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002836 int recursive) {
2837 xmlNodePtr ret;
2838
2839 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002840 switch (node->type) {
2841 case XML_TEXT_NODE:
2842 case XML_CDATA_SECTION_NODE:
2843 case XML_ELEMENT_NODE:
2844 case XML_ENTITY_REF_NODE:
2845 case XML_ENTITY_NODE:
2846 case XML_PI_NODE:
2847 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002848 case XML_XINCLUDE_START:
2849 case XML_XINCLUDE_END:
2850 break;
2851 case XML_ATTRIBUTE_NODE:
2852 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2853 case XML_NAMESPACE_DECL:
2854 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2855
Daniel Veillard39196eb2001-06-19 18:09:42 +00002856 case XML_DOCUMENT_NODE:
2857 case XML_HTML_DOCUMENT_NODE:
2858#ifdef LIBXML_DOCB_ENABLED
2859 case XML_DOCB_DOCUMENT_NODE:
2860#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002861 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002862 case XML_DOCUMENT_TYPE_NODE:
2863 case XML_DOCUMENT_FRAG_NODE:
2864 case XML_NOTATION_NODE:
2865 case XML_DTD_NODE:
2866 case XML_ELEMENT_DECL:
2867 case XML_ATTRIBUTE_DECL:
2868 case XML_ENTITY_DECL:
2869 return(NULL);
2870 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002871
Owen Taylor3473f882001-02-23 17:55:21 +00002872 /*
2873 * Allocate a new node and fill the fields.
2874 */
2875 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2876 if (ret == NULL) {
2877 xmlGenericError(xmlGenericErrorContext,
2878 "xmlStaticCopyNode : malloc failed\n");
2879 return(NULL);
2880 }
2881 memset(ret, 0, sizeof(xmlNode));
2882 ret->type = node->type;
2883
2884 ret->doc = doc;
2885 ret->parent = parent;
2886 if (node->name == xmlStringText)
2887 ret->name = xmlStringText;
2888 else if (node->name == xmlStringTextNoenc)
2889 ret->name = xmlStringTextNoenc;
2890 else if (node->name == xmlStringComment)
2891 ret->name = xmlStringComment;
2892 else if (node->name != NULL)
2893 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002894 if ((node->type != XML_ELEMENT_NODE) &&
2895 (node->content != NULL) &&
2896 (node->type != XML_ENTITY_REF_NODE) &&
2897 (node->type != XML_XINCLUDE_END) &&
2898 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002899 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00002900 }else{
2901 if (node->type == XML_ELEMENT_NODE)
2902 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002903 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002904 if (parent != NULL) {
2905 xmlNodePtr tmp;
2906
2907 tmp = xmlAddChild(parent, ret);
2908 /* node could have coalesced */
2909 if (tmp != ret)
2910 return(tmp);
2911 }
Owen Taylor3473f882001-02-23 17:55:21 +00002912
2913 if (!recursive) return(ret);
2914 if (node->nsDef != NULL)
2915 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2916
2917 if (node->ns != NULL) {
2918 xmlNsPtr ns;
2919
2920 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2921 if (ns == NULL) {
2922 /*
2923 * Humm, we are copying an element whose namespace is defined
2924 * out of the new tree scope. Search it in the original tree
2925 * and add it at the top of the new tree
2926 */
2927 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2928 if (ns != NULL) {
2929 xmlNodePtr root = ret;
2930
2931 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002932 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002933 }
2934 } else {
2935 /*
2936 * reference the existing namespace definition in our own tree.
2937 */
2938 ret->ns = ns;
2939 }
2940 }
2941 if (node->properties != NULL)
2942 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002943 if (node->type == XML_ENTITY_REF_NODE) {
2944 if ((doc == NULL) || (node->doc != doc)) {
2945 /*
2946 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002947 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002948 * we cannot keep the reference. Try to find it in the
2949 * target document.
2950 */
2951 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2952 } else {
2953 ret->children = node->children;
2954 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002955 ret->last = ret->children;
2956 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002957 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002958 UPDATE_LAST_CHILD_AND_PARENT(ret)
2959 }
Owen Taylor3473f882001-02-23 17:55:21 +00002960 return(ret);
2961}
2962
2963static xmlNodePtr
2964xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2965 xmlNodePtr ret = NULL;
2966 xmlNodePtr p = NULL,q;
2967
2968 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002969 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002970 if (doc == NULL) {
2971 node = node->next;
2972 continue;
2973 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002974 if (doc->intSubset == NULL) {
2975 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2976 q->doc = doc;
2977 q->parent = parent;
2978 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00002979 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002980 } else {
2981 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00002982 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002983 }
2984 } else
2985 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002986 if (ret == NULL) {
2987 q->prev = NULL;
2988 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002989 } else if (p != q) {
2990 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002991 p->next = q;
2992 q->prev = p;
2993 p = q;
2994 }
2995 node = node->next;
2996 }
2997 return(ret);
2998}
2999
3000/**
3001 * xmlCopyNode:
3002 * @node: the node
3003 * @recursive: if 1 do a recursive copy.
3004 *
3005 * Do a copy of the node.
3006 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003007 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003008 */
3009xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003010xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003011 xmlNodePtr ret;
3012
3013 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3014 return(ret);
3015}
3016
3017/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003018 * xmlDocCopyNode:
3019 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003020 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003021 * @recursive: if 1 do a recursive copy.
3022 *
3023 * Do a copy of the node to a given document.
3024 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003025 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003026 */
3027xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003028xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003029 xmlNodePtr ret;
3030
3031 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3032 return(ret);
3033}
3034
3035/**
Owen Taylor3473f882001-02-23 17:55:21 +00003036 * xmlCopyNodeList:
3037 * @node: the first node in the list.
3038 *
3039 * Do a recursive copy of the node list.
3040 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003041 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003042 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003043xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003044 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3045 return(ret);
3046}
3047
3048/**
Owen Taylor3473f882001-02-23 17:55:21 +00003049 * xmlCopyDtd:
3050 * @dtd: the dtd
3051 *
3052 * Do a copy of the dtd.
3053 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003054 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003055 */
3056xmlDtdPtr
3057xmlCopyDtd(xmlDtdPtr dtd) {
3058 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003059 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003060
3061 if (dtd == NULL) return(NULL);
3062 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3063 if (ret == NULL) return(NULL);
3064 if (dtd->entities != NULL)
3065 ret->entities = (void *) xmlCopyEntitiesTable(
3066 (xmlEntitiesTablePtr) dtd->entities);
3067 if (dtd->notations != NULL)
3068 ret->notations = (void *) xmlCopyNotationTable(
3069 (xmlNotationTablePtr) dtd->notations);
3070 if (dtd->elements != NULL)
3071 ret->elements = (void *) xmlCopyElementTable(
3072 (xmlElementTablePtr) dtd->elements);
3073 if (dtd->attributes != NULL)
3074 ret->attributes = (void *) xmlCopyAttributeTable(
3075 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003076 if (dtd->pentities != NULL)
3077 ret->pentities = (void *) xmlCopyEntitiesTable(
3078 (xmlEntitiesTablePtr) dtd->pentities);
3079
3080 cur = dtd->children;
3081 while (cur != NULL) {
3082 q = NULL;
3083
3084 if (cur->type == XML_ENTITY_DECL) {
3085 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3086 switch (tmp->etype) {
3087 case XML_INTERNAL_GENERAL_ENTITY:
3088 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3089 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3090 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3091 break;
3092 case XML_INTERNAL_PARAMETER_ENTITY:
3093 case XML_EXTERNAL_PARAMETER_ENTITY:
3094 q = (xmlNodePtr)
3095 xmlGetParameterEntityFromDtd(ret, tmp->name);
3096 break;
3097 case XML_INTERNAL_PREDEFINED_ENTITY:
3098 break;
3099 }
3100 } else if (cur->type == XML_ELEMENT_DECL) {
3101 xmlElementPtr tmp = (xmlElementPtr) cur;
3102 q = (xmlNodePtr)
3103 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3104 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3105 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3106 q = (xmlNodePtr)
3107 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3108 } else if (cur->type == XML_COMMENT_NODE) {
3109 q = xmlCopyNode(cur, 0);
3110 }
3111
3112 if (q == NULL) {
3113 cur = cur->next;
3114 continue;
3115 }
3116
3117 if (p == NULL)
3118 ret->children = q;
3119 else
3120 p->next = q;
3121
3122 q->prev = p;
3123 q->parent = (xmlNodePtr) ret;
3124 q->next = NULL;
3125 ret->last = q;
3126 p = q;
3127 cur = cur->next;
3128 }
3129
Owen Taylor3473f882001-02-23 17:55:21 +00003130 return(ret);
3131}
3132
3133/**
3134 * xmlCopyDoc:
3135 * @doc: the document
3136 * @recursive: if 1 do a recursive copy.
3137 *
3138 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003139 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003140 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003141 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003142 */
3143xmlDocPtr
3144xmlCopyDoc(xmlDocPtr doc, int recursive) {
3145 xmlDocPtr ret;
3146
3147 if (doc == NULL) return(NULL);
3148 ret = xmlNewDoc(doc->version);
3149 if (ret == NULL) return(NULL);
3150 if (doc->name != NULL)
3151 ret->name = xmlMemStrdup(doc->name);
3152 if (doc->encoding != NULL)
3153 ret->encoding = xmlStrdup(doc->encoding);
3154 ret->charset = doc->charset;
3155 ret->compression = doc->compression;
3156 ret->standalone = doc->standalone;
3157 if (!recursive) return(ret);
3158
Daniel Veillardb33c2012001-04-25 12:59:04 +00003159 ret->last = NULL;
3160 ret->children = NULL;
3161 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003162 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003163 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003164 ret->intSubset->parent = ret;
3165 }
Owen Taylor3473f882001-02-23 17:55:21 +00003166 if (doc->oldNs != NULL)
3167 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3168 if (doc->children != NULL) {
3169 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003170
3171 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3172 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003173 ret->last = NULL;
3174 tmp = ret->children;
3175 while (tmp != NULL) {
3176 if (tmp->next == NULL)
3177 ret->last = tmp;
3178 tmp = tmp->next;
3179 }
3180 }
3181 return(ret);
3182}
3183
3184/************************************************************************
3185 * *
3186 * Content access functions *
3187 * *
3188 ************************************************************************/
3189
3190/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003191 * xmlGetLineNo:
3192 * @node : valid node
3193 *
3194 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003195 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003196 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003197 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003198 */
3199long
3200xmlGetLineNo(xmlNodePtr node)
3201{
3202 long result = -1;
3203
3204 if (!node)
3205 return result;
3206 if (node->type == XML_ELEMENT_NODE)
3207 result = (long) node->content;
3208 else if ((node->prev != NULL) &&
3209 ((node->prev->type == XML_ELEMENT_NODE) ||
3210 (node->prev->type == XML_TEXT_NODE)))
3211 result = xmlGetLineNo(node->prev);
3212 else if ((node->parent != NULL) &&
3213 ((node->parent->type == XML_ELEMENT_NODE) ||
3214 (node->parent->type == XML_TEXT_NODE)))
3215 result = xmlGetLineNo(node->parent);
3216
3217 return result;
3218}
3219
3220/**
3221 * xmlGetNodePath:
3222 * @node: a node
3223 *
3224 * Build a structure based Path for the given node
3225 *
3226 * Returns the new path or NULL in case of error. The caller must free
3227 * the returned string
3228 */
3229xmlChar *
3230xmlGetNodePath(xmlNodePtr node)
3231{
3232 xmlNodePtr cur, tmp, next;
3233 xmlChar *buffer = NULL, *temp;
3234 size_t buf_len;
3235 xmlChar *buf;
3236 char sep;
3237 const char *name;
3238 char nametemp[100];
3239 int occur = 0;
3240
3241 if (node == NULL)
3242 return (NULL);
3243
3244 buf_len = 500;
3245 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3246 if (buffer == NULL)
3247 return (NULL);
3248 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3249 if (buf == NULL) {
3250 xmlFree(buffer);
3251 return (NULL);
3252 }
3253
3254 buffer[0] = 0;
3255 cur = node;
3256 do {
3257 name = "";
3258 sep = '?';
3259 occur = 0;
3260 if ((cur->type == XML_DOCUMENT_NODE) ||
3261 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3262 if (buffer[0] == '/')
3263 break;
3264 sep = '/';
3265 next = NULL;
3266 } else if (cur->type == XML_ELEMENT_NODE) {
3267 sep = '/';
3268 name = (const char *) cur->name;
3269 if (cur->ns) {
3270 snprintf(nametemp, sizeof(nametemp) - 1,
3271 "%s:%s", cur->ns->prefix, cur->name);
3272 nametemp[sizeof(nametemp) - 1] = 0;
3273 name = nametemp;
3274 }
3275 next = cur->parent;
3276
3277 /*
3278 * Thumbler index computation
3279 */
3280 tmp = cur->prev;
3281 while (tmp != NULL) {
3282 if (xmlStrEqual(cur->name, tmp->name))
3283 occur++;
3284 tmp = tmp->prev;
3285 }
3286 if (occur == 0) {
3287 tmp = cur->next;
3288 while (tmp != NULL) {
3289 if (xmlStrEqual(cur->name, tmp->name))
3290 occur++;
3291 tmp = tmp->next;
3292 }
3293 if (occur != 0)
3294 occur = 1;
3295 } else
3296 occur++;
3297 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3298 sep = '@';
3299 name = (const char *) (((xmlAttrPtr) cur)->name);
3300 next = ((xmlAttrPtr) cur)->parent;
3301 } else {
3302 next = cur->parent;
3303 }
3304
3305 /*
3306 * Make sure there is enough room
3307 */
3308 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3309 buf_len =
3310 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3311 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3312 if (temp == NULL) {
3313 xmlFree(buf);
3314 xmlFree(buffer);
3315 return (NULL);
3316 }
3317 buffer = temp;
3318 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3319 if (temp == NULL) {
3320 xmlFree(buf);
3321 xmlFree(buffer);
3322 return (NULL);
3323 }
3324 buf = temp;
3325 }
3326 if (occur == 0)
3327 snprintf((char *) buf, buf_len, "%c%s%s",
3328 sep, name, (char *) buffer);
3329 else
3330 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3331 sep, name, occur, (char *) buffer);
3332 snprintf((char *) buffer, buf_len, "%s", buf);
3333 cur = next;
3334 } while (cur != NULL);
3335 xmlFree(buf);
3336 return (buffer);
3337}
3338
3339/**
Owen Taylor3473f882001-02-23 17:55:21 +00003340 * xmlDocGetRootElement:
3341 * @doc: the document
3342 *
3343 * Get the root element of the document (doc->children is a list
3344 * containing possibly comments, PIs, etc ...).
3345 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003346 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003347 */
3348xmlNodePtr
3349xmlDocGetRootElement(xmlDocPtr doc) {
3350 xmlNodePtr ret;
3351
3352 if (doc == NULL) return(NULL);
3353 ret = doc->children;
3354 while (ret != NULL) {
3355 if (ret->type == XML_ELEMENT_NODE)
3356 return(ret);
3357 ret = ret->next;
3358 }
3359 return(ret);
3360}
3361
3362/**
3363 * xmlDocSetRootElement:
3364 * @doc: the document
3365 * @root: the new document root element
3366 *
3367 * Set the root element of the document (doc->children is a list
3368 * containing possibly comments, PIs, etc ...).
3369 *
3370 * Returns the old root element if any was found
3371 */
3372xmlNodePtr
3373xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3374 xmlNodePtr old = NULL;
3375
3376 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003377 if (root == NULL)
3378 return(NULL);
3379 xmlUnlinkNode(root);
3380 root->doc = doc;
3381 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003382 old = doc->children;
3383 while (old != NULL) {
3384 if (old->type == XML_ELEMENT_NODE)
3385 break;
3386 old = old->next;
3387 }
3388 if (old == NULL) {
3389 if (doc->children == NULL) {
3390 doc->children = root;
3391 doc->last = root;
3392 } else {
3393 xmlAddSibling(doc->children, root);
3394 }
3395 } else {
3396 xmlReplaceNode(old, root);
3397 }
3398 return(old);
3399}
3400
3401/**
3402 * xmlNodeSetLang:
3403 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003404 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003405 *
3406 * Set the language of a node, i.e. the values of the xml:lang
3407 * attribute.
3408 */
3409void
3410xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003411 xmlNsPtr ns;
3412
Owen Taylor3473f882001-02-23 17:55:21 +00003413 if (cur == NULL) return;
3414 switch(cur->type) {
3415 case XML_TEXT_NODE:
3416 case XML_CDATA_SECTION_NODE:
3417 case XML_COMMENT_NODE:
3418 case XML_DOCUMENT_NODE:
3419 case XML_DOCUMENT_TYPE_NODE:
3420 case XML_DOCUMENT_FRAG_NODE:
3421 case XML_NOTATION_NODE:
3422 case XML_HTML_DOCUMENT_NODE:
3423 case XML_DTD_NODE:
3424 case XML_ELEMENT_DECL:
3425 case XML_ATTRIBUTE_DECL:
3426 case XML_ENTITY_DECL:
3427 case XML_PI_NODE:
3428 case XML_ENTITY_REF_NODE:
3429 case XML_ENTITY_NODE:
3430 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003431#ifdef LIBXML_DOCB_ENABLED
3432 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003433#endif
3434 case XML_XINCLUDE_START:
3435 case XML_XINCLUDE_END:
3436 return;
3437 case XML_ELEMENT_NODE:
3438 case XML_ATTRIBUTE_NODE:
3439 break;
3440 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003441 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3442 if (ns == NULL)
3443 return;
3444 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003445}
3446
3447/**
3448 * xmlNodeGetLang:
3449 * @cur: the node being checked
3450 *
3451 * Searches the language of a node, i.e. the values of the xml:lang
3452 * attribute or the one carried by the nearest ancestor.
3453 *
3454 * Returns a pointer to the lang value, or NULL if not found
3455 * It's up to the caller to free the memory.
3456 */
3457xmlChar *
3458xmlNodeGetLang(xmlNodePtr cur) {
3459 xmlChar *lang;
3460
3461 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003462 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003463 if (lang != NULL)
3464 return(lang);
3465 cur = cur->parent;
3466 }
3467 return(NULL);
3468}
3469
3470
3471/**
3472 * xmlNodeSetSpacePreserve:
3473 * @cur: the node being changed
3474 * @val: the xml:space value ("0": default, 1: "preserve")
3475 *
3476 * Set (or reset) the space preserving behaviour of a node, i.e. the
3477 * value of the xml:space attribute.
3478 */
3479void
3480xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003481 xmlNsPtr ns;
3482
Owen Taylor3473f882001-02-23 17:55:21 +00003483 if (cur == NULL) return;
3484 switch(cur->type) {
3485 case XML_TEXT_NODE:
3486 case XML_CDATA_SECTION_NODE:
3487 case XML_COMMENT_NODE:
3488 case XML_DOCUMENT_NODE:
3489 case XML_DOCUMENT_TYPE_NODE:
3490 case XML_DOCUMENT_FRAG_NODE:
3491 case XML_NOTATION_NODE:
3492 case XML_HTML_DOCUMENT_NODE:
3493 case XML_DTD_NODE:
3494 case XML_ELEMENT_DECL:
3495 case XML_ATTRIBUTE_DECL:
3496 case XML_ENTITY_DECL:
3497 case XML_PI_NODE:
3498 case XML_ENTITY_REF_NODE:
3499 case XML_ENTITY_NODE:
3500 case XML_NAMESPACE_DECL:
3501 case XML_XINCLUDE_START:
3502 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003503#ifdef LIBXML_DOCB_ENABLED
3504 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003505#endif
3506 return;
3507 case XML_ELEMENT_NODE:
3508 case XML_ATTRIBUTE_NODE:
3509 break;
3510 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003511 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3512 if (ns == NULL)
3513 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003514 switch (val) {
3515 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003516 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003517 break;
3518 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003519 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003520 break;
3521 }
3522}
3523
3524/**
3525 * xmlNodeGetSpacePreserve:
3526 * @cur: the node being checked
3527 *
3528 * Searches the space preserving behaviour of a node, i.e. the values
3529 * of the xml:space attribute or the one carried by the nearest
3530 * ancestor.
3531 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003532 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003533 */
3534int
3535xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3536 xmlChar *space;
3537
3538 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003539 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003540 if (space != NULL) {
3541 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3542 xmlFree(space);
3543 return(1);
3544 }
3545 if (xmlStrEqual(space, BAD_CAST "default")) {
3546 xmlFree(space);
3547 return(0);
3548 }
3549 xmlFree(space);
3550 }
3551 cur = cur->parent;
3552 }
3553 return(-1);
3554}
3555
3556/**
3557 * xmlNodeSetName:
3558 * @cur: the node being changed
3559 * @name: the new tag name
3560 *
3561 * Set (or reset) the name of a node.
3562 */
3563void
3564xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3565 if (cur == NULL) return;
3566 if (name == NULL) return;
3567 switch(cur->type) {
3568 case XML_TEXT_NODE:
3569 case XML_CDATA_SECTION_NODE:
3570 case XML_COMMENT_NODE:
3571 case XML_DOCUMENT_TYPE_NODE:
3572 case XML_DOCUMENT_FRAG_NODE:
3573 case XML_NOTATION_NODE:
3574 case XML_HTML_DOCUMENT_NODE:
3575 case XML_NAMESPACE_DECL:
3576 case XML_XINCLUDE_START:
3577 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003578#ifdef LIBXML_DOCB_ENABLED
3579 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003580#endif
3581 return;
3582 case XML_ELEMENT_NODE:
3583 case XML_ATTRIBUTE_NODE:
3584 case XML_PI_NODE:
3585 case XML_ENTITY_REF_NODE:
3586 case XML_ENTITY_NODE:
3587 case XML_DTD_NODE:
3588 case XML_DOCUMENT_NODE:
3589 case XML_ELEMENT_DECL:
3590 case XML_ATTRIBUTE_DECL:
3591 case XML_ENTITY_DECL:
3592 break;
3593 }
3594 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3595 cur->name = xmlStrdup(name);
3596}
3597
3598/**
3599 * xmlNodeSetBase:
3600 * @cur: the node being changed
3601 * @uri: the new base URI
3602 *
3603 * Set (or reset) the base URI of a node, i.e. the value of the
3604 * xml:base attribute.
3605 */
3606void
3607xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003608 xmlNsPtr ns;
3609
Owen Taylor3473f882001-02-23 17:55:21 +00003610 if (cur == NULL) return;
3611 switch(cur->type) {
3612 case XML_TEXT_NODE:
3613 case XML_CDATA_SECTION_NODE:
3614 case XML_COMMENT_NODE:
3615 case XML_DOCUMENT_NODE:
3616 case XML_DOCUMENT_TYPE_NODE:
3617 case XML_DOCUMENT_FRAG_NODE:
3618 case XML_NOTATION_NODE:
3619 case XML_HTML_DOCUMENT_NODE:
3620 case XML_DTD_NODE:
3621 case XML_ELEMENT_DECL:
3622 case XML_ATTRIBUTE_DECL:
3623 case XML_ENTITY_DECL:
3624 case XML_PI_NODE:
3625 case XML_ENTITY_REF_NODE:
3626 case XML_ENTITY_NODE:
3627 case XML_NAMESPACE_DECL:
3628 case XML_XINCLUDE_START:
3629 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003630#ifdef LIBXML_DOCB_ENABLED
3631 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003632#endif
3633 return;
3634 case XML_ELEMENT_NODE:
3635 case XML_ATTRIBUTE_NODE:
3636 break;
3637 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003638
3639 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3640 if (ns == NULL)
3641 return;
3642 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003643}
3644
3645/**
Owen Taylor3473f882001-02-23 17:55:21 +00003646 * xmlNodeGetBase:
3647 * @doc: the document the node pertains to
3648 * @cur: the node being checked
3649 *
3650 * Searches for the BASE URL. The code should work on both XML
3651 * and HTML document even if base mechanisms are completely different.
3652 * It returns the base as defined in RFC 2396 sections
3653 * 5.1.1. Base URI within Document Content
3654 * and
3655 * 5.1.2. Base URI from the Encapsulating Entity
3656 * However it does not return the document base (5.1.3), use
3657 * xmlDocumentGetBase() for this
3658 *
3659 * Returns a pointer to the base URL, or NULL if not found
3660 * It's up to the caller to free the memory.
3661 */
3662xmlChar *
3663xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003664 xmlChar *oldbase = NULL;
3665 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003666
3667 if ((cur == NULL) && (doc == NULL))
3668 return(NULL);
3669 if (doc == NULL) doc = cur->doc;
3670 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3671 cur = doc->children;
3672 while ((cur != NULL) && (cur->name != NULL)) {
3673 if (cur->type != XML_ELEMENT_NODE) {
3674 cur = cur->next;
3675 continue;
3676 }
3677 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3678 cur = cur->children;
3679 continue;
3680 }
3681 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3682 cur = cur->children;
3683 continue;
3684 }
3685 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3686 return(xmlGetProp(cur, BAD_CAST "href"));
3687 }
3688 cur = cur->next;
3689 }
3690 return(NULL);
3691 }
3692 while (cur != NULL) {
3693 if (cur->type == XML_ENTITY_DECL) {
3694 xmlEntityPtr ent = (xmlEntityPtr) cur;
3695 return(xmlStrdup(ent->URI));
3696 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003697 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003698 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003699 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003700 if (oldbase != NULL) {
3701 newbase = xmlBuildURI(oldbase, base);
3702 if (newbase != NULL) {
3703 xmlFree(oldbase);
3704 xmlFree(base);
3705 oldbase = newbase;
3706 } else {
3707 xmlFree(oldbase);
3708 xmlFree(base);
3709 return(NULL);
3710 }
3711 } else {
3712 oldbase = base;
3713 }
3714 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3715 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3716 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3717 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003718 }
3719 }
Owen Taylor3473f882001-02-23 17:55:21 +00003720 cur = cur->parent;
3721 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003722 if ((doc != NULL) && (doc->URL != NULL)) {
3723 if (oldbase == NULL)
3724 return(xmlStrdup(doc->URL));
3725 newbase = xmlBuildURI(oldbase, doc->URL);
3726 xmlFree(oldbase);
3727 return(newbase);
3728 }
3729 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003730}
3731
3732/**
3733 * xmlNodeGetContent:
3734 * @cur: the node being read
3735 *
3736 * Read the value of a node, this can be either the text carried
3737 * directly by this node if it's a TEXT node or the aggregate string
3738 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003739 * Entity references are substituted.
3740 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003741 * It's up to the caller to free the memory.
3742 */
3743xmlChar *
3744xmlNodeGetContent(xmlNodePtr cur) {
3745 if (cur == NULL) return(NULL);
3746 switch (cur->type) {
3747 case XML_DOCUMENT_FRAG_NODE:
3748 case XML_ELEMENT_NODE: {
3749 xmlNodePtr tmp = cur;
3750 xmlBufferPtr buffer;
3751 xmlChar *ret;
3752
3753 buffer = xmlBufferCreate();
3754 if (buffer == NULL)
3755 return(NULL);
3756 while (tmp != NULL) {
3757 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003758 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003759 case XML_TEXT_NODE:
3760 if (tmp->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00003761 xmlBufferCat(buffer, tmp->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003762 break;
3763 case XML_ENTITY_REF_NODE: {
3764 xmlEntityPtr ent;
3765
3766 ent = xmlGetDocEntity(cur->doc, tmp->name);
3767 if (ent != NULL)
3768 xmlBufferCat(buffer, ent->content);
3769 }
3770 default:
3771 break;
3772 }
3773 /*
3774 * Skip to next node
3775 */
3776 if (tmp->children != NULL) {
3777 if (tmp->children->type != XML_ENTITY_DECL) {
3778 tmp = tmp->children;
3779 continue;
3780 }
3781 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003782 if (tmp == cur)
3783 break;
3784
Owen Taylor3473f882001-02-23 17:55:21 +00003785 if (tmp->next != NULL) {
3786 tmp = tmp->next;
3787 continue;
3788 }
3789
3790 do {
3791 tmp = tmp->parent;
3792 if (tmp == NULL)
3793 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003794 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003795 tmp = NULL;
3796 break;
3797 }
3798 if (tmp->next != NULL) {
3799 tmp = tmp->next;
3800 break;
3801 }
3802 } while (tmp != NULL);
3803 }
3804 ret = buffer->content;
3805 buffer->content = NULL;
3806 xmlBufferFree(buffer);
3807 return(ret);
3808 }
3809 case XML_ATTRIBUTE_NODE: {
3810 xmlAttrPtr attr = (xmlAttrPtr) cur;
3811 if (attr->parent != NULL)
3812 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3813 else
3814 return(xmlNodeListGetString(NULL, attr->children, 1));
3815 break;
3816 }
3817 case XML_COMMENT_NODE:
3818 case XML_PI_NODE:
3819 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00003820 return(xmlStrdup(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00003821 return(NULL);
3822 case XML_ENTITY_REF_NODE:
3823 /*
3824 * Locate the entity, and get it's content
3825 * @@@
3826 */
3827 return(NULL);
3828 case XML_ENTITY_NODE:
3829 case XML_DOCUMENT_NODE:
3830 case XML_HTML_DOCUMENT_NODE:
3831 case XML_DOCUMENT_TYPE_NODE:
3832 case XML_NOTATION_NODE:
3833 case XML_DTD_NODE:
3834 case XML_XINCLUDE_START:
3835 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003836#ifdef LIBXML_DOCB_ENABLED
3837 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003838#endif
3839 return(NULL);
3840 case XML_NAMESPACE_DECL:
3841 return(xmlStrdup(((xmlNsPtr)cur)->href));
3842 case XML_ELEMENT_DECL:
3843 /* TODO !!! */
3844 return(NULL);
3845 case XML_ATTRIBUTE_DECL:
3846 /* TODO !!! */
3847 return(NULL);
3848 case XML_ENTITY_DECL:
3849 /* TODO !!! */
3850 return(NULL);
3851 case XML_CDATA_SECTION_NODE:
3852 case XML_TEXT_NODE:
3853 if (cur->content != NULL)
Daniel Veillard9ff88172002-03-11 09:15:32 +00003854 return(xmlStrdup(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00003855 return(NULL);
3856 }
3857 return(NULL);
3858}
3859
3860/**
3861 * xmlNodeSetContent:
3862 * @cur: the node being modified
3863 * @content: the new value of the content
3864 *
3865 * Replace the content of a node.
3866 */
3867void
3868xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3869 if (cur == NULL) {
3870#ifdef DEBUG_TREE
3871 xmlGenericError(xmlGenericErrorContext,
3872 "xmlNodeSetContent : node == NULL\n");
3873#endif
3874 return;
3875 }
3876 switch (cur->type) {
3877 case XML_DOCUMENT_FRAG_NODE:
3878 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003879 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003880 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3881 cur->children = xmlStringGetNodeList(cur->doc, content);
3882 UPDATE_LAST_CHILD_AND_PARENT(cur)
3883 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003884 case XML_TEXT_NODE:
3885 case XML_CDATA_SECTION_NODE:
3886 case XML_ENTITY_REF_NODE:
3887 case XML_ENTITY_NODE:
3888 case XML_PI_NODE:
3889 case XML_COMMENT_NODE:
3890 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003891 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003892 }
3893 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3894 cur->last = cur->children = NULL;
3895 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003896 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00003897 } else
3898 cur->content = NULL;
3899 break;
3900 case XML_DOCUMENT_NODE:
3901 case XML_HTML_DOCUMENT_NODE:
3902 case XML_DOCUMENT_TYPE_NODE:
3903 case XML_XINCLUDE_START:
3904 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003905#ifdef LIBXML_DOCB_ENABLED
3906 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003907#endif
3908 break;
3909 case XML_NOTATION_NODE:
3910 break;
3911 case XML_DTD_NODE:
3912 break;
3913 case XML_NAMESPACE_DECL:
3914 break;
3915 case XML_ELEMENT_DECL:
3916 /* TODO !!! */
3917 break;
3918 case XML_ATTRIBUTE_DECL:
3919 /* TODO !!! */
3920 break;
3921 case XML_ENTITY_DECL:
3922 /* TODO !!! */
3923 break;
3924 }
3925}
3926
3927/**
3928 * xmlNodeSetContentLen:
3929 * @cur: the node being modified
3930 * @content: the new value of the content
3931 * @len: the size of @content
3932 *
3933 * Replace the content of a node.
3934 */
3935void
3936xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3937 if (cur == NULL) {
3938#ifdef DEBUG_TREE
3939 xmlGenericError(xmlGenericErrorContext,
3940 "xmlNodeSetContentLen : node == NULL\n");
3941#endif
3942 return;
3943 }
3944 switch (cur->type) {
3945 case XML_DOCUMENT_FRAG_NODE:
3946 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003947 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003948 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3949 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3950 UPDATE_LAST_CHILD_AND_PARENT(cur)
3951 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003952 case XML_TEXT_NODE:
3953 case XML_CDATA_SECTION_NODE:
3954 case XML_ENTITY_REF_NODE:
3955 case XML_ENTITY_NODE:
3956 case XML_PI_NODE:
3957 case XML_COMMENT_NODE:
3958 case XML_NOTATION_NODE:
3959 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003960 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003961 }
3962 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3963 cur->children = cur->last = NULL;
3964 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003965 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00003966 } else
3967 cur->content = NULL;
3968 break;
3969 case XML_DOCUMENT_NODE:
3970 case XML_DTD_NODE:
3971 case XML_HTML_DOCUMENT_NODE:
3972 case XML_DOCUMENT_TYPE_NODE:
3973 case XML_NAMESPACE_DECL:
3974 case XML_XINCLUDE_START:
3975 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003976#ifdef LIBXML_DOCB_ENABLED
3977 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003978#endif
3979 break;
3980 case XML_ELEMENT_DECL:
3981 /* TODO !!! */
3982 break;
3983 case XML_ATTRIBUTE_DECL:
3984 /* TODO !!! */
3985 break;
3986 case XML_ENTITY_DECL:
3987 /* TODO !!! */
3988 break;
3989 }
3990}
3991
3992/**
3993 * xmlNodeAddContentLen:
3994 * @cur: the node being modified
3995 * @content: extra content
3996 * @len: the size of @content
3997 *
3998 * Append the extra substring to the node content.
3999 */
4000void
4001xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4002 if (cur == NULL) {
4003#ifdef DEBUG_TREE
4004 xmlGenericError(xmlGenericErrorContext,
4005 "xmlNodeAddContentLen : node == NULL\n");
4006#endif
4007 return;
4008 }
4009 if (len <= 0) return;
4010 switch (cur->type) {
4011 case XML_DOCUMENT_FRAG_NODE:
4012 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004013 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004014
Daniel Veillard7db37732001-07-12 01:20:08 +00004015 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004016 newNode = xmlNewTextLen(content, len);
4017 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004018 tmp = xmlAddChild(cur, newNode);
4019 if (tmp != newNode)
4020 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004021 if ((last != NULL) && (last->next == newNode)) {
4022 xmlTextMerge(last, newNode);
4023 }
4024 }
4025 break;
4026 }
4027 case XML_ATTRIBUTE_NODE:
4028 break;
4029 case XML_TEXT_NODE:
4030 case XML_CDATA_SECTION_NODE:
4031 case XML_ENTITY_REF_NODE:
4032 case XML_ENTITY_NODE:
4033 case XML_PI_NODE:
4034 case XML_COMMENT_NODE:
4035 case XML_NOTATION_NODE:
4036 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004037 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004038 }
4039 case XML_DOCUMENT_NODE:
4040 case XML_DTD_NODE:
4041 case XML_HTML_DOCUMENT_NODE:
4042 case XML_DOCUMENT_TYPE_NODE:
4043 case XML_NAMESPACE_DECL:
4044 case XML_XINCLUDE_START:
4045 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004046#ifdef LIBXML_DOCB_ENABLED
4047 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004048#endif
4049 break;
4050 case XML_ELEMENT_DECL:
4051 case XML_ATTRIBUTE_DECL:
4052 case XML_ENTITY_DECL:
4053 break;
4054 }
4055}
4056
4057/**
4058 * xmlNodeAddContent:
4059 * @cur: the node being modified
4060 * @content: extra content
4061 *
4062 * Append the extra substring to the node content.
4063 */
4064void
4065xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4066 int len;
4067
4068 if (cur == NULL) {
4069#ifdef DEBUG_TREE
4070 xmlGenericError(xmlGenericErrorContext,
4071 "xmlNodeAddContent : node == NULL\n");
4072#endif
4073 return;
4074 }
4075 if (content == NULL) return;
4076 len = xmlStrlen(content);
4077 xmlNodeAddContentLen(cur, content, len);
4078}
4079
4080/**
4081 * xmlTextMerge:
4082 * @first: the first text node
4083 * @second: the second text node being merged
4084 *
4085 * Merge two text nodes into one
4086 * Returns the first text node augmented
4087 */
4088xmlNodePtr
4089xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4090 if (first == NULL) return(second);
4091 if (second == NULL) return(first);
4092 if (first->type != XML_TEXT_NODE) return(first);
4093 if (second->type != XML_TEXT_NODE) return(first);
4094 if (second->name != first->name)
4095 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004096 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004097 xmlUnlinkNode(second);
4098 xmlFreeNode(second);
4099 return(first);
4100}
4101
4102/**
4103 * xmlGetNsList:
4104 * @doc: the document
4105 * @node: the current node
4106 *
4107 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004108 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004109 * that need to be freed by the caller or NULL if no
4110 * namespace if defined
4111 */
4112xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004113xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4114{
Owen Taylor3473f882001-02-23 17:55:21 +00004115 xmlNsPtr cur;
4116 xmlNsPtr *ret = NULL;
4117 int nbns = 0;
4118 int maxns = 10;
4119 int i;
4120
4121 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004122 if (node->type == XML_ELEMENT_NODE) {
4123 cur = node->nsDef;
4124 while (cur != NULL) {
4125 if (ret == NULL) {
4126 ret =
4127 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4128 sizeof(xmlNsPtr));
4129 if (ret == NULL) {
4130 xmlGenericError(xmlGenericErrorContext,
4131 "xmlGetNsList : out of memory!\n");
4132 return (NULL);
4133 }
4134 ret[nbns] = NULL;
4135 }
4136 for (i = 0; i < nbns; i++) {
4137 if ((cur->prefix == ret[i]->prefix) ||
4138 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4139 break;
4140 }
4141 if (i >= nbns) {
4142 if (nbns >= maxns) {
4143 maxns *= 2;
4144 ret = (xmlNsPtr *) xmlRealloc(ret,
4145 (maxns +
4146 1) *
4147 sizeof(xmlNsPtr));
4148 if (ret == NULL) {
4149 xmlGenericError(xmlGenericErrorContext,
4150 "xmlGetNsList : realloc failed!\n");
4151 return (NULL);
4152 }
4153 }
4154 ret[nbns++] = cur;
4155 ret[nbns] = NULL;
4156 }
Owen Taylor3473f882001-02-23 17:55:21 +00004157
Daniel Veillard77044732001-06-29 21:31:07 +00004158 cur = cur->next;
4159 }
4160 }
4161 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004162 }
Daniel Veillard77044732001-06-29 21:31:07 +00004163 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004164}
4165
4166/**
4167 * xmlSearchNs:
4168 * @doc: the document
4169 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004170 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004171 *
4172 * Search a Ns registered under a given name space for a document.
4173 * recurse on the parents until it finds the defined namespace
4174 * or return NULL otherwise.
4175 * @nameSpace can be NULL, this is a search for the default namespace.
4176 * We don't allow to cross entities boundaries. If you don't declare
4177 * the namespace within those you will be in troubles !!! A warning
4178 * is generated to cover this case.
4179 *
4180 * Returns the namespace pointer or NULL.
4181 */
4182xmlNsPtr
4183xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4184 xmlNsPtr cur;
4185
4186 if (node == NULL) return(NULL);
4187 if ((nameSpace != NULL) &&
4188 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004189 if (doc == NULL)
4190 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004191 if (doc->oldNs == NULL) {
4192 /*
4193 * Allocate a new Namespace and fill the fields.
4194 */
4195 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4196 if (doc->oldNs == NULL) {
4197 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004198 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004199 return(NULL);
4200 }
4201 memset(doc->oldNs, 0, sizeof(xmlNs));
4202 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4203
4204 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4205 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4206 }
4207 return(doc->oldNs);
4208 }
4209 while (node != NULL) {
4210 if ((node->type == XML_ENTITY_REF_NODE) ||
4211 (node->type == XML_ENTITY_NODE) ||
4212 (node->type == XML_ENTITY_DECL))
4213 return(NULL);
4214 if (node->type == XML_ELEMENT_NODE) {
4215 cur = node->nsDef;
4216 while (cur != NULL) {
4217 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4218 (cur->href != NULL))
4219 return(cur);
4220 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4221 (cur->href != NULL) &&
4222 (xmlStrEqual(cur->prefix, nameSpace)))
4223 return(cur);
4224 cur = cur->next;
4225 }
4226 }
4227 node = node->parent;
4228 }
4229 return(NULL);
4230}
4231
4232/**
4233 * xmlSearchNsByHref:
4234 * @doc: the document
4235 * @node: the current node
4236 * @href: the namespace value
4237 *
4238 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4239 * the defined namespace or return NULL otherwise.
4240 * Returns the namespace pointer or NULL.
4241 */
4242xmlNsPtr
4243xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4244 xmlNsPtr cur;
4245 xmlNodePtr orig = node;
4246
4247 if ((node == NULL) || (href == NULL)) return(NULL);
4248 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004249 /*
4250 * Only the document can hold the XML spec namespace.
4251 */
4252 if (doc == NULL)
4253 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004254 if (doc->oldNs == NULL) {
4255 /*
4256 * Allocate a new Namespace and fill the fields.
4257 */
4258 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4259 if (doc->oldNs == NULL) {
4260 xmlGenericError(xmlGenericErrorContext,
4261 "xmlSearchNsByHref : malloc failed\n");
4262 return(NULL);
4263 }
4264 memset(doc->oldNs, 0, sizeof(xmlNs));
4265 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4266
4267 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4268 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4269 }
4270 return(doc->oldNs);
4271 }
4272 while (node != NULL) {
4273 cur = node->nsDef;
4274 while (cur != NULL) {
4275 if ((cur->href != NULL) && (href != NULL) &&
4276 (xmlStrEqual(cur->href, href))) {
4277 /*
4278 * Check that the prefix is not shadowed between orig and node
4279 */
4280 xmlNodePtr check = orig;
4281 xmlNsPtr tst;
4282
4283 while (check != node) {
4284 tst = check->nsDef;
4285 while (tst != NULL) {
4286 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4287 goto shadowed;
4288 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4289 (xmlStrEqual(tst->prefix, cur->prefix)))
4290 goto shadowed;
4291 tst = tst->next;
4292 }
4293 check = check->parent;
4294 }
4295 return(cur);
4296 }
4297shadowed:
4298 cur = cur->next;
4299 }
4300 node = node->parent;
4301 }
4302 return(NULL);
4303}
4304
4305/**
4306 * xmlNewReconciliedNs
4307 * @doc: the document
4308 * @tree: a node expected to hold the new namespace
4309 * @ns: the original namespace
4310 *
4311 * This function tries to locate a namespace definition in a tree
4312 * ancestors, or create a new namespace definition node similar to
4313 * @ns trying to reuse the same prefix. However if the given prefix is
4314 * null (default namespace) or reused within the subtree defined by
4315 * @tree or on one of its ancestors then a new prefix is generated.
4316 * Returns the (new) namespace definition or NULL in case of error
4317 */
4318xmlNsPtr
4319xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4320 xmlNsPtr def;
4321 xmlChar prefix[50];
4322 int counter = 1;
4323
4324 if (tree == NULL) {
4325#ifdef DEBUG_TREE
4326 xmlGenericError(xmlGenericErrorContext,
4327 "xmlNewReconciliedNs : tree == NULL\n");
4328#endif
4329 return(NULL);
4330 }
4331 if (ns == NULL) {
4332#ifdef DEBUG_TREE
4333 xmlGenericError(xmlGenericErrorContext,
4334 "xmlNewReconciliedNs : ns == NULL\n");
4335#endif
4336 return(NULL);
4337 }
4338 /*
4339 * Search an existing namespace definition inherited.
4340 */
4341 def = xmlSearchNsByHref(doc, tree, ns->href);
4342 if (def != NULL)
4343 return(def);
4344
4345 /*
4346 * Find a close prefix which is not already in use.
4347 * Let's strip namespace prefixes longer than 20 chars !
4348 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004349 if (ns->prefix == NULL)
4350 sprintf((char *) prefix, "default");
4351 else
4352 sprintf((char *) prefix, "%.20s", ns->prefix);
4353
Owen Taylor3473f882001-02-23 17:55:21 +00004354 def = xmlSearchNs(doc, tree, prefix);
4355 while (def != NULL) {
4356 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004357 if (ns->prefix == NULL)
4358 sprintf((char *) prefix, "default%d", counter++);
4359 else
4360 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004361 def = xmlSearchNs(doc, tree, prefix);
4362 }
4363
4364 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004365 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004366 */
4367 def = xmlNewNs(tree, ns->href, prefix);
4368 return(def);
4369}
4370
4371/**
4372 * xmlReconciliateNs
4373 * @doc: the document
4374 * @tree: a node defining the subtree to reconciliate
4375 *
4376 * This function checks that all the namespaces declared within the given
4377 * tree are properly declared. This is needed for example after Copy or Cut
4378 * and then paste operations. The subtree may still hold pointers to
4379 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004380 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004381 * the new environment. If not possible the new namespaces are redeclared
4382 * on @tree at the top of the given subtree.
4383 * Returns the number of namespace declarations created or -1 in case of error.
4384 */
4385int
4386xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4387 xmlNsPtr *oldNs = NULL;
4388 xmlNsPtr *newNs = NULL;
4389 int sizeCache = 0;
4390 int nbCache = 0;
4391
4392 xmlNsPtr n;
4393 xmlNodePtr node = tree;
4394 xmlAttrPtr attr;
4395 int ret = 0, i;
4396
4397 while (node != NULL) {
4398 /*
4399 * Reconciliate the node namespace
4400 */
4401 if (node->ns != NULL) {
4402 /*
4403 * initialize the cache if needed
4404 */
4405 if (sizeCache == 0) {
4406 sizeCache = 10;
4407 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4408 sizeof(xmlNsPtr));
4409 if (oldNs == NULL) {
4410 xmlGenericError(xmlGenericErrorContext,
4411 "xmlReconciliateNs : memory pbm\n");
4412 return(-1);
4413 }
4414 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4415 sizeof(xmlNsPtr));
4416 if (newNs == NULL) {
4417 xmlGenericError(xmlGenericErrorContext,
4418 "xmlReconciliateNs : memory pbm\n");
4419 xmlFree(oldNs);
4420 return(-1);
4421 }
4422 }
4423 for (i = 0;i < nbCache;i++) {
4424 if (oldNs[i] == node->ns) {
4425 node->ns = newNs[i];
4426 break;
4427 }
4428 }
4429 if (i == nbCache) {
4430 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004431 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004432 */
4433 n = xmlNewReconciliedNs(doc, tree, node->ns);
4434 if (n != NULL) { /* :-( what if else ??? */
4435 /*
4436 * check if we need to grow the cache buffers.
4437 */
4438 if (sizeCache <= nbCache) {
4439 sizeCache *= 2;
4440 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4441 sizeof(xmlNsPtr));
4442 if (oldNs == NULL) {
4443 xmlGenericError(xmlGenericErrorContext,
4444 "xmlReconciliateNs : memory pbm\n");
4445 xmlFree(newNs);
4446 return(-1);
4447 }
4448 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4449 sizeof(xmlNsPtr));
4450 if (newNs == NULL) {
4451 xmlGenericError(xmlGenericErrorContext,
4452 "xmlReconciliateNs : memory pbm\n");
4453 xmlFree(oldNs);
4454 return(-1);
4455 }
4456 }
4457 newNs[nbCache] = n;
4458 oldNs[nbCache++] = node->ns;
4459 node->ns = n;
4460 }
4461 }
4462 }
4463 /*
4464 * now check for namespace hold by attributes on the node.
4465 */
4466 attr = node->properties;
4467 while (attr != NULL) {
4468 if (attr->ns != NULL) {
4469 /*
4470 * initialize the cache if needed
4471 */
4472 if (sizeCache == 0) {
4473 sizeCache = 10;
4474 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4475 sizeof(xmlNsPtr));
4476 if (oldNs == NULL) {
4477 xmlGenericError(xmlGenericErrorContext,
4478 "xmlReconciliateNs : memory pbm\n");
4479 return(-1);
4480 }
4481 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4482 sizeof(xmlNsPtr));
4483 if (newNs == NULL) {
4484 xmlGenericError(xmlGenericErrorContext,
4485 "xmlReconciliateNs : memory pbm\n");
4486 xmlFree(oldNs);
4487 return(-1);
4488 }
4489 }
4490 for (i = 0;i < nbCache;i++) {
4491 if (oldNs[i] == attr->ns) {
4492 node->ns = newNs[i];
4493 break;
4494 }
4495 }
4496 if (i == nbCache) {
4497 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004498 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004499 */
4500 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4501 if (n != NULL) { /* :-( what if else ??? */
4502 /*
4503 * check if we need to grow the cache buffers.
4504 */
4505 if (sizeCache <= nbCache) {
4506 sizeCache *= 2;
4507 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4508 sizeof(xmlNsPtr));
4509 if (oldNs == NULL) {
4510 xmlGenericError(xmlGenericErrorContext,
4511 "xmlReconciliateNs : memory pbm\n");
4512 xmlFree(newNs);
4513 return(-1);
4514 }
4515 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4516 sizeof(xmlNsPtr));
4517 if (newNs == NULL) {
4518 xmlGenericError(xmlGenericErrorContext,
4519 "xmlReconciliateNs : memory pbm\n");
4520 xmlFree(oldNs);
4521 return(-1);
4522 }
4523 }
4524 newNs[nbCache] = n;
4525 oldNs[nbCache++] = attr->ns;
4526 attr->ns = n;
4527 }
4528 }
4529 }
4530 attr = attr->next;
4531 }
4532
4533 /*
4534 * Browse the full subtree, deep first
4535 */
4536 if (node->children != NULL) {
4537 /* deep first */
4538 node = node->children;
4539 } else if ((node != tree) && (node->next != NULL)) {
4540 /* then siblings */
4541 node = node->next;
4542 } else if (node != tree) {
4543 /* go up to parents->next if needed */
4544 while (node != tree) {
4545 if (node->parent != NULL)
4546 node = node->parent;
4547 if ((node != tree) && (node->next != NULL)) {
4548 node = node->next;
4549 break;
4550 }
4551 if (node->parent == NULL) {
4552 node = NULL;
4553 break;
4554 }
4555 }
4556 /* exit condition */
4557 if (node == tree)
4558 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004559 } else
4560 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004561 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004562 if (oldNs != NULL)
4563 xmlFree(oldNs);
4564 if (newNs != NULL)
4565 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004566 return(ret);
4567}
4568
4569/**
4570 * xmlHasProp:
4571 * @node: the node
4572 * @name: the attribute name
4573 *
4574 * Search an attribute associated to a node
4575 * This function also looks in DTD attribute declaration for #FIXED or
4576 * default declaration values unless DTD use has been turned off.
4577 *
4578 * Returns the attribute or the attribute declaration or NULL if
4579 * neither was found.
4580 */
4581xmlAttrPtr
4582xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4583 xmlAttrPtr prop;
4584 xmlDocPtr doc;
4585
4586 if ((node == NULL) || (name == NULL)) return(NULL);
4587 /*
4588 * Check on the properties attached to the node
4589 */
4590 prop = node->properties;
4591 while (prop != NULL) {
4592 if (xmlStrEqual(prop->name, name)) {
4593 return(prop);
4594 }
4595 prop = prop->next;
4596 }
4597 if (!xmlCheckDTD) return(NULL);
4598
4599 /*
4600 * Check if there is a default declaration in the internal
4601 * or external subsets
4602 */
4603 doc = node->doc;
4604 if (doc != NULL) {
4605 xmlAttributePtr attrDecl;
4606 if (doc->intSubset != NULL) {
4607 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4608 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4609 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4610 if (attrDecl != NULL)
4611 return((xmlAttrPtr) attrDecl);
4612 }
4613 }
4614 return(NULL);
4615}
4616
4617/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004618 * xmlHasNsProp:
4619 * @node: the node
4620 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004621 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004622 *
4623 * Search for an attribute associated to a node
4624 * This attribute has to be anchored in the namespace specified.
4625 * This does the entity substitution.
4626 * This function looks in DTD attribute declaration for #FIXED or
4627 * default declaration values unless DTD use has been turned off.
4628 *
4629 * Returns the attribute or the attribute declaration or NULL
4630 * if neither was found.
4631 */
4632xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004633xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004634 xmlAttrPtr prop;
4635 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004636
4637 if (node == NULL)
4638 return(NULL);
4639
4640 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004641 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004642 return(xmlHasProp(node, name));
4643 while (prop != NULL) {
4644 /*
4645 * One need to have
4646 * - same attribute names
4647 * - and the attribute carrying that namespace
4648 * or
4649 * no namespace on the attribute and the element carrying it
4650 */
4651 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004652 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4653 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004654 }
4655 prop = prop->next;
4656 }
4657 if (!xmlCheckDTD) return(NULL);
4658
4659 /*
4660 * Check if there is a default declaration in the internal
4661 * or external subsets
4662 */
4663 doc = node->doc;
4664 if (doc != NULL) {
4665 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004666 xmlAttributePtr attrDecl = NULL;
4667 xmlNsPtr *nsList, *cur;
4668 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004669
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004670 nsList = xmlGetNsList(node->doc, node);
4671 if (nsList == NULL)
4672 return(NULL);
4673 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4674 ename = xmlStrdup(node->ns->prefix);
4675 ename = xmlStrcat(ename, BAD_CAST ":");
4676 ename = xmlStrcat(ename, node->name);
4677 } else {
4678 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004679 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004680 if (ename == NULL) {
4681 xmlFree(nsList);
4682 return(NULL);
4683 }
4684
4685 cur = nsList;
4686 while (*cur != NULL) {
4687 if (xmlStrEqual((*cur)->href, nameSpace)) {
4688 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4689 name, (*cur)->prefix);
4690 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4691 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4692 name, (*cur)->prefix);
4693 }
4694 cur++;
4695 }
4696 xmlFree(nsList);
4697 xmlFree(ename);
4698 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004699 }
4700 }
4701 return(NULL);
4702}
4703
4704/**
Owen Taylor3473f882001-02-23 17:55:21 +00004705 * xmlGetProp:
4706 * @node: the node
4707 * @name: the attribute name
4708 *
4709 * Search and get the value of an attribute associated to a node
4710 * This does the entity substitution.
4711 * This function looks in DTD attribute declaration for #FIXED or
4712 * default declaration values unless DTD use has been turned off.
4713 *
4714 * Returns the attribute value or NULL if not found.
4715 * It's up to the caller to free the memory.
4716 */
4717xmlChar *
4718xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4719 xmlAttrPtr prop;
4720 xmlDocPtr doc;
4721
4722 if ((node == NULL) || (name == NULL)) return(NULL);
4723 /*
4724 * Check on the properties attached to the node
4725 */
4726 prop = node->properties;
4727 while (prop != NULL) {
4728 if (xmlStrEqual(prop->name, name)) {
4729 xmlChar *ret;
4730
4731 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4732 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4733 return(ret);
4734 }
4735 prop = prop->next;
4736 }
4737 if (!xmlCheckDTD) return(NULL);
4738
4739 /*
4740 * Check if there is a default declaration in the internal
4741 * or external subsets
4742 */
4743 doc = node->doc;
4744 if (doc != NULL) {
4745 xmlAttributePtr attrDecl;
4746 if (doc->intSubset != NULL) {
4747 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4748 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4749 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4750 if (attrDecl != NULL)
4751 return(xmlStrdup(attrDecl->defaultValue));
4752 }
4753 }
4754 return(NULL);
4755}
4756
4757/**
4758 * xmlGetNsProp:
4759 * @node: the node
4760 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004761 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004762 *
4763 * Search and get the value of an attribute associated to a node
4764 * This attribute has to be anchored in the namespace specified.
4765 * This does the entity substitution.
4766 * This function looks in DTD attribute declaration for #FIXED or
4767 * default declaration values unless DTD use has been turned off.
4768 *
4769 * Returns the attribute value or NULL if not found.
4770 * It's up to the caller to free the memory.
4771 */
4772xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004773xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004774 xmlAttrPtr prop;
4775 xmlDocPtr doc;
4776 xmlNsPtr ns;
4777
4778 if (node == NULL)
4779 return(NULL);
4780
4781 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004782 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004783 return(xmlGetProp(node, name));
4784 while (prop != NULL) {
4785 /*
4786 * One need to have
4787 * - same attribute names
4788 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004789 */
4790 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004791 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004792 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004793 xmlChar *ret;
4794
4795 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4796 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4797 return(ret);
4798 }
4799 prop = prop->next;
4800 }
4801 if (!xmlCheckDTD) return(NULL);
4802
4803 /*
4804 * Check if there is a default declaration in the internal
4805 * or external subsets
4806 */
4807 doc = node->doc;
4808 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004809 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004810 xmlAttributePtr attrDecl;
4811
Owen Taylor3473f882001-02-23 17:55:21 +00004812 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4813 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4814 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4815
4816 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4817 /*
4818 * The DTD declaration only allows a prefix search
4819 */
4820 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004821 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004822 return(xmlStrdup(attrDecl->defaultValue));
4823 }
4824 }
4825 }
4826 return(NULL);
4827}
4828
4829/**
4830 * xmlSetProp:
4831 * @node: the node
4832 * @name: the attribute name
4833 * @value: the attribute value
4834 *
4835 * Set (or reset) an attribute carried by a node.
4836 * Returns the attribute pointer.
4837 */
4838xmlAttrPtr
4839xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004840 xmlAttrPtr prop;
4841 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004842
4843 if ((node == NULL) || (name == NULL))
4844 return(NULL);
4845 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004846 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004847 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004848 if ((xmlStrEqual(prop->name, name)) &&
4849 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004850 xmlNodePtr oldprop = prop->children;
4851
Owen Taylor3473f882001-02-23 17:55:21 +00004852 prop->children = NULL;
4853 prop->last = NULL;
4854 if (value != NULL) {
4855 xmlChar *buffer;
4856 xmlNodePtr tmp;
4857
4858 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4859 prop->children = xmlStringGetNodeList(node->doc, buffer);
4860 prop->last = NULL;
4861 prop->doc = doc;
4862 tmp = prop->children;
4863 while (tmp != NULL) {
4864 tmp->parent = (xmlNodePtr) prop;
4865 tmp->doc = doc;
4866 if (tmp->next == NULL)
4867 prop->last = tmp;
4868 tmp = tmp->next;
4869 }
4870 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004871 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004872 if (oldprop != NULL)
4873 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004874 return(prop);
4875 }
4876 prop = prop->next;
4877 }
4878 prop = xmlNewProp(node, name, value);
4879 return(prop);
4880}
4881
4882/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004883 * xmlUnsetProp:
4884 * @node: the node
4885 * @name: the attribute name
4886 *
4887 * Remove an attribute carried by a node.
4888 * Returns 0 if successful, -1 if not found
4889 */
4890int
4891xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4892 xmlAttrPtr prop = node->properties, prev = NULL;;
4893
4894 if ((node == NULL) || (name == NULL))
4895 return(-1);
4896 while (prop != NULL) {
4897 if ((xmlStrEqual(prop->name, name)) &&
4898 (prop->ns == NULL)) {
4899 if (prev == NULL)
4900 node->properties = prop->next;
4901 else
4902 prev->next = prop->next;
4903 xmlFreeProp(prop);
4904 return(0);
4905 }
4906 prev = prop;
4907 prop = prop->next;
4908 }
4909 return(-1);
4910}
4911
4912/**
Owen Taylor3473f882001-02-23 17:55:21 +00004913 * xmlSetNsProp:
4914 * @node: the node
4915 * @ns: the namespace definition
4916 * @name: the attribute name
4917 * @value: the attribute value
4918 *
4919 * Set (or reset) an attribute carried by a node.
4920 * The ns structure must be in scope, this is not checked.
4921 *
4922 * Returns the attribute pointer.
4923 */
4924xmlAttrPtr
4925xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4926 const xmlChar *value) {
4927 xmlAttrPtr prop;
4928
4929 if ((node == NULL) || (name == NULL))
4930 return(NULL);
4931
4932 if (ns == NULL)
4933 return(xmlSetProp(node, name, value));
4934 if (ns->href == NULL)
4935 return(NULL);
4936 prop = node->properties;
4937
4938 while (prop != NULL) {
4939 /*
4940 * One need to have
4941 * - same attribute names
4942 * - and the attribute carrying that namespace
4943 * or
4944 * no namespace on the attribute and the element carrying it
4945 */
4946 if ((xmlStrEqual(prop->name, name)) &&
4947 (((prop->ns == NULL) && (node->ns != NULL) &&
4948 (xmlStrEqual(node->ns->href, ns->href))) ||
4949 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4950 if (prop->children != NULL)
4951 xmlFreeNodeList(prop->children);
4952 prop->children = NULL;
4953 prop->last = NULL;
4954 prop->ns = ns;
4955 if (value != NULL) {
4956 xmlChar *buffer;
4957 xmlNodePtr tmp;
4958
4959 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4960 prop->children = xmlStringGetNodeList(node->doc, buffer);
4961 prop->last = NULL;
4962 tmp = prop->children;
4963 while (tmp != NULL) {
4964 tmp->parent = (xmlNodePtr) prop;
4965 if (tmp->next == NULL)
4966 prop->last = tmp;
4967 tmp = tmp->next;
4968 }
4969 xmlFree(buffer);
4970 }
4971 return(prop);
4972 }
4973 prop = prop->next;
4974 }
4975 prop = xmlNewNsProp(node, ns, name, value);
4976 return(prop);
4977}
4978
4979/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004980 * xmlUnsetNsProp:
4981 * @node: the node
4982 * @ns: the namespace definition
4983 * @name: the attribute name
4984 *
4985 * Remove an attribute carried by a node.
4986 * Returns 0 if successful, -1 if not found
4987 */
4988int
4989xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4990 xmlAttrPtr prop = node->properties, prev = NULL;;
4991
4992 if ((node == NULL) || (name == NULL))
4993 return(-1);
4994 if (ns == NULL)
4995 return(xmlUnsetProp(node, name));
4996 if (ns->href == NULL)
4997 return(-1);
4998 while (prop != NULL) {
4999 if ((xmlStrEqual(prop->name, name)) &&
5000 (((prop->ns == NULL) && (node->ns != NULL) &&
5001 (xmlStrEqual(node->ns->href, ns->href))) ||
5002 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5003 if (prev == NULL)
5004 node->properties = prop->next;
5005 else
5006 prev->next = prop->next;
5007 xmlFreeProp(prop);
5008 return(0);
5009 }
5010 prev = prop;
5011 prop = prop->next;
5012 }
5013 return(-1);
5014}
5015
5016/**
Owen Taylor3473f882001-02-23 17:55:21 +00005017 * xmlNodeIsText:
5018 * @node: the node
5019 *
5020 * Is this node a Text node ?
5021 * Returns 1 yes, 0 no
5022 */
5023int
5024xmlNodeIsText(xmlNodePtr node) {
5025 if (node == NULL) return(0);
5026
5027 if (node->type == XML_TEXT_NODE) return(1);
5028 return(0);
5029}
5030
5031/**
5032 * xmlIsBlankNode:
5033 * @node: the node
5034 *
5035 * Checks whether this node is an empty or whitespace only
5036 * (and possibly ignorable) text-node.
5037 *
5038 * Returns 1 yes, 0 no
5039 */
5040int
5041xmlIsBlankNode(xmlNodePtr node) {
5042 const xmlChar *cur;
5043 if (node == NULL) return(0);
5044
Daniel Veillard7db37732001-07-12 01:20:08 +00005045 if ((node->type != XML_TEXT_NODE) &&
5046 (node->type != XML_CDATA_SECTION_NODE))
5047 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005048 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005049 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005050 while (*cur != 0) {
5051 if (!IS_BLANK(*cur)) return(0);
5052 cur++;
5053 }
5054
5055 return(1);
5056}
5057
5058/**
5059 * xmlTextConcat:
5060 * @node: the node
5061 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005062 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005063 *
5064 * Concat the given string at the end of the existing node content
5065 */
5066
5067void
5068xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5069 if (node == NULL) return;
5070
5071 if ((node->type != XML_TEXT_NODE) &&
5072 (node->type != XML_CDATA_SECTION_NODE)) {
5073#ifdef DEBUG_TREE
5074 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005075 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005076#endif
5077 return;
5078 }
Owen Taylor3473f882001-02-23 17:55:21 +00005079 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005080}
5081
5082/************************************************************************
5083 * *
5084 * Output : to a FILE or in memory *
5085 * *
5086 ************************************************************************/
5087
Owen Taylor3473f882001-02-23 17:55:21 +00005088/**
5089 * xmlBufferCreate:
5090 *
5091 * routine to create an XML buffer.
5092 * returns the new structure.
5093 */
5094xmlBufferPtr
5095xmlBufferCreate(void) {
5096 xmlBufferPtr ret;
5097
5098 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5099 if (ret == NULL) {
5100 xmlGenericError(xmlGenericErrorContext,
5101 "xmlBufferCreate : out of memory!\n");
5102 return(NULL);
5103 }
5104 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005105 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005106 ret->alloc = xmlBufferAllocScheme;
5107 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5108 if (ret->content == NULL) {
5109 xmlGenericError(xmlGenericErrorContext,
5110 "xmlBufferCreate : out of memory!\n");
5111 xmlFree(ret);
5112 return(NULL);
5113 }
5114 ret->content[0] = 0;
5115 return(ret);
5116}
5117
5118/**
5119 * xmlBufferCreateSize:
5120 * @size: initial size of buffer
5121 *
5122 * routine to create an XML buffer.
5123 * returns the new structure.
5124 */
5125xmlBufferPtr
5126xmlBufferCreateSize(size_t size) {
5127 xmlBufferPtr ret;
5128
5129 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5130 if (ret == NULL) {
5131 xmlGenericError(xmlGenericErrorContext,
5132 "xmlBufferCreate : out of memory!\n");
5133 return(NULL);
5134 }
5135 ret->use = 0;
5136 ret->alloc = xmlBufferAllocScheme;
5137 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5138 if (ret->size){
5139 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5140 if (ret->content == NULL) {
5141 xmlGenericError(xmlGenericErrorContext,
5142 "xmlBufferCreate : out of memory!\n");
5143 xmlFree(ret);
5144 return(NULL);
5145 }
5146 ret->content[0] = 0;
5147 } else
5148 ret->content = NULL;
5149 return(ret);
5150}
5151
5152/**
5153 * xmlBufferSetAllocationScheme:
5154 * @buf: the buffer to free
5155 * @scheme: allocation scheme to use
5156 *
5157 * Sets the allocation scheme for this buffer
5158 */
5159void
5160xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5161 xmlBufferAllocationScheme scheme) {
5162 if (buf == NULL) {
5163#ifdef DEBUG_BUFFER
5164 xmlGenericError(xmlGenericErrorContext,
5165 "xmlBufferSetAllocationScheme: buf == NULL\n");
5166#endif
5167 return;
5168 }
5169
5170 buf->alloc = scheme;
5171}
5172
5173/**
5174 * xmlBufferFree:
5175 * @buf: the buffer to free
5176 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005177 * Frees an XML buffer. It frees both the content and the structure which
5178 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005179 */
5180void
5181xmlBufferFree(xmlBufferPtr buf) {
5182 if (buf == NULL) {
5183#ifdef DEBUG_BUFFER
5184 xmlGenericError(xmlGenericErrorContext,
5185 "xmlBufferFree: buf == NULL\n");
5186#endif
5187 return;
5188 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005189 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005190 xmlFree(buf->content);
5191 }
Owen Taylor3473f882001-02-23 17:55:21 +00005192 xmlFree(buf);
5193}
5194
5195/**
5196 * xmlBufferEmpty:
5197 * @buf: the buffer
5198 *
5199 * empty a buffer.
5200 */
5201void
5202xmlBufferEmpty(xmlBufferPtr buf) {
5203 if (buf->content == NULL) return;
5204 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005205 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005206}
5207
5208/**
5209 * xmlBufferShrink:
5210 * @buf: the buffer to dump
5211 * @len: the number of xmlChar to remove
5212 *
5213 * Remove the beginning of an XML buffer.
5214 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005215 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005216 */
5217int
5218xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5219 if (len == 0) return(0);
5220 if (len > buf->use) return(-1);
5221
5222 buf->use -= len;
5223 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5224
5225 buf->content[buf->use] = 0;
5226 return(len);
5227}
5228
5229/**
5230 * xmlBufferGrow:
5231 * @buf: the buffer
5232 * @len: the minimum free size to allocate
5233 *
5234 * Grow the available space of an XML buffer.
5235 *
5236 * Returns the new available space or -1 in case of error
5237 */
5238int
5239xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5240 int size;
5241 xmlChar *newbuf;
5242
5243 if (len + buf->use < buf->size) return(0);
5244
5245 size = buf->use + len + 100;
5246
5247 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5248 if (newbuf == NULL) return(-1);
5249 buf->content = newbuf;
5250 buf->size = size;
5251 return(buf->size - buf->use);
5252}
5253
5254/**
5255 * xmlBufferDump:
5256 * @file: the file output
5257 * @buf: the buffer to dump
5258 *
5259 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005260 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005261 */
5262int
5263xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5264 int ret;
5265
5266 if (buf == NULL) {
5267#ifdef DEBUG_BUFFER
5268 xmlGenericError(xmlGenericErrorContext,
5269 "xmlBufferDump: buf == NULL\n");
5270#endif
5271 return(0);
5272 }
5273 if (buf->content == NULL) {
5274#ifdef DEBUG_BUFFER
5275 xmlGenericError(xmlGenericErrorContext,
5276 "xmlBufferDump: buf->content == NULL\n");
5277#endif
5278 return(0);
5279 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005280 if (file == NULL)
5281 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005282 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5283 return(ret);
5284}
5285
5286/**
5287 * xmlBufferContent:
5288 * @buf: the buffer
5289 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005290 * Function to extract the content of a buffer
5291 *
Owen Taylor3473f882001-02-23 17:55:21 +00005292 * Returns the internal content
5293 */
5294
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005295const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005296xmlBufferContent(const xmlBufferPtr buf)
5297{
5298 if(!buf)
5299 return NULL;
5300
5301 return buf->content;
5302}
5303
5304/**
5305 * xmlBufferLength:
5306 * @buf: the buffer
5307 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005308 * Function to get the length of a buffer
5309 *
Owen Taylor3473f882001-02-23 17:55:21 +00005310 * Returns the length of data in the internal content
5311 */
5312
5313int
5314xmlBufferLength(const xmlBufferPtr buf)
5315{
5316 if(!buf)
5317 return 0;
5318
5319 return buf->use;
5320}
5321
5322/**
5323 * xmlBufferResize:
5324 * @buf: the buffer to resize
5325 * @size: the desired size
5326 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005327 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005328 *
5329 * Returns 0 in case of problems, 1 otherwise
5330 */
5331int
5332xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5333{
5334 unsigned int newSize;
5335 xmlChar* rebuf = NULL;
5336
5337 /*take care of empty case*/
5338 newSize = (buf->size ? buf->size*2 : size);
5339
5340 /* Don't resize if we don't have to */
5341 if (size < buf->size)
5342 return 1;
5343
5344 /* figure out new size */
5345 switch (buf->alloc){
5346 case XML_BUFFER_ALLOC_DOUBLEIT:
5347 while (size > newSize) newSize *= 2;
5348 break;
5349 case XML_BUFFER_ALLOC_EXACT:
5350 newSize = size+10;
5351 break;
5352 default:
5353 newSize = size+10;
5354 break;
5355 }
5356
5357 if (buf->content == NULL)
5358 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5359 else
5360 rebuf = (xmlChar *) xmlRealloc(buf->content,
5361 newSize * sizeof(xmlChar));
5362 if (rebuf == NULL) {
5363 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005364 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005365 return 0;
5366 }
5367 buf->content = rebuf;
5368 buf->size = newSize;
5369
5370 return 1;
5371}
5372
5373/**
5374 * xmlBufferAdd:
5375 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005376 * @str: the #xmlChar string
5377 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005378 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005379 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005380 * str is recomputed.
5381 */
5382void
5383xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5384 unsigned int needSize;
5385
5386 if (str == NULL) {
5387#ifdef DEBUG_BUFFER
5388 xmlGenericError(xmlGenericErrorContext,
5389 "xmlBufferAdd: str == NULL\n");
5390#endif
5391 return;
5392 }
5393 if (len < -1) {
5394#ifdef DEBUG_BUFFER
5395 xmlGenericError(xmlGenericErrorContext,
5396 "xmlBufferAdd: len < 0\n");
5397#endif
5398 return;
5399 }
5400 if (len == 0) return;
5401
5402 if (len < 0)
5403 len = xmlStrlen(str);
5404
5405 if (len <= 0) return;
5406
5407 needSize = buf->use + len + 2;
5408 if (needSize > buf->size){
5409 if (!xmlBufferResize(buf, needSize)){
5410 xmlGenericError(xmlGenericErrorContext,
5411 "xmlBufferAdd : out of memory!\n");
5412 return;
5413 }
5414 }
5415
5416 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5417 buf->use += len;
5418 buf->content[buf->use] = 0;
5419}
5420
5421/**
5422 * xmlBufferAddHead:
5423 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005424 * @str: the #xmlChar string
5425 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005426 *
5427 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005428 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005429 */
5430void
5431xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5432 unsigned int needSize;
5433
5434 if (str == NULL) {
5435#ifdef DEBUG_BUFFER
5436 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005437 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005438#endif
5439 return;
5440 }
5441 if (len < -1) {
5442#ifdef DEBUG_BUFFER
5443 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005444 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005445#endif
5446 return;
5447 }
5448 if (len == 0) return;
5449
5450 if (len < 0)
5451 len = xmlStrlen(str);
5452
5453 if (len <= 0) return;
5454
5455 needSize = buf->use + len + 2;
5456 if (needSize > buf->size){
5457 if (!xmlBufferResize(buf, needSize)){
5458 xmlGenericError(xmlGenericErrorContext,
5459 "xmlBufferAddHead : out of memory!\n");
5460 return;
5461 }
5462 }
5463
5464 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5465 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5466 buf->use += len;
5467 buf->content[buf->use] = 0;
5468}
5469
5470/**
5471 * xmlBufferCat:
5472 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005473 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005474 *
5475 * Append a zero terminated string to an XML buffer.
5476 */
5477void
5478xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5479 if (str != NULL)
5480 xmlBufferAdd(buf, str, -1);
5481}
5482
5483/**
5484 * xmlBufferCCat:
5485 * @buf: the buffer to dump
5486 * @str: the C char string
5487 *
5488 * Append a zero terminated C string to an XML buffer.
5489 */
5490void
5491xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5492 const char *cur;
5493
5494 if (str == NULL) {
5495#ifdef DEBUG_BUFFER
5496 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005497 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005498#endif
5499 return;
5500 }
5501 for (cur = str;*cur != 0;cur++) {
5502 if (buf->use + 10 >= buf->size) {
5503 if (!xmlBufferResize(buf, buf->use+10)){
5504 xmlGenericError(xmlGenericErrorContext,
5505 "xmlBufferCCat : out of memory!\n");
5506 return;
5507 }
5508 }
5509 buf->content[buf->use++] = *cur;
5510 }
5511 buf->content[buf->use] = 0;
5512}
5513
5514/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005515 * xmlBufferWriteXmlCHAR:
5516 * @buf: the XML buffer
5517 * @string: the string to add
5518 *
5519 * For VMS only.
5520 * routine which manages and grows an output buffer. This one adds
5521 * xmlChars at the end of the buffer.
5522 */
5523/**
Owen Taylor3473f882001-02-23 17:55:21 +00005524 * xmlBufferWriteCHAR:
5525 * @buf: the XML buffer
5526 * @string: the string to add
5527 *
5528 * routine which manages and grows an output buffer. This one adds
5529 * xmlChars at the end of the buffer.
5530 */
5531void
5532#ifdef VMS
5533xmlBufferWriteXmlCHAR
5534#else
5535xmlBufferWriteCHAR
5536#endif
5537(xmlBufferPtr buf, const xmlChar *string) {
5538 xmlBufferCat(buf, string);
5539}
5540
5541/**
5542 * xmlBufferWriteChar:
5543 * @buf: the XML buffer output
5544 * @string: the string to add
5545 *
5546 * routine which manage and grows an output buffer. This one add
5547 * C chars at the end of the array.
5548 */
5549void
5550xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5551 xmlBufferCCat(buf, string);
5552}
5553
5554
5555/**
5556 * xmlBufferWriteQuotedString:
5557 * @buf: the XML buffer output
5558 * @string: the string to add
5559 *
5560 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005561 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005562 * quote or double-quotes internally
5563 */
5564void
5565xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5566 if (xmlStrchr(string, '"')) {
5567 if (xmlStrchr(string, '\'')) {
5568#ifdef DEBUG_BUFFER
5569 xmlGenericError(xmlGenericErrorContext,
5570 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5571#endif
5572 }
5573 xmlBufferCCat(buf, "'");
5574 xmlBufferCat(buf, string);
5575 xmlBufferCCat(buf, "'");
5576 } else {
5577 xmlBufferCCat(buf, "\"");
5578 xmlBufferCat(buf, string);
5579 xmlBufferCCat(buf, "\"");
5580 }
5581}
5582
5583
5584/************************************************************************
5585 * *
5586 * Dumping XML tree content to a simple buffer *
5587 * *
5588 ************************************************************************/
5589
Owen Taylor3473f882001-02-23 17:55:21 +00005590static void
5591xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5592 int format);
5593void
5594htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5595
5596/**
5597 * xmlNsDump:
5598 * @buf: the XML buffer output
5599 * @cur: a namespace
5600 *
5601 * Dump a local Namespace definition.
5602 * Should be called in the context of attributes dumps.
5603 */
5604static void
5605xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5606 if (cur == NULL) {
5607#ifdef DEBUG_TREE
5608 xmlGenericError(xmlGenericErrorContext,
5609 "xmlNsDump : Ns == NULL\n");
5610#endif
5611 return;
5612 }
5613 if (cur->type == XML_LOCAL_NAMESPACE) {
5614 /* Within the context of an element attributes */
5615 if (cur->prefix != NULL) {
5616 xmlBufferWriteChar(buf, " xmlns:");
5617 xmlBufferWriteCHAR(buf, cur->prefix);
5618 } else
5619 xmlBufferWriteChar(buf, " xmlns");
5620 xmlBufferWriteChar(buf, "=");
5621 xmlBufferWriteQuotedString(buf, cur->href);
5622 }
5623}
5624
5625/**
5626 * xmlNsListDump:
5627 * @buf: the XML buffer output
5628 * @cur: the first namespace
5629 *
5630 * Dump a list of local Namespace definitions.
5631 * Should be called in the context of attributes dumps.
5632 */
5633static void
5634xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5635 while (cur != NULL) {
5636 xmlNsDump(buf, cur);
5637 cur = cur->next;
5638 }
5639}
5640
5641/**
5642 * xmlDtdDump:
5643 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005644 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005645 *
5646 * Dump the XML document DTD, if any.
5647 */
5648static void
5649xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5650 if (dtd == NULL) {
5651#ifdef DEBUG_TREE
5652 xmlGenericError(xmlGenericErrorContext,
5653 "xmlDtdDump : no internal subset\n");
5654#endif
5655 return;
5656 }
5657 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5658 xmlBufferWriteCHAR(buf, dtd->name);
5659 if (dtd->ExternalID != NULL) {
5660 xmlBufferWriteChar(buf, " PUBLIC ");
5661 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5662 xmlBufferWriteChar(buf, " ");
5663 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5664 } else if (dtd->SystemID != NULL) {
5665 xmlBufferWriteChar(buf, " SYSTEM ");
5666 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5667 }
5668 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5669 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5670 xmlBufferWriteChar(buf, ">");
5671 return;
5672 }
5673 xmlBufferWriteChar(buf, " [\n");
5674 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5675#if 0
5676 if (dtd->entities != NULL)
5677 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5678 if (dtd->notations != NULL)
5679 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5680 if (dtd->elements != NULL)
5681 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5682 if (dtd->attributes != NULL)
5683 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5684#endif
5685 xmlBufferWriteChar(buf, "]>");
5686}
5687
5688/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005689 * xmlAttrSerializeContent:
5690 * @buf: the XML buffer output
5691 * @doc: the document
5692 * @attr: the attribute pointer
5693 *
5694 * Serialize the attribute in the buffer
5695 */
5696static void
5697xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5698 const xmlChar *cur, *base;
5699 xmlNodePtr children;
5700
5701 children = attr->children;
5702 while (children != NULL) {
5703 switch (children->type) {
5704 case XML_TEXT_NODE:
5705 base = cur = children->content;
5706 while (*cur != 0) {
5707 if (*cur == '\n') {
5708 if (base != cur)
5709 xmlBufferAdd(buf, base, cur - base);
5710 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5711 cur++;
5712 base = cur;
5713#if 0
5714 } else if (*cur == '\'') {
5715 if (base != cur)
5716 xmlBufferAdd(buf, base, cur - base);
5717 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5718 cur++;
5719 base = cur;
5720#endif
5721 } else if (*cur == '"') {
5722 if (base != cur)
5723 xmlBufferAdd(buf, base, cur - base);
5724 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5725 cur++;
5726 base = cur;
5727 } else if (*cur == '<') {
5728 if (base != cur)
5729 xmlBufferAdd(buf, base, cur - base);
5730 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
5731 cur++;
5732 base = cur;
5733 } else if (*cur == '>') {
5734 if (base != cur)
5735 xmlBufferAdd(buf, base, cur - base);
5736 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
5737 cur++;
5738 base = cur;
5739 } else if (*cur == '&') {
5740 if (base != cur)
5741 xmlBufferAdd(buf, base, cur - base);
5742 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
5743 cur++;
5744 base = cur;
5745 } else if ((*cur >= 0x80) && ((doc == NULL) ||
5746 (doc->encoding == NULL))) {
5747 /*
5748 * We assume we have UTF-8 content.
5749 */
5750 char tmp[10];
5751 int val = 0, l = 1;
5752
5753 if (base != cur)
5754 xmlBufferAdd(buf, base, cur - base);
5755 if (*cur < 0xC0) {
5756 xmlGenericError(xmlGenericErrorContext,
5757 "xmlAttrSerializeContent : input not UTF-8\n");
5758 if (doc != NULL)
5759 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5760 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5761 tmp[sizeof(tmp) - 1] = 0;
5762 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5763 cur++;
5764 base = cur;
5765 continue;
5766 } else if (*cur < 0xE0) {
5767 val = (cur[0]) & 0x1F;
5768 val <<= 6;
5769 val |= (cur[1]) & 0x3F;
5770 l = 2;
5771 } else if (*cur < 0xF0) {
5772 val = (cur[0]) & 0x0F;
5773 val <<= 6;
5774 val |= (cur[1]) & 0x3F;
5775 val <<= 6;
5776 val |= (cur[2]) & 0x3F;
5777 l = 3;
5778 } else if (*cur < 0xF8) {
5779 val = (cur[0]) & 0x07;
5780 val <<= 6;
5781 val |= (cur[1]) & 0x3F;
5782 val <<= 6;
5783 val |= (cur[2]) & 0x3F;
5784 val <<= 6;
5785 val |= (cur[3]) & 0x3F;
5786 l = 4;
5787 }
5788 if ((l == 1) || (!IS_CHAR(val))) {
5789 xmlGenericError(xmlGenericErrorContext,
5790 "xmlAttrSerializeContent : char out of range\n");
5791 if (doc != NULL)
5792 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5793 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5794 tmp[sizeof(tmp) - 1] = 0;
5795 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5796 cur++;
5797 base = cur;
5798 continue;
5799 }
5800 /*
5801 * We could do multiple things here. Just save
5802 * as a char ref
5803 */
5804 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
5805 tmp[sizeof(tmp) - 1] = 0;
5806 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5807 cur += l;
5808 base = cur;
5809 } else {
5810 cur++;
5811 }
5812 }
5813 if (base != cur)
5814 xmlBufferAdd(buf, base, cur - base);
5815 break;
5816 case XML_ENTITY_REF_NODE:
5817 xmlBufferAdd(buf, BAD_CAST "&", 1);
5818 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
5819 xmlBufferAdd(buf, BAD_CAST ";", 1);
5820 break;
5821 default:
5822 /* should not happen unless we have a badly built tree */
5823 break;
5824 }
5825 children = children->next;
5826 }
5827}
5828
5829/**
Owen Taylor3473f882001-02-23 17:55:21 +00005830 * xmlAttrDump:
5831 * @buf: the XML buffer output
5832 * @doc: the document
5833 * @cur: the attribute pointer
5834 *
5835 * Dump an XML attribute
5836 */
5837static void
5838xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00005839 if (cur == NULL) {
5840#ifdef DEBUG_TREE
5841 xmlGenericError(xmlGenericErrorContext,
5842 "xmlAttrDump : property == NULL\n");
5843#endif
5844 return;
5845 }
5846 xmlBufferWriteChar(buf, " ");
5847 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5848 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5849 xmlBufferWriteChar(buf, ":");
5850 }
5851 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00005852 xmlBufferWriteChar(buf, "=\"");
5853 xmlAttrSerializeContent(buf, doc, cur);
5854 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00005855}
5856
5857/**
5858 * xmlAttrListDump:
5859 * @buf: the XML buffer output
5860 * @doc: the document
5861 * @cur: the first attribute pointer
5862 *
5863 * Dump a list of XML attributes
5864 */
5865static void
5866xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5867 if (cur == NULL) {
5868#ifdef DEBUG_TREE
5869 xmlGenericError(xmlGenericErrorContext,
5870 "xmlAttrListDump : property == NULL\n");
5871#endif
5872 return;
5873 }
5874 while (cur != NULL) {
5875 xmlAttrDump(buf, doc, cur);
5876 cur = cur->next;
5877 }
5878}
5879
5880
5881
5882/**
5883 * xmlNodeListDump:
5884 * @buf: the XML buffer output
5885 * @doc: the document
5886 * @cur: the first node
5887 * @level: the imbrication level for indenting
5888 * @format: is formatting allowed
5889 *
5890 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005891 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
5892 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00005893 */
5894static void
5895xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5896 int format) {
5897 int i;
5898
5899 if (cur == NULL) {
5900#ifdef DEBUG_TREE
5901 xmlGenericError(xmlGenericErrorContext,
5902 "xmlNodeListDump : node == NULL\n");
5903#endif
5904 return;
5905 }
5906 while (cur != NULL) {
5907 if ((format) && (xmlIndentTreeOutput) &&
5908 (cur->type == XML_ELEMENT_NODE))
5909 for (i = 0;i < level;i++)
5910 xmlBufferWriteChar(buf, " ");
5911 xmlNodeDump(buf, doc, cur, level, format);
5912 if (format) {
5913 xmlBufferWriteChar(buf, "\n");
5914 }
5915 cur = cur->next;
5916 }
5917}
5918
5919/**
5920 * xmlNodeDump:
5921 * @buf: the XML buffer output
5922 * @doc: the document
5923 * @cur: the current node
5924 * @level: the imbrication level for indenting
5925 * @format: is formatting allowed
5926 *
5927 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005928 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
5929 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00005930 */
5931void
5932xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5933 int format) {
5934 int i;
5935 xmlNodePtr tmp;
5936
5937 if (cur == NULL) {
5938#ifdef DEBUG_TREE
5939 xmlGenericError(xmlGenericErrorContext,
5940 "xmlNodeDump : node == NULL\n");
5941#endif
5942 return;
5943 }
5944 if (cur->type == XML_XINCLUDE_START)
5945 return;
5946 if (cur->type == XML_XINCLUDE_END)
5947 return;
5948 if (cur->type == XML_DTD_NODE) {
5949 xmlDtdDump(buf, (xmlDtdPtr) cur);
5950 return;
5951 }
5952 if (cur->type == XML_ELEMENT_DECL) {
5953 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5954 return;
5955 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005956 if (cur->type == XML_ATTRIBUTE_NODE){
5957 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5958 return;
5959 }
Owen Taylor3473f882001-02-23 17:55:21 +00005960 if (cur->type == XML_ATTRIBUTE_DECL) {
5961 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5962 return;
5963 }
5964 if (cur->type == XML_ENTITY_DECL) {
5965 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5966 return;
5967 }
5968 if (cur->type == XML_TEXT_NODE) {
5969 if (cur->content != NULL) {
5970 if ((cur->name == xmlStringText) ||
5971 (cur->name != xmlStringTextNoenc)) {
5972 xmlChar *buffer;
5973
Owen Taylor3473f882001-02-23 17:55:21 +00005974 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005975 if (buffer != NULL) {
5976 xmlBufferWriteCHAR(buf, buffer);
5977 xmlFree(buffer);
5978 }
5979 } else {
5980 /*
5981 * Disable escaping, needed for XSLT
5982 */
Owen Taylor3473f882001-02-23 17:55:21 +00005983 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005984 }
5985 }
5986 return;
5987 }
5988 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005989 xmlBufferWriteChar(buf, "<?");
5990 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005991 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005992 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00005993 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005994 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00005995 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00005996 return;
5997 }
5998 if (cur->type == XML_COMMENT_NODE) {
5999 if (cur->content != NULL) {
6000 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006001 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006002 xmlBufferWriteChar(buf, "-->");
6003 }
6004 return;
6005 }
6006 if (cur->type == XML_ENTITY_REF_NODE) {
6007 xmlBufferWriteChar(buf, "&");
6008 xmlBufferWriteCHAR(buf, cur->name);
6009 xmlBufferWriteChar(buf, ";");
6010 return;
6011 }
6012 if (cur->type == XML_CDATA_SECTION_NODE) {
6013 xmlBufferWriteChar(buf, "<![CDATA[");
6014 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006015 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006016 xmlBufferWriteChar(buf, "]]>");
6017 return;
6018 }
6019
6020 if (format == 1) {
6021 tmp = cur->children;
6022 while (tmp != NULL) {
6023 if ((tmp->type == XML_TEXT_NODE) ||
6024 (tmp->type == XML_ENTITY_REF_NODE)) {
6025 format = 0;
6026 break;
6027 }
6028 tmp = tmp->next;
6029 }
6030 }
6031 xmlBufferWriteChar(buf, "<");
6032 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6033 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6034 xmlBufferWriteChar(buf, ":");
6035 }
6036
6037 xmlBufferWriteCHAR(buf, cur->name);
6038 if (cur->nsDef)
6039 xmlNsListDump(buf, cur->nsDef);
6040 if (cur->properties != NULL)
6041 xmlAttrListDump(buf, doc, cur->properties);
6042
Daniel Veillard7db37732001-07-12 01:20:08 +00006043 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6044 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006045 (!xmlSaveNoEmptyTags)) {
6046 xmlBufferWriteChar(buf, "/>");
6047 return;
6048 }
6049 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006050 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006051 xmlChar *buffer;
6052
Owen Taylor3473f882001-02-23 17:55:21 +00006053 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006054 if (buffer != NULL) {
6055 xmlBufferWriteCHAR(buf, buffer);
6056 xmlFree(buffer);
6057 }
6058 }
6059 if (cur->children != NULL) {
6060 if (format) xmlBufferWriteChar(buf, "\n");
6061 xmlNodeListDump(buf, doc, cur->children,
6062 (level >= 0?level+1:-1), format);
6063 if ((xmlIndentTreeOutput) && (format))
6064 for (i = 0;i < level;i++)
6065 xmlBufferWriteChar(buf, " ");
6066 }
6067 xmlBufferWriteChar(buf, "</");
6068 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6069 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6070 xmlBufferWriteChar(buf, ":");
6071 }
6072
6073 xmlBufferWriteCHAR(buf, cur->name);
6074 xmlBufferWriteChar(buf, ">");
6075}
6076
6077/**
6078 * xmlElemDump:
6079 * @f: the FILE * for the output
6080 * @doc: the document
6081 * @cur: the current node
6082 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006083 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006084 */
6085void
6086xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6087 xmlBufferPtr buf;
6088
6089 if (cur == NULL) {
6090#ifdef DEBUG_TREE
6091 xmlGenericError(xmlGenericErrorContext,
6092 "xmlElemDump : cur == NULL\n");
6093#endif
6094 return;
6095 }
Owen Taylor3473f882001-02-23 17:55:21 +00006096#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006097 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006098 xmlGenericError(xmlGenericErrorContext,
6099 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006100 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006101#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006102
Owen Taylor3473f882001-02-23 17:55:21 +00006103 buf = xmlBufferCreate();
6104 if (buf == NULL) return;
6105 if ((doc != NULL) &&
6106 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6107#ifdef LIBXML_HTML_ENABLED
6108 htmlNodeDump(buf, doc, cur);
6109#else
6110 xmlGenericError(xmlGenericErrorContext,
6111 "HTML support not compiled in\n");
6112#endif /* LIBXML_HTML_ENABLED */
6113 } else
6114 xmlNodeDump(buf, doc, cur, 0, 1);
6115 xmlBufferDump(f, buf);
6116 xmlBufferFree(buf);
6117}
6118
6119/************************************************************************
6120 * *
6121 * Dumping XML tree content to an I/O output buffer *
6122 * *
6123 ************************************************************************/
6124
Owen Taylor3473f882001-02-23 17:55:21 +00006125static void
6126xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6127 int level, int format, const char *encoding);
6128/**
6129 * xmlNsDumpOutput:
6130 * @buf: the XML buffer output
6131 * @cur: a namespace
6132 *
6133 * Dump a local Namespace definition.
6134 * Should be called in the context of attributes dumps.
6135 */
6136static void
6137xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6138 if (cur == NULL) {
6139#ifdef DEBUG_TREE
6140 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006141 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006142#endif
6143 return;
6144 }
6145 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6146 /* Within the context of an element attributes */
6147 if (cur->prefix != NULL) {
6148 xmlOutputBufferWriteString(buf, " xmlns:");
6149 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6150 } else
6151 xmlOutputBufferWriteString(buf, " xmlns");
6152 xmlOutputBufferWriteString(buf, "=");
6153 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6154 }
6155}
6156
6157/**
6158 * xmlNsListDumpOutput:
6159 * @buf: the XML buffer output
6160 * @cur: the first namespace
6161 *
6162 * Dump a list of local Namespace definitions.
6163 * Should be called in the context of attributes dumps.
6164 */
6165static void
6166xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6167 while (cur != NULL) {
6168 xmlNsDumpOutput(buf, cur);
6169 cur = cur->next;
6170 }
6171}
6172
6173/**
6174 * xmlDtdDumpOutput:
6175 * @buf: the XML buffer output
6176 * @doc: the document
6177 * @encoding: an optional encoding string
6178 *
6179 * Dump the XML document DTD, if any.
6180 */
6181static void
6182xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6183 if (dtd == NULL) {
6184#ifdef DEBUG_TREE
6185 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006186 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006187#endif
6188 return;
6189 }
6190 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6191 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6192 if (dtd->ExternalID != NULL) {
6193 xmlOutputBufferWriteString(buf, " PUBLIC ");
6194 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6195 xmlOutputBufferWriteString(buf, " ");
6196 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6197 } else if (dtd->SystemID != NULL) {
6198 xmlOutputBufferWriteString(buf, " SYSTEM ");
6199 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6200 }
6201 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6202 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6203 xmlOutputBufferWriteString(buf, ">");
6204 return;
6205 }
6206 xmlOutputBufferWriteString(buf, " [\n");
6207 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6208 xmlOutputBufferWriteString(buf, "]>");
6209}
6210
6211/**
6212 * xmlAttrDumpOutput:
6213 * @buf: the XML buffer output
6214 * @doc: the document
6215 * @cur: the attribute pointer
6216 * @encoding: an optional encoding string
6217 *
6218 * Dump an XML attribute
6219 */
6220static void
6221xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006222 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006223 if (cur == NULL) {
6224#ifdef DEBUG_TREE
6225 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006226 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006227#endif
6228 return;
6229 }
6230 xmlOutputBufferWriteString(buf, " ");
6231 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6232 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6233 xmlOutputBufferWriteString(buf, ":");
6234 }
6235 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006236 xmlOutputBufferWriteString(buf, "=\"");
6237 xmlAttrSerializeContent(buf->buffer, doc, cur);
6238 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006239}
6240
6241/**
6242 * xmlAttrListDumpOutput:
6243 * @buf: the XML buffer output
6244 * @doc: the document
6245 * @cur: the first attribute pointer
6246 * @encoding: an optional encoding string
6247 *
6248 * Dump a list of XML attributes
6249 */
6250static void
6251xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6252 xmlAttrPtr cur, const char *encoding) {
6253 if (cur == NULL) {
6254#ifdef DEBUG_TREE
6255 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006256 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006257#endif
6258 return;
6259 }
6260 while (cur != NULL) {
6261 xmlAttrDumpOutput(buf, doc, cur, encoding);
6262 cur = cur->next;
6263 }
6264}
6265
6266
6267
6268/**
6269 * xmlNodeListDumpOutput:
6270 * @buf: the XML buffer output
6271 * @doc: the document
6272 * @cur: the first node
6273 * @level: the imbrication level for indenting
6274 * @format: is formatting allowed
6275 * @encoding: an optional encoding string
6276 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006277 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006278 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6279 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006280 */
6281static void
6282xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6283 xmlNodePtr cur, int level, int format, const char *encoding) {
6284 int i;
6285
6286 if (cur == NULL) {
6287#ifdef DEBUG_TREE
6288 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006289 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006290#endif
6291 return;
6292 }
6293 while (cur != NULL) {
6294 if ((format) && (xmlIndentTreeOutput) &&
6295 (cur->type == XML_ELEMENT_NODE))
6296 for (i = 0;i < level;i++)
6297 xmlOutputBufferWriteString(buf, " ");
6298 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6299 if (format) {
6300 xmlOutputBufferWriteString(buf, "\n");
6301 }
6302 cur = cur->next;
6303 }
6304}
6305
6306/**
6307 * xmlNodeDumpOutput:
6308 * @buf: the XML buffer output
6309 * @doc: the document
6310 * @cur: the current node
6311 * @level: the imbrication level for indenting
6312 * @format: is formatting allowed
6313 * @encoding: an optional encoding string
6314 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006315 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006316 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6317 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006318 */
6319void
6320xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6321 int level, int format, const char *encoding) {
6322 int i;
6323 xmlNodePtr tmp;
6324
6325 if (cur == NULL) {
6326#ifdef DEBUG_TREE
6327 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006328 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006329#endif
6330 return;
6331 }
6332 if (cur->type == XML_XINCLUDE_START)
6333 return;
6334 if (cur->type == XML_XINCLUDE_END)
6335 return;
6336 if (cur->type == XML_DTD_NODE) {
6337 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6338 return;
6339 }
6340 if (cur->type == XML_ELEMENT_DECL) {
6341 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6342 return;
6343 }
6344 if (cur->type == XML_ATTRIBUTE_DECL) {
6345 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6346 return;
6347 }
6348 if (cur->type == XML_ENTITY_DECL) {
6349 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6350 return;
6351 }
6352 if (cur->type == XML_TEXT_NODE) {
6353 if (cur->content != NULL) {
6354 if ((cur->name == xmlStringText) ||
6355 (cur->name != xmlStringTextNoenc)) {
6356 xmlChar *buffer;
6357
Owen Taylor3473f882001-02-23 17:55:21 +00006358 if (encoding == NULL)
6359 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6360 else
6361 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006362 if (buffer != NULL) {
6363 xmlOutputBufferWriteString(buf, (const char *)buffer);
6364 xmlFree(buffer);
6365 }
6366 } else {
6367 /*
6368 * Disable escaping, needed for XSLT
6369 */
Owen Taylor3473f882001-02-23 17:55:21 +00006370 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006371 }
6372 }
6373
6374 return;
6375 }
6376 if (cur->type == XML_PI_NODE) {
6377 if (cur->content != NULL) {
6378 xmlOutputBufferWriteString(buf, "<?");
6379 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6380 if (cur->content != NULL) {
6381 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006382 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006383 }
6384 xmlOutputBufferWriteString(buf, "?>");
6385 } else {
6386 xmlOutputBufferWriteString(buf, "<?");
6387 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6388 xmlOutputBufferWriteString(buf, "?>");
6389 }
6390 return;
6391 }
6392 if (cur->type == XML_COMMENT_NODE) {
6393 if (cur->content != NULL) {
6394 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006395 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006396 xmlOutputBufferWriteString(buf, "-->");
6397 }
6398 return;
6399 }
6400 if (cur->type == XML_ENTITY_REF_NODE) {
6401 xmlOutputBufferWriteString(buf, "&");
6402 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6403 xmlOutputBufferWriteString(buf, ";");
6404 return;
6405 }
6406 if (cur->type == XML_CDATA_SECTION_NODE) {
6407 xmlOutputBufferWriteString(buf, "<![CDATA[");
6408 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006409 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006410 xmlOutputBufferWriteString(buf, "]]>");
6411 return;
6412 }
6413
6414 if (format == 1) {
6415 tmp = cur->children;
6416 while (tmp != NULL) {
6417 if ((tmp->type == XML_TEXT_NODE) ||
6418 (tmp->type == XML_ENTITY_REF_NODE)) {
6419 format = 0;
6420 break;
6421 }
6422 tmp = tmp->next;
6423 }
6424 }
6425 xmlOutputBufferWriteString(buf, "<");
6426 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6427 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6428 xmlOutputBufferWriteString(buf, ":");
6429 }
6430
6431 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6432 if (cur->nsDef)
6433 xmlNsListDumpOutput(buf, cur->nsDef);
6434 if (cur->properties != NULL)
6435 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6436
Daniel Veillard7db37732001-07-12 01:20:08 +00006437 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6438 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006439 xmlOutputBufferWriteString(buf, "/>");
6440 return;
6441 }
6442 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006443 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006444 xmlChar *buffer;
6445
Owen Taylor3473f882001-02-23 17:55:21 +00006446 if (encoding == NULL)
6447 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6448 else
6449 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006450 if (buffer != NULL) {
6451 xmlOutputBufferWriteString(buf, (const char *)buffer);
6452 xmlFree(buffer);
6453 }
6454 }
6455 if (cur->children != NULL) {
6456 if (format) xmlOutputBufferWriteString(buf, "\n");
6457 xmlNodeListDumpOutput(buf, doc, cur->children,
6458 (level >= 0?level+1:-1), format, encoding);
6459 if ((xmlIndentTreeOutput) && (format))
6460 for (i = 0;i < level;i++)
6461 xmlOutputBufferWriteString(buf, " ");
6462 }
6463 xmlOutputBufferWriteString(buf, "</");
6464 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6465 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6466 xmlOutputBufferWriteString(buf, ":");
6467 }
6468
6469 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6470 xmlOutputBufferWriteString(buf, ">");
6471}
6472
6473/**
6474 * xmlDocContentDumpOutput:
6475 * @buf: the XML buffer output
6476 * @cur: the document
6477 * @encoding: an optional encoding string
6478 * @format: should formatting spaces been added
6479 *
6480 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006481 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6482 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006483 */
6484static void
6485xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6486 const char *encoding, int format) {
6487 xmlOutputBufferWriteString(buf, "<?xml version=");
6488 if (cur->version != NULL)
6489 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6490 else
6491 xmlOutputBufferWriteString(buf, "\"1.0\"");
6492 if (encoding == NULL) {
6493 if (cur->encoding != NULL)
6494 encoding = (const char *) cur->encoding;
6495 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6496 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6497 }
6498 if (encoding != NULL) {
6499 xmlOutputBufferWriteString(buf, " encoding=");
6500 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6501 }
6502 switch (cur->standalone) {
6503 case 0:
6504 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6505 break;
6506 case 1:
6507 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6508 break;
6509 }
6510 xmlOutputBufferWriteString(buf, "?>\n");
6511 if (cur->children != NULL) {
6512 xmlNodePtr child = cur->children;
6513
6514 while (child != NULL) {
6515 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6516 xmlOutputBufferWriteString(buf, "\n");
6517 child = child->next;
6518 }
6519 }
6520}
6521
6522/************************************************************************
6523 * *
6524 * Saving functions front-ends *
6525 * *
6526 ************************************************************************/
6527
6528/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006529 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006530 * @out_doc: Document to generate XML text from
6531 * @doc_txt_ptr: Memory pointer for allocated XML text
6532 * @doc_txt_len: Length of the generated XML text
6533 * @txt_encoding: Character encoding to use when generating XML text
6534 * @format: should formatting spaces been added
6535 *
6536 * Dump the current DOM tree into memory using the character encoding specified
6537 * by the caller. Note it is up to the caller of this function to free the
6538 * allocated memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006539 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6540 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006541 */
6542
6543void
6544xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006545 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006546 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006547 int dummy = 0;
6548
6549 xmlCharEncoding doc_charset;
6550 xmlOutputBufferPtr out_buff = NULL;
6551 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6552
6553 if (doc_txt_len == NULL) {
6554 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6555 }
6556
6557 if (doc_txt_ptr == NULL) {
6558 *doc_txt_len = 0;
6559 xmlGenericError(xmlGenericErrorContext,
6560 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6561 return;
6562 }
6563
6564 *doc_txt_ptr = NULL;
6565 *doc_txt_len = 0;
6566
6567 if (out_doc == NULL) {
6568 /* No document, no output */
6569 xmlGenericError(xmlGenericErrorContext,
6570 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6571 return;
6572 }
6573
6574 /*
6575 * Validate the encoding value, if provided.
6576 * This logic is copied from xmlSaveFileEnc.
6577 */
6578
6579 if (txt_encoding == NULL)
6580 txt_encoding = (const char *) out_doc->encoding;
6581 if (txt_encoding != NULL) {
6582 doc_charset = xmlParseCharEncoding(txt_encoding);
6583
6584 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6585 xmlGenericError(xmlGenericErrorContext,
6586 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6587 return;
6588
6589 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6590 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6591 if ( conv_hdlr == NULL ) {
6592 xmlGenericError(xmlGenericErrorContext,
6593 "%s: %s %s '%s'\n",
6594 "xmlDocDumpFormatMemoryEnc",
6595 "Failed to identify encoding handler for",
6596 "character set",
6597 txt_encoding);
6598 return;
6599 }
6600 }
6601 }
6602
6603 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6604 xmlGenericError(xmlGenericErrorContext,
6605 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6606 return;
6607 }
6608
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006609 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006610 xmlOutputBufferFlush(out_buff);
6611 if (out_buff->conv != NULL) {
6612 *doc_txt_len = out_buff->conv->use;
6613 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6614 } else {
6615 *doc_txt_len = out_buff->buffer->use;
6616 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6617 }
6618 (void)xmlOutputBufferClose(out_buff);
6619
6620 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6621 *doc_txt_len = 0;
6622 xmlGenericError(xmlGenericErrorContext,
6623 "xmlDocDumpFormatMemoryEnc: %s\n",
6624 "Failed to allocate memory for document text representation.");
6625 }
6626
6627 return;
6628}
6629
6630/**
6631 * xmlDocDumpMemory:
6632 * @cur: the document
6633 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006634 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006635 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006636 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006637 * It's up to the caller to free the memory.
6638 */
6639void
6640xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6641 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6642}
6643
6644/**
6645 * xmlDocDumpFormatMemory:
6646 * @cur: the document
6647 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006648 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006649 * @format: should formatting spaces been added
6650 *
6651 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006652 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006653 * It's up to the caller to free the memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006654 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6655 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006656 */
6657void
6658xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6659 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6660}
6661
6662/**
6663 * xmlDocDumpMemoryEnc:
6664 * @out_doc: Document to generate XML text from
6665 * @doc_txt_ptr: Memory pointer for allocated XML text
6666 * @doc_txt_len: Length of the generated XML text
6667 * @txt_encoding: Character encoding to use when generating XML text
6668 *
6669 * Dump the current DOM tree into memory using the character encoding specified
6670 * by the caller. Note it is up to the caller of this function to free the
6671 * allocated memory.
6672 */
6673
6674void
6675xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6676 int * doc_txt_len, const char * txt_encoding) {
6677 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006678 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006679}
6680
6681/**
6682 * xmlGetDocCompressMode:
6683 * @doc: the document
6684 *
6685 * get the compression ratio for a document, ZLIB based
6686 * Returns 0 (uncompressed) to 9 (max compression)
6687 */
6688int
6689xmlGetDocCompressMode (xmlDocPtr doc) {
6690 if (doc == NULL) return(-1);
6691 return(doc->compression);
6692}
6693
6694/**
6695 * xmlSetDocCompressMode:
6696 * @doc: the document
6697 * @mode: the compression ratio
6698 *
6699 * set the compression ratio for a document, ZLIB based
6700 * Correct values: 0 (uncompressed) to 9 (max compression)
6701 */
6702void
6703xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6704 if (doc == NULL) return;
6705 if (mode < 0) doc->compression = 0;
6706 else if (mode > 9) doc->compression = 9;
6707 else doc->compression = mode;
6708}
6709
6710/**
6711 * xmlGetCompressMode:
6712 *
6713 * get the default compression mode used, ZLIB based.
6714 * Returns 0 (uncompressed) to 9 (max compression)
6715 */
6716int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006717xmlGetCompressMode(void)
6718{
6719 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006720}
6721
6722/**
6723 * xmlSetCompressMode:
6724 * @mode: the compression ratio
6725 *
6726 * set the default compression mode used, ZLIB based
6727 * Correct values: 0 (uncompressed) to 9 (max compression)
6728 */
6729void
6730xmlSetCompressMode(int mode) {
6731 if (mode < 0) xmlCompressMode = 0;
6732 else if (mode > 9) xmlCompressMode = 9;
6733 else xmlCompressMode = mode;
6734}
6735
6736/**
6737 * xmlDocDump:
6738 * @f: the FILE*
6739 * @cur: the document
6740 *
6741 * Dump an XML document to an open FILE.
6742 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006743 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006744 */
6745int
6746xmlDocDump(FILE *f, xmlDocPtr cur) {
6747 xmlOutputBufferPtr buf;
6748 const char * encoding;
6749 xmlCharEncodingHandlerPtr handler = NULL;
6750 int ret;
6751
6752 if (cur == NULL) {
6753#ifdef DEBUG_TREE
6754 xmlGenericError(xmlGenericErrorContext,
6755 "xmlDocDump : document == NULL\n");
6756#endif
6757 return(-1);
6758 }
6759 encoding = (const char *) cur->encoding;
6760
6761 if (encoding != NULL) {
6762 xmlCharEncoding enc;
6763
6764 enc = xmlParseCharEncoding(encoding);
6765
6766 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6767 xmlGenericError(xmlGenericErrorContext,
6768 "xmlDocDump: document not in UTF8\n");
6769 return(-1);
6770 }
6771 if (enc != XML_CHAR_ENCODING_UTF8) {
6772 handler = xmlFindCharEncodingHandler(encoding);
6773 if (handler == NULL) {
6774 xmlFree((char *) cur->encoding);
6775 cur->encoding = NULL;
6776 }
6777 }
6778 }
6779 buf = xmlOutputBufferCreateFile(f, handler);
6780 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006781 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006782
6783 ret = xmlOutputBufferClose(buf);
6784 return(ret);
6785}
6786
6787/**
6788 * xmlSaveFileTo:
6789 * @buf: an output I/O buffer
6790 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006791 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006792 *
6793 * Dump an XML document to an I/O buffer.
6794 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006795 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006796 */
6797int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006798xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006799 int ret;
6800
6801 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006802 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006803 ret = xmlOutputBufferClose(buf);
6804 return(ret);
6805}
6806
6807/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006808 * xmlSaveFormatFileTo:
6809 * @buf: an output I/O buffer
6810 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006811 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006812 * @format: should formatting spaces been added
6813 *
6814 * Dump an XML document to an I/O buffer.
6815 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006816 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006817 */
6818int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006819xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006820 int ret;
6821
6822 if (buf == NULL) return(0);
6823 xmlDocContentDumpOutput(buf, cur, encoding, format);
6824 ret = xmlOutputBufferClose(buf);
6825 return(ret);
6826}
6827
6828/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006829 * xmlSaveFormatFileEnc
6830 * @filename: the filename or URL to output
6831 * @cur: the document being saved
6832 * @encoding: the name of the encoding to use or NULL.
6833 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006834 *
6835 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006836 */
6837int
Daniel Veillardf012a642001-07-23 19:10:52 +00006838xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6839 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006840 xmlOutputBufferPtr buf;
6841 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006842 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006843 int ret;
6844
Daniel Veillardfb25a512002-01-13 20:32:08 +00006845 if (encoding == NULL)
6846 encoding = (const char *) cur->encoding;
6847
Owen Taylor3473f882001-02-23 17:55:21 +00006848 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006849
6850 enc = xmlParseCharEncoding(encoding);
6851 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6852 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006853 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006854 return(-1);
6855 }
6856 if (enc != XML_CHAR_ENCODING_UTF8) {
6857 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006858 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006859 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006860 }
6861 }
6862
Daniel Veillardf012a642001-07-23 19:10:52 +00006863#ifdef HAVE_ZLIB_H
6864 if (cur->compression < 0) cur->compression = xmlCompressMode;
6865#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006866 /*
6867 * save the content to a temp buffer.
6868 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006869 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006870 if (buf == NULL) return(-1);
6871
Daniel Veillardf012a642001-07-23 19:10:52 +00006872 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006873
6874 ret = xmlOutputBufferClose(buf);
6875 return(ret);
6876}
6877
Daniel Veillardf012a642001-07-23 19:10:52 +00006878
6879/**
6880 * xmlSaveFileEnc:
6881 * @filename: the filename (or URL)
6882 * @cur: the document
6883 * @encoding: the name of an encoding (or NULL)
6884 *
6885 * Dump an XML document, converting it to the given encoding
6886 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006887 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006888 */
6889int
6890xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6891 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6892}
6893
Owen Taylor3473f882001-02-23 17:55:21 +00006894/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006895 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006896 * @filename: the filename (or URL)
6897 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006898 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006899 *
6900 * Dump an XML document to a file. Will use compression if
6901 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006902 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006903 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006904 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006905 */
6906int
Daniel Veillard67fee942001-04-26 18:59:03 +00006907xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006908 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006909}
6910
Daniel Veillard67fee942001-04-26 18:59:03 +00006911/**
6912 * xmlSaveFile:
6913 * @filename: the filename (or URL)
6914 * @cur: the document
6915 *
6916 * Dump an XML document to a file. Will use compression if
6917 * compiled in and enabled. If @filename is "-" the stdout file is
6918 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006919 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006920 */
6921int
6922xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006923 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006924}
6925