blob: 6be2c05bf2eb5352e2bed3dbaf9cb792cbfcc054 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * tree.c : implemetation of access function for an XML tree.
3 *
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
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000036
Daniel Veillard56a4cb82001-03-24 17:00:36 +000037xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
38
39/************************************************************************
40 * *
41 * A few static variables and macros *
42 * *
43 ************************************************************************/
44
Owen Taylor3473f882001-02-23 17:55:21 +000045xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
46xmlChar xmlStringTextNoenc[] =
47 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
48xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
49int oldXMLWDcompatibility = 0;
50int xmlIndentTreeOutput = 0;
51xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
52
53static int xmlCompressMode = 0;
54static int xmlCheckDTD = 1;
55int xmlSaveNoEmptyTags = 0;
56
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 * *
75 * Allocation and deallocation of basic structures *
76 * *
77 ************************************************************************/
78
79/**
80 * xmlSetBufferAllocationScheme:
81 * @scheme: allocation method to use
82 *
83 * Set the buffer allocation method. Types are
84 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
85 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
86 * improves performance
87 */
88void
89xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
90 xmlBufferAllocScheme = scheme;
91}
92
93/**
94 * xmlGetBufferAllocationScheme:
95 *
96 * Types are
97 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
98 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
99 * improves performance
100 *
101 * Returns the current allocation scheme
102 */
103xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000104xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000105 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000106}
107
108/**
109 * xmlNewNs:
110 * @node: the element carrying the namespace
111 * @href: the URI associated
112 * @prefix: the prefix for the namespace
113 *
114 * Creation of a new Namespace. This function will refuse to create
115 * a namespace with a similar prefix than an existing one present on this
116 * node.
117 * We use href==NULL in the case of an element creation where the namespace
118 * was not defined.
119 * Returns returns a new namespace pointer or NULL
120 */
121xmlNsPtr
122xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
123 xmlNsPtr cur;
124
125 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
126 return(NULL);
127
128 /*
129 * Allocate a new Namespace and fill the fields.
130 */
131 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
132 if (cur == NULL) {
133 xmlGenericError(xmlGenericErrorContext,
134 "xmlNewNs : malloc failed\n");
135 return(NULL);
136 }
137 memset(cur, 0, sizeof(xmlNs));
138 cur->type = XML_LOCAL_NAMESPACE;
139
140 if (href != NULL)
141 cur->href = xmlStrdup(href);
142 if (prefix != NULL)
143 cur->prefix = xmlStrdup(prefix);
144
145 /*
146 * Add it at the end to preserve parsing order ...
147 * and checks for existing use of the prefix
148 */
149 if (node != NULL) {
150 if (node->nsDef == NULL) {
151 node->nsDef = cur;
152 } else {
153 xmlNsPtr prev = node->nsDef;
154
155 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
156 (xmlStrEqual(prev->prefix, cur->prefix))) {
157 xmlFreeNs(cur);
158 return(NULL);
159 }
160 while (prev->next != NULL) {
161 prev = prev->next;
162 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
163 (xmlStrEqual(prev->prefix, cur->prefix))) {
164 xmlFreeNs(cur);
165 return(NULL);
166 }
167 }
168 prev->next = cur;
169 }
170 }
171 return(cur);
172}
173
174/**
175 * xmlSetNs:
176 * @node: a node in the document
177 * @ns: a namespace pointer
178 *
179 * Associate a namespace to a node, a posteriori.
180 */
181void
182xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
183 if (node == NULL) {
184#ifdef DEBUG_TREE
185 xmlGenericError(xmlGenericErrorContext,
186 "xmlSetNs: node == NULL\n");
187#endif
188 return;
189 }
190 node->ns = ns;
191}
192
193/**
194 * xmlFreeNs:
195 * @cur: the namespace pointer
196 *
197 * Free up the structures associated to a namespace
198 */
199void
200xmlFreeNs(xmlNsPtr cur) {
201 if (cur == NULL) {
202#ifdef DEBUG_TREE
203 xmlGenericError(xmlGenericErrorContext,
204 "xmlFreeNs : ns == NULL\n");
205#endif
206 return;
207 }
208 if (cur->href != NULL) xmlFree((char *) cur->href);
209 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000210 xmlFree(cur);
211}
212
213/**
214 * xmlFreeNsList:
215 * @cur: the first namespace pointer
216 *
217 * Free up all the structures associated to the chained namespaces.
218 */
219void
220xmlFreeNsList(xmlNsPtr cur) {
221 xmlNsPtr next;
222 if (cur == NULL) {
223#ifdef DEBUG_TREE
224 xmlGenericError(xmlGenericErrorContext,
225 "xmlFreeNsList : ns == NULL\n");
226#endif
227 return;
228 }
229 while (cur != NULL) {
230 next = cur->next;
231 xmlFreeNs(cur);
232 cur = next;
233 }
234}
235
236/**
237 * xmlNewDtd:
238 * @doc: the document pointer
239 * @name: the DTD name
240 * @ExternalID: the external ID
241 * @SystemID: the system ID
242 *
243 * Creation of a new DTD for the external subset. To create an
244 * internal subset, use xmlCreateIntSubset().
245 *
246 * Returns a pointer to the new DTD structure
247 */
248xmlDtdPtr
249xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
250 const xmlChar *ExternalID, const xmlChar *SystemID) {
251 xmlDtdPtr cur;
252
253 if ((doc != NULL) && (doc->extSubset != NULL)) {
254#ifdef DEBUG_TREE
255 xmlGenericError(xmlGenericErrorContext,
256 "xmlNewDtd(%s): document %s already have a DTD %s\n",
257 /* !!! */ (char *) name, doc->name,
258 /* !!! */ (char *)doc->extSubset->name);
259#endif
260 return(NULL);
261 }
262
263 /*
264 * Allocate a new DTD and fill the fields.
265 */
266 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
267 if (cur == NULL) {
268 xmlGenericError(xmlGenericErrorContext,
269 "xmlNewDtd : malloc failed\n");
270 return(NULL);
271 }
272 memset(cur, 0 , sizeof(xmlDtd));
273 cur->type = XML_DTD_NODE;
274
275 if (name != NULL)
276 cur->name = xmlStrdup(name);
277 if (ExternalID != NULL)
278 cur->ExternalID = xmlStrdup(ExternalID);
279 if (SystemID != NULL)
280 cur->SystemID = xmlStrdup(SystemID);
281 if (doc != NULL)
282 doc->extSubset = cur;
283 cur->doc = doc;
284
285 return(cur);
286}
287
288/**
289 * xmlGetIntSubset:
290 * @doc: the document pointer
291 *
292 * Get the internal subset of a document
293 * Returns a pointer to the DTD structure or NULL if not found
294 */
295
296xmlDtdPtr
297xmlGetIntSubset(xmlDocPtr doc) {
298 xmlNodePtr cur;
299
300 if (doc == NULL)
301 return(NULL);
302 cur = doc->children;
303 while (cur != NULL) {
304 if (cur->type == XML_DTD_NODE)
305 return((xmlDtdPtr) cur);
306 cur = cur->next;
307 }
308 return((xmlDtdPtr) doc->intSubset);
309}
310
311/**
312 * xmlCreateIntSubset:
313 * @doc: the document pointer
314 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000315 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000316 * @SystemID: the system ID
317 *
318 * Create the internal subset of a document
319 * Returns a pointer to the new DTD structure
320 */
321xmlDtdPtr
322xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
323 const xmlChar *ExternalID, const xmlChar *SystemID) {
324 xmlDtdPtr cur;
325
326 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
327#ifdef DEBUG_TREE
328 xmlGenericError(xmlGenericErrorContext,
329
330 "xmlCreateIntSubset(): document %s already have an internal subset\n",
331 doc->name);
332#endif
333 return(NULL);
334 }
335
336 /*
337 * Allocate a new DTD and fill the fields.
338 */
339 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
340 if (cur == NULL) {
341 xmlGenericError(xmlGenericErrorContext,
342 "xmlNewDtd : malloc failed\n");
343 return(NULL);
344 }
345 memset(cur, 0, sizeof(xmlDtd));
346 cur->type = XML_DTD_NODE;
347
348 if (name != NULL)
349 cur->name = xmlStrdup(name);
350 if (ExternalID != NULL)
351 cur->ExternalID = xmlStrdup(ExternalID);
352 if (SystemID != NULL)
353 cur->SystemID = xmlStrdup(SystemID);
354 if (doc != NULL) {
355 doc->intSubset = cur;
356 cur->parent = doc;
357 cur->doc = doc;
358 if (doc->children == NULL) {
359 doc->children = (xmlNodePtr) cur;
360 doc->last = (xmlNodePtr) cur;
361 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000362 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000363 xmlNodePtr prev;
364
Owen Taylor3473f882001-02-23 17:55:21 +0000365 prev = doc->children;
366 prev->prev = (xmlNodePtr) cur;
367 cur->next = prev;
368 doc->children = (xmlNodePtr) cur;
369 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000370 xmlNodePtr next;
371
372 next = doc->children;
373 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
374 next = next->next;
375 if (next == NULL) {
376 cur->prev = doc->last;
377 cur->prev->next = (xmlNodePtr) cur;
378 cur->next = NULL;
379 doc->last = (xmlNodePtr) cur;
380 } else {
381 cur->next = next;
382 cur->prev = next->prev;
383 if (cur->prev == NULL)
384 doc->children = (xmlNodePtr) cur;
385 else
386 cur->prev->next = (xmlNodePtr) cur;
387 next->prev = (xmlNodePtr) cur;
388 }
Owen Taylor3473f882001-02-23 17:55:21 +0000389 }
390 }
391 }
392 return(cur);
393}
394
395/**
396 * xmlFreeDtd:
397 * @cur: the DTD structure to free up
398 *
399 * Free a DTD structure.
400 */
401void
402xmlFreeDtd(xmlDtdPtr cur) {
403 if (cur == NULL) {
404#ifdef DEBUG_TREE
405 xmlGenericError(xmlGenericErrorContext,
406 "xmlFreeDtd : DTD == NULL\n");
407#endif
408 return;
409 }
410 if (cur->children != NULL) {
411 xmlNodePtr next, c = cur->children;
412
413 /*
414 * Cleanup all the DTD comments they are not in the Dtd
415 * indexes.
416 */
417 while (c != NULL) {
418 next = c->next;
419 if (c->type == XML_COMMENT_NODE) {
420 xmlUnlinkNode(c);
421 xmlFreeNode(c);
422 }
423 c = next;
424 }
425 }
426 if (cur->name != NULL) xmlFree((char *) cur->name);
427 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
428 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
429 /* TODO !!! */
430 if (cur->notations != NULL)
431 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
432
433 if (cur->elements != NULL)
434 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
435 if (cur->attributes != NULL)
436 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
437 if (cur->entities != NULL)
438 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
439 if (cur->pentities != NULL)
440 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
441
Owen Taylor3473f882001-02-23 17:55:21 +0000442 xmlFree(cur);
443}
444
445/**
446 * xmlNewDoc:
447 * @version: xmlChar string giving the version of XML "1.0"
448 *
449 * Returns a new document
450 */
451xmlDocPtr
452xmlNewDoc(const xmlChar *version) {
453 xmlDocPtr cur;
454
455 if (version == NULL)
456 version = (const xmlChar *) "1.0";
457
458 /*
459 * Allocate a new document and fill the fields.
460 */
461 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
462 if (cur == NULL) {
463 xmlGenericError(xmlGenericErrorContext,
464 "xmlNewDoc : malloc failed\n");
465 return(NULL);
466 }
467 memset(cur, 0, sizeof(xmlDoc));
468 cur->type = XML_DOCUMENT_NODE;
469
470 cur->version = xmlStrdup(version);
471 cur->standalone = -1;
472 cur->compression = -1; /* not initialized */
473 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000474 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000475 return(cur);
476}
477
478/**
479 * xmlFreeDoc:
480 * @cur: pointer to the document
481 * @:
482 *
483 * Free up all the structures used by a document, tree included.
484 */
485void
486xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000487 xmlDtdPtr extSubset, intSubset;
488
Owen Taylor3473f882001-02-23 17:55:21 +0000489 if (cur == NULL) {
490#ifdef DEBUG_TREE
491 xmlGenericError(xmlGenericErrorContext,
492 "xmlFreeDoc : document == NULL\n");
493#endif
494 return;
495 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000496 /*
497 * Do this before freeing the children list to avoid ID lookups
498 */
499 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
500 cur->ids = NULL;
501 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
502 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000503 extSubset = cur->extSubset;
504 intSubset = cur->intSubset;
505 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000506 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000507 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000508 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000509 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000510 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000511 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000512 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000513 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000514 }
515
516 if (cur->children != NULL) xmlFreeNodeList(cur->children);
517
Owen Taylor3473f882001-02-23 17:55:21 +0000518 if (cur->version != NULL) xmlFree((char *) cur->version);
519 if (cur->name != NULL) xmlFree((char *) cur->name);
520 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000521 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000522 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000523 xmlFree(cur);
524}
525
526/**
527 * xmlStringLenGetNodeList:
528 * @doc: the document
529 * @value: the value of the text
530 * @len: the length of the string value
531 *
532 * Parse the value string and build the node list associated. Should
533 * produce a flat tree with only TEXTs and ENTITY_REFs.
534 * Returns a pointer to the first child
535 */
536xmlNodePtr
537xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
538 xmlNodePtr ret = NULL, last = NULL;
539 xmlNodePtr node;
540 xmlChar *val;
541 const xmlChar *cur = value;
542 const xmlChar *q;
543 xmlEntityPtr ent;
544
545 if (value == NULL) return(NULL);
546
547 q = cur;
548 while ((*cur != 0) && (cur - value < len)) {
549 if (*cur == '&') {
550 /*
551 * Save the current text.
552 */
553 if (cur != q) {
554 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
555 xmlNodeAddContentLen(last, q, cur - q);
556 } else {
557 node = xmlNewDocTextLen(doc, q, cur - q);
558 if (node == NULL) return(ret);
559 if (last == NULL)
560 last = ret = node;
561 else {
562 last->next = node;
563 node->prev = last;
564 last = node;
565 }
566 }
567 }
568 /*
569 * Read the entity string
570 */
571 cur++;
572 q = cur;
573 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
574 if ((*cur == 0) || (cur - value >= len)) {
575#ifdef DEBUG_TREE
576 xmlGenericError(xmlGenericErrorContext,
577 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
578#endif
579 return(ret);
580 }
581 if (cur != q) {
582 /*
583 * Predefined entities don't generate nodes
584 */
585 val = xmlStrndup(q, cur - q);
586 ent = xmlGetDocEntity(doc, val);
587 if ((ent != NULL) &&
588 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
589 if (last == NULL) {
590 node = xmlNewDocText(doc, ent->content);
591 last = ret = node;
592 } else
593 xmlNodeAddContent(last, ent->content);
594
595 } else {
596 /*
597 * Create a new REFERENCE_REF node
598 */
599 node = xmlNewReference(doc, val);
600 if (node == NULL) {
601 if (val != NULL) xmlFree(val);
602 return(ret);
603 }
604 if (last == NULL)
605 last = ret = node;
606 else {
607 last->next = node;
608 node->prev = last;
609 last = node;
610 }
611 }
612 xmlFree(val);
613 }
614 cur++;
615 q = cur;
616 } else
617 cur++;
618 }
619 if (cur != q) {
620 /*
621 * Handle the last piece of text.
622 */
623 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
624 xmlNodeAddContentLen(last, q, cur - q);
625 } else {
626 node = xmlNewDocTextLen(doc, q, cur - q);
627 if (node == NULL) return(ret);
628 if (last == NULL)
629 last = ret = node;
630 else {
631 last->next = node;
632 node->prev = last;
633 last = node;
634 }
635 }
636 }
637 return(ret);
638}
639
640/**
641 * xmlStringGetNodeList:
642 * @doc: the document
643 * @value: the value of the attribute
644 *
645 * Parse the value string and build the node list associated. Should
646 * produce a flat tree with only TEXTs and ENTITY_REFs.
647 * Returns a pointer to the first child
648 */
649xmlNodePtr
650xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
651 xmlNodePtr ret = NULL, last = NULL;
652 xmlNodePtr node;
653 xmlChar *val;
654 const xmlChar *cur = value;
655 const xmlChar *q;
656 xmlEntityPtr ent;
657
658 if (value == NULL) return(NULL);
659
660 q = cur;
661 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000662 if (cur[0] == '&') {
663 int charval = 0;
664 xmlChar tmp;
665
Owen Taylor3473f882001-02-23 17:55:21 +0000666 /*
667 * Save the current text.
668 */
669 if (cur != q) {
670 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
671 xmlNodeAddContentLen(last, q, cur - q);
672 } else {
673 node = xmlNewDocTextLen(doc, q, cur - q);
674 if (node == NULL) return(ret);
675 if (last == NULL)
676 last = ret = node;
677 else {
678 last->next = node;
679 node->prev = last;
680 last = node;
681 }
682 }
683 }
Owen Taylor3473f882001-02-23 17:55:21 +0000684 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000685 if ((cur[1] == '#') && (cur[2] == 'x')) {
686 cur += 3;
687 tmp = *cur;
688 while (tmp != ';') { /* Non input consuming loop */
689 if ((tmp >= '0') && (tmp <= '9'))
690 charval = charval * 16 + (tmp - '0');
691 else if ((tmp >= 'a') && (tmp <= 'f'))
692 charval = charval * 16 + (tmp - 'a') + 10;
693 else if ((tmp >= 'A') && (tmp <= 'F'))
694 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000695 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000696 xmlGenericError(xmlGenericErrorContext,
697 "xmlStringGetNodeList: incharvalid hexadecimal charvalue\n");
698 charval = 0;
699 break;
700 }
701 cur++;
702 tmp = *cur;
703 }
704 if (tmp == ';')
705 cur++;
706 q = cur;
707 } else if (cur[1] == '#') {
708 cur += 2;
709 tmp = *cur;
710 while (tmp != ';') { /* Non input consuming loops */
711 if ((tmp >= '0') && (tmp <= '9'))
712 charval = charval * 10 + (tmp - '0');
713 else {
714 xmlGenericError(xmlGenericErrorContext,
715 "xmlStringGetNodeList: incharvalid decimal charvalue\n");
716 charval = 0;
717 break;
718 }
719 cur++;
720 tmp = *cur;
721 }
722 if (tmp == ';')
723 cur++;
724 q = cur;
725 } else {
726 /*
727 * Read the entity string
728 */
729 cur++;
730 q = cur;
731 while ((*cur != 0) && (*cur != ';')) cur++;
732 if (*cur == 0) {
733#ifdef DEBUG_TREE
734 xmlGenericError(xmlGenericErrorContext,
735 "xmlStringGetNodeList: unterminated entity %30s\n", q);
736#endif
737 return(ret);
738 }
739 if (cur != q) {
740 /*
741 * Predefined entities don't generate nodes
742 */
743 val = xmlStrndup(q, cur - q);
744 ent = xmlGetDocEntity(doc, val);
745 if ((ent != NULL) &&
746 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
747 if (last == NULL) {
748 node = xmlNewDocText(doc, ent->content);
749 last = ret = node;
750 } else
751 xmlNodeAddContent(last, ent->content);
752
753 } else {
754 /*
755 * Create a new REFERENCE_REF node
756 */
757 node = xmlNewReference(doc, val);
758 if (node == NULL) {
759 if (val != NULL) xmlFree(val);
760 return(ret);
761 }
762 if (last == NULL) {
763 last = ret = node;
764 } else {
765 last = xmlAddNextSibling(last, node);
766 }
767 }
768 xmlFree(val);
769 }
770 cur++;
771 q = cur;
772 }
773 if (charval != 0) {
774 xmlChar buf[10];
775 int len;
776
777 len = xmlCopyCharMultiByte(buf, charval);
778 buf[len] = 0;
779 node = xmlNewDocText(doc, buf);
780 if (node != NULL) {
781 if (last == NULL) {
782 last = ret = node;
783 } else {
784 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000785 }
786 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000787
788 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000789 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000790 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000791 cur++;
792 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000793 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000794 /*
795 * Handle the last piece of text.
796 */
797 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
798 xmlNodeAddContentLen(last, q, cur - q);
799 } else {
800 node = xmlNewDocTextLen(doc, q, cur - q);
801 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000802 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000803 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000804 } else {
805 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000806 }
807 }
808 }
809 return(ret);
810}
811
812/**
813 * xmlNodeListGetString:
814 * @doc: the document
815 * @list: a Node list
816 * @inLine: should we replace entity contents or show their external form
817 *
818 * Returns the string equivalent to the text contained in the Node list
819 * made of TEXTs and ENTITY_REFs
820 * Returns a pointer to the string copy, the calller must free it.
821 */
822xmlChar *
823xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
824 xmlNodePtr node = list;
825 xmlChar *ret = NULL;
826 xmlEntityPtr ent;
827
828 if (list == NULL) return(NULL);
829
830 while (node != NULL) {
831 if ((node->type == XML_TEXT_NODE) ||
832 (node->type == XML_CDATA_SECTION_NODE)) {
833 if (inLine) {
834#ifndef XML_USE_BUFFER_CONTENT
835 ret = xmlStrcat(ret, node->content);
836#else
837 ret = xmlStrcat(ret, xmlBufferContent(node->content));
838#endif
839 } else {
840 xmlChar *buffer;
841
842#ifndef XML_USE_BUFFER_CONTENT
843 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
844#else
845 buffer = xmlEncodeEntitiesReentrant(doc,
846 xmlBufferContent(node->content));
847#endif
848 if (buffer != NULL) {
849 ret = xmlStrcat(ret, buffer);
850 xmlFree(buffer);
851 }
852 }
853 } else if (node->type == XML_ENTITY_REF_NODE) {
854 if (inLine) {
855 ent = xmlGetDocEntity(doc, node->name);
856 if (ent != NULL)
857 ret = xmlStrcat(ret, ent->content);
858 else {
859#ifndef XML_USE_BUFFER_CONTENT
860 ret = xmlStrcat(ret, node->content);
861#else
862 ret = xmlStrcat(ret, xmlBufferContent(node->content));
863#endif
864 }
865 } else {
866 xmlChar buf[2];
867 buf[0] = '&'; buf[1] = 0;
868 ret = xmlStrncat(ret, buf, 1);
869 ret = xmlStrcat(ret, node->name);
870 buf[0] = ';'; buf[1] = 0;
871 ret = xmlStrncat(ret, buf, 1);
872 }
873 }
874#if 0
875 else {
876 xmlGenericError(xmlGenericErrorContext,
877 "xmlGetNodeListString : invalide node type %d\n",
878 node->type);
879 }
880#endif
881 node = node->next;
882 }
883 return(ret);
884}
885
886/**
887 * xmlNodeListGetRawString:
888 * @doc: the document
889 * @list: a Node list
890 * @inLine: should we replace entity contents or show their external form
891 *
892 * Returns the string equivalent to the text contained in the Node list
893 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
894 * this function doesn't do any character encoding handling.
895 *
896 * Returns a pointer to the string copy, the calller must free it.
897 */
898xmlChar *
899xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
900 xmlNodePtr node = list;
901 xmlChar *ret = NULL;
902 xmlEntityPtr ent;
903
904 if (list == NULL) return(NULL);
905
906 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000907 if ((node->type == XML_TEXT_NODE) ||
908 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000909 if (inLine) {
910#ifndef XML_USE_BUFFER_CONTENT
911 ret = xmlStrcat(ret, node->content);
912#else
913 ret = xmlStrcat(ret, xmlBufferContent(node->content));
914#endif
915 } else {
916 xmlChar *buffer;
917
918#ifndef XML_USE_BUFFER_CONTENT
919 buffer = xmlEncodeSpecialChars(doc, node->content);
920#else
921 buffer = xmlEncodeSpecialChars(doc,
922 xmlBufferContent(node->content));
923#endif
924 if (buffer != NULL) {
925 ret = xmlStrcat(ret, buffer);
926 xmlFree(buffer);
927 }
928 }
929 } else if (node->type == XML_ENTITY_REF_NODE) {
930 if (inLine) {
931 ent = xmlGetDocEntity(doc, node->name);
932 if (ent != NULL)
933 ret = xmlStrcat(ret, ent->content);
934 else {
935#ifndef XML_USE_BUFFER_CONTENT
936 ret = xmlStrcat(ret, node->content);
937#else
938 ret = xmlStrcat(ret, xmlBufferContent(node->content));
939#endif
940 }
941 } else {
942 xmlChar buf[2];
943 buf[0] = '&'; buf[1] = 0;
944 ret = xmlStrncat(ret, buf, 1);
945 ret = xmlStrcat(ret, node->name);
946 buf[0] = ';'; buf[1] = 0;
947 ret = xmlStrncat(ret, buf, 1);
948 }
949 }
950#if 0
951 else {
952 xmlGenericError(xmlGenericErrorContext,
953 "xmlGetNodeListString : invalide node type %d\n",
954 node->type);
955 }
956#endif
957 node = node->next;
958 }
959 return(ret);
960}
961
962/**
963 * xmlNewProp:
964 * @node: the holding node
965 * @name: the name of the attribute
966 * @value: the value of the attribute
967 *
968 * Create a new property carried by a node.
969 * Returns a pointer to the attribute
970 */
971xmlAttrPtr
972xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
973 xmlAttrPtr cur;
974 xmlDocPtr doc = NULL;
975
976 if (name == NULL) {
977#ifdef DEBUG_TREE
978 xmlGenericError(xmlGenericErrorContext,
979 "xmlNewProp : name == NULL\n");
980#endif
981 return(NULL);
982 }
983
984 /*
985 * Allocate a new property and fill the fields.
986 */
987 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
988 if (cur == NULL) {
989 xmlGenericError(xmlGenericErrorContext,
990 "xmlNewProp : malloc failed\n");
991 return(NULL);
992 }
993 memset(cur, 0, sizeof(xmlAttr));
994 cur->type = XML_ATTRIBUTE_NODE;
995
996 cur->parent = node;
997 if (node != NULL) {
998 doc = node->doc;
999 cur->doc = doc;
1000 }
1001 cur->name = xmlStrdup(name);
1002 if (value != NULL) {
1003 xmlChar *buffer;
1004 xmlNodePtr tmp;
1005
1006 buffer = xmlEncodeEntitiesReentrant(doc, value);
1007 cur->children = xmlStringGetNodeList(doc, buffer);
1008 cur->last = NULL;
1009 tmp = cur->children;
1010 while (tmp != NULL) {
1011 tmp->parent = (xmlNodePtr) cur;
1012 tmp->doc = doc;
1013 if (tmp->next == NULL)
1014 cur->last = tmp;
1015 tmp = tmp->next;
1016 }
1017 xmlFree(buffer);
1018 }
1019
1020 /*
1021 * Add it at the end to preserve parsing order ...
1022 */
1023 if (node != NULL) {
1024 if (node->properties == NULL) {
1025 node->properties = cur;
1026 } else {
1027 xmlAttrPtr prev = node->properties;
1028
1029 while (prev->next != NULL) prev = prev->next;
1030 prev->next = cur;
1031 cur->prev = prev;
1032 }
1033 }
1034 return(cur);
1035}
1036
1037/**
1038 * xmlNewNsProp:
1039 * @node: the holding node
1040 * @ns: the namespace
1041 * @name: the name of the attribute
1042 * @value: the value of the attribute
1043 *
1044 * Create a new property tagged with a namespace and carried by a node.
1045 * Returns a pointer to the attribute
1046 */
1047xmlAttrPtr
1048xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1049 const xmlChar *value) {
1050 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001051 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001052
1053 if (name == NULL) {
1054#ifdef DEBUG_TREE
1055 xmlGenericError(xmlGenericErrorContext,
1056 "xmlNewProp : name == NULL\n");
1057#endif
1058 return(NULL);
1059 }
1060
1061 /*
1062 * Allocate a new property and fill the fields.
1063 */
1064 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1065 if (cur == NULL) {
1066 xmlGenericError(xmlGenericErrorContext,
1067 "xmlNewProp : malloc failed\n");
1068 return(NULL);
1069 }
1070 memset(cur, 0, sizeof(xmlAttr));
1071 cur->type = XML_ATTRIBUTE_NODE;
1072
1073 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001074 if (node != NULL) {
1075 doc = node->doc;
1076 cur->doc = doc;
1077 }
Owen Taylor3473f882001-02-23 17:55:21 +00001078 cur->ns = ns;
1079 cur->name = xmlStrdup(name);
1080 if (value != NULL) {
1081 xmlChar *buffer;
1082 xmlNodePtr tmp;
1083
Daniel Veillarda682b212001-06-07 19:59:42 +00001084 buffer = xmlEncodeEntitiesReentrant(doc, value);
1085 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001086 cur->last = NULL;
1087 tmp = cur->children;
1088 while (tmp != NULL) {
1089 tmp->parent = (xmlNodePtr) cur;
1090 if (tmp->next == NULL)
1091 cur->last = tmp;
1092 tmp = tmp->next;
1093 }
1094 xmlFree(buffer);
1095 }
1096
1097 /*
1098 * Add it at the end to preserve parsing order ...
1099 */
1100 if (node != NULL) {
1101 if (node->properties == NULL) {
1102 node->properties = cur;
1103 } else {
1104 xmlAttrPtr prev = node->properties;
1105
1106 while (prev->next != NULL) prev = prev->next;
1107 prev->next = cur;
1108 cur->prev = prev;
1109 }
1110 }
1111 return(cur);
1112}
1113
1114/**
1115 * xmlNewDocProp:
1116 * @doc: the document
1117 * @name: the name of the attribute
1118 * @value: the value of the attribute
1119 *
1120 * Create a new property carried by a document.
1121 * Returns a pointer to the attribute
1122 */
1123xmlAttrPtr
1124xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1125 xmlAttrPtr cur;
1126
1127 if (name == NULL) {
1128#ifdef DEBUG_TREE
1129 xmlGenericError(xmlGenericErrorContext,
1130 "xmlNewProp : name == NULL\n");
1131#endif
1132 return(NULL);
1133 }
1134
1135 /*
1136 * Allocate a new property and fill the fields.
1137 */
1138 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1139 if (cur == NULL) {
1140 xmlGenericError(xmlGenericErrorContext,
1141 "xmlNewProp : malloc failed\n");
1142 return(NULL);
1143 }
1144 memset(cur, 0, sizeof(xmlAttr));
1145 cur->type = XML_ATTRIBUTE_NODE;
1146
1147 cur->name = xmlStrdup(name);
1148 cur->doc = doc;
1149 if (value != NULL) {
1150 xmlNodePtr tmp;
1151
1152 cur->children = xmlStringGetNodeList(doc, value);
1153 cur->last = NULL;
1154
1155 tmp = cur->children;
1156 while (tmp != NULL) {
1157 tmp->parent = (xmlNodePtr) cur;
1158 if (tmp->next == NULL)
1159 cur->last = tmp;
1160 tmp = tmp->next;
1161 }
1162 }
1163 return(cur);
1164}
1165
1166/**
1167 * xmlFreePropList:
1168 * @cur: the first property in the list
1169 *
1170 * Free a property and all its siblings, all the children are freed too.
1171 */
1172void
1173xmlFreePropList(xmlAttrPtr cur) {
1174 xmlAttrPtr next;
1175 if (cur == NULL) {
1176#ifdef DEBUG_TREE
1177 xmlGenericError(xmlGenericErrorContext,
1178 "xmlFreePropList : property == NULL\n");
1179#endif
1180 return;
1181 }
1182 while (cur != NULL) {
1183 next = cur->next;
1184 xmlFreeProp(cur);
1185 cur = next;
1186 }
1187}
1188
1189/**
1190 * xmlFreeProp:
1191 * @cur: an attribute
1192 *
1193 * Free one attribute, all the content is freed too
1194 */
1195void
1196xmlFreeProp(xmlAttrPtr cur) {
1197 if (cur == NULL) {
1198#ifdef DEBUG_TREE
1199 xmlGenericError(xmlGenericErrorContext,
1200 "xmlFreeProp : property == NULL\n");
1201#endif
1202 return;
1203 }
1204 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001205 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1206 ((cur->parent->doc->intSubset != NULL) ||
1207 (cur->parent->doc->extSubset != NULL))) {
1208 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1209 xmlRemoveID(cur->parent->doc, cur);
1210 }
Owen Taylor3473f882001-02-23 17:55:21 +00001211 if (cur->name != NULL) xmlFree((char *) cur->name);
1212 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001213 xmlFree(cur);
1214}
1215
1216/**
1217 * xmlRemoveProp:
1218 * @cur: an attribute
1219 *
1220 * Unlink and free one attribute, all the content is freed too
1221 * Note this doesn't work for namespace definition attributes
1222 *
1223 * Returns 0 if success and -1 in case of error.
1224 */
1225int
1226xmlRemoveProp(xmlAttrPtr cur) {
1227 xmlAttrPtr tmp;
1228 if (cur == NULL) {
1229#ifdef DEBUG_TREE
1230 xmlGenericError(xmlGenericErrorContext,
1231 "xmlRemoveProp : cur == NULL\n");
1232#endif
1233 return(-1);
1234 }
1235 if (cur->parent == NULL) {
1236#ifdef DEBUG_TREE
1237 xmlGenericError(xmlGenericErrorContext,
1238 "xmlRemoveProp : cur->parent == NULL\n");
1239#endif
1240 return(-1);
1241 }
1242 tmp = cur->parent->properties;
1243 if (tmp == cur) {
1244 cur->parent->properties = cur->next;
1245 xmlFreeProp(cur);
1246 return(0);
1247 }
1248 while (tmp != NULL) {
1249 if (tmp->next == cur) {
1250 tmp->next = cur->next;
1251 if (tmp->next != NULL)
1252 tmp->next->prev = tmp;
1253 xmlFreeProp(cur);
1254 return(0);
1255 }
1256 tmp = tmp->next;
1257 }
1258#ifdef DEBUG_TREE
1259 xmlGenericError(xmlGenericErrorContext,
1260 "xmlRemoveProp : attribute not owned by its node\n");
1261#endif
1262 return(-1);
1263}
1264
1265/**
1266 * xmlNewPI:
1267 * @name: the processing instruction name
1268 * @content: the PI content
1269 *
1270 * Creation of a processing instruction element.
1271 * Returns a pointer to the new node object.
1272 */
1273xmlNodePtr
1274xmlNewPI(const xmlChar *name, const xmlChar *content) {
1275 xmlNodePtr cur;
1276
1277 if (name == NULL) {
1278#ifdef DEBUG_TREE
1279 xmlGenericError(xmlGenericErrorContext,
1280 "xmlNewPI : name == NULL\n");
1281#endif
1282 return(NULL);
1283 }
1284
1285 /*
1286 * Allocate a new node and fill the fields.
1287 */
1288 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1289 if (cur == NULL) {
1290 xmlGenericError(xmlGenericErrorContext,
1291 "xmlNewPI : malloc failed\n");
1292 return(NULL);
1293 }
1294 memset(cur, 0, sizeof(xmlNode));
1295 cur->type = XML_PI_NODE;
1296
1297 cur->name = xmlStrdup(name);
1298 if (content != NULL) {
1299#ifndef XML_USE_BUFFER_CONTENT
1300 cur->content = xmlStrdup(content);
1301#else
1302 cur->content = xmlBufferCreateSize(0);
1303 xmlBufferSetAllocationScheme(cur->content,
1304 xmlGetBufferAllocationScheme());
1305 xmlBufferAdd(cur->content, content, -1);
1306#endif
1307 }
1308 return(cur);
1309}
1310
1311/**
1312 * xmlNewNode:
1313 * @ns: namespace if any
1314 * @name: the node name
1315 *
1316 * Creation of a new node element. @ns is optionnal (NULL).
1317 *
1318 * Returns a pointer to the new node object.
1319 */
1320xmlNodePtr
1321xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1322 xmlNodePtr cur;
1323
1324 if (name == NULL) {
1325#ifdef DEBUG_TREE
1326 xmlGenericError(xmlGenericErrorContext,
1327 "xmlNewNode : name == NULL\n");
1328#endif
1329 return(NULL);
1330 }
1331
1332 /*
1333 * Allocate a new node and fill the fields.
1334 */
1335 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1336 if (cur == NULL) {
1337 xmlGenericError(xmlGenericErrorContext,
1338 "xmlNewNode : malloc failed\n");
1339 return(NULL);
1340 }
1341 memset(cur, 0, sizeof(xmlNode));
1342 cur->type = XML_ELEMENT_NODE;
1343
1344 cur->name = xmlStrdup(name);
1345 cur->ns = ns;
1346 return(cur);
1347}
1348
1349/**
1350 * xmlNewDocNode:
1351 * @doc: the document
1352 * @ns: namespace if any
1353 * @name: the node name
1354 * @content: the XML text content if any
1355 *
1356 * Creation of a new node element within a document. @ns and @content
1357 * are optionnal (NULL).
1358 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1359 * references, but XML special chars need to be escaped first by using
1360 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1361 * need entities support.
1362 *
1363 * Returns a pointer to the new node object.
1364 */
1365xmlNodePtr
1366xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1367 const xmlChar *name, const xmlChar *content) {
1368 xmlNodePtr cur;
1369
1370 cur = xmlNewNode(ns, name);
1371 if (cur != NULL) {
1372 cur->doc = doc;
1373 if (content != NULL) {
1374 cur->children = xmlStringGetNodeList(doc, content);
1375 UPDATE_LAST_CHILD_AND_PARENT(cur)
1376 }
1377 }
1378 return(cur);
1379}
1380
1381
1382/**
1383 * xmlNewDocRawNode:
1384 * @doc: the document
1385 * @ns: namespace if any
1386 * @name: the node name
1387 * @content: the text content if any
1388 *
1389 * Creation of a new node element within a document. @ns and @content
1390 * are optionnal (NULL).
1391 *
1392 * Returns a pointer to the new node object.
1393 */
1394xmlNodePtr
1395xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1396 const xmlChar *name, const xmlChar *content) {
1397 xmlNodePtr cur;
1398
1399 cur = xmlNewNode(ns, name);
1400 if (cur != NULL) {
1401 cur->doc = doc;
1402 if (content != NULL) {
1403 cur->children = xmlNewDocText(doc, content);
1404 UPDATE_LAST_CHILD_AND_PARENT(cur)
1405 }
1406 }
1407 return(cur);
1408}
1409
1410/**
1411 * xmlNewDocFragment:
1412 * @doc: the document owning the fragment
1413 *
1414 * Creation of a new Fragment node.
1415 * Returns a pointer to the new node object.
1416 */
1417xmlNodePtr
1418xmlNewDocFragment(xmlDocPtr doc) {
1419 xmlNodePtr cur;
1420
1421 /*
1422 * Allocate a new DocumentFragment node and fill the fields.
1423 */
1424 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1425 if (cur == NULL) {
1426 xmlGenericError(xmlGenericErrorContext,
1427 "xmlNewDocFragment : malloc failed\n");
1428 return(NULL);
1429 }
1430 memset(cur, 0, sizeof(xmlNode));
1431 cur->type = XML_DOCUMENT_FRAG_NODE;
1432
1433 cur->doc = doc;
1434 return(cur);
1435}
1436
1437/**
1438 * xmlNewText:
1439 * @content: the text content
1440 *
1441 * Creation of a new text node.
1442 * Returns a pointer to the new node object.
1443 */
1444xmlNodePtr
1445xmlNewText(const xmlChar *content) {
1446 xmlNodePtr cur;
1447
1448 /*
1449 * Allocate a new node and fill the fields.
1450 */
1451 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1452 if (cur == NULL) {
1453 xmlGenericError(xmlGenericErrorContext,
1454 "xmlNewText : malloc failed\n");
1455 return(NULL);
1456 }
1457 memset(cur, 0, sizeof(xmlNode));
1458 cur->type = XML_TEXT_NODE;
1459
1460 cur->name = xmlStringText;
1461 if (content != NULL) {
1462#ifndef XML_USE_BUFFER_CONTENT
1463 cur->content = xmlStrdup(content);
1464#else
1465 cur->content = xmlBufferCreateSize(0);
1466 xmlBufferSetAllocationScheme(cur->content,
1467 xmlGetBufferAllocationScheme());
1468 xmlBufferAdd(cur->content, content, -1);
1469#endif
1470 }
1471 return(cur);
1472}
1473
1474/**
1475 * xmlNewTextChild:
1476 * @parent: the parent node
1477 * @ns: a namespace if any
1478 * @name: the name of the child
1479 * @content: the text content of the child if any.
1480 *
1481 * Creation of a new child element, added at the end of @parent children list.
1482 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1483 * a child TEXT node will be created containing the string content.
1484 *
1485 * Returns a pointer to the new node object.
1486 */
1487xmlNodePtr
1488xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1489 const xmlChar *name, const xmlChar *content) {
1490 xmlNodePtr cur, prev;
1491
1492 if (parent == NULL) {
1493#ifdef DEBUG_TREE
1494 xmlGenericError(xmlGenericErrorContext,
1495 "xmlNewTextChild : parent == NULL\n");
1496#endif
1497 return(NULL);
1498 }
1499
1500 if (name == NULL) {
1501#ifdef DEBUG_TREE
1502 xmlGenericError(xmlGenericErrorContext,
1503 "xmlNewTextChild : name == NULL\n");
1504#endif
1505 return(NULL);
1506 }
1507
1508 /*
1509 * Allocate a new node
1510 */
1511 if (ns == NULL)
1512 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1513 else
1514 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1515 if (cur == NULL) return(NULL);
1516
1517 /*
1518 * add the new element at the end of the children list.
1519 */
1520 cur->type = XML_ELEMENT_NODE;
1521 cur->parent = parent;
1522 cur->doc = parent->doc;
1523 if (parent->children == NULL) {
1524 parent->children = cur;
1525 parent->last = cur;
1526 } else {
1527 prev = parent->last;
1528 prev->next = cur;
1529 cur->prev = prev;
1530 parent->last = cur;
1531 }
1532
1533 return(cur);
1534}
1535
1536/**
1537 * xmlNewCharRef:
1538 * @doc: the document
1539 * @name: the char ref string, starting with # or "&# ... ;"
1540 *
1541 * Creation of a new character reference node.
1542 * Returns a pointer to the new node object.
1543 */
1544xmlNodePtr
1545xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1546 xmlNodePtr cur;
1547
1548 /*
1549 * Allocate a new node and fill the fields.
1550 */
1551 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1552 if (cur == NULL) {
1553 xmlGenericError(xmlGenericErrorContext,
1554 "xmlNewText : malloc failed\n");
1555 return(NULL);
1556 }
1557 memset(cur, 0, sizeof(xmlNode));
1558 cur->type = XML_ENTITY_REF_NODE;
1559
1560 cur->doc = doc;
1561 if (name[0] == '&') {
1562 int len;
1563 name++;
1564 len = xmlStrlen(name);
1565 if (name[len - 1] == ';')
1566 cur->name = xmlStrndup(name, len - 1);
1567 else
1568 cur->name = xmlStrndup(name, len);
1569 } else
1570 cur->name = xmlStrdup(name);
1571 return(cur);
1572}
1573
1574/**
1575 * xmlNewReference:
1576 * @doc: the document
1577 * @name: the reference name, or the reference string with & and ;
1578 *
1579 * Creation of a new reference node.
1580 * Returns a pointer to the new node object.
1581 */
1582xmlNodePtr
1583xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1584 xmlNodePtr cur;
1585 xmlEntityPtr ent;
1586
1587 /*
1588 * Allocate a new node and fill the fields.
1589 */
1590 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1591 if (cur == NULL) {
1592 xmlGenericError(xmlGenericErrorContext,
1593 "xmlNewText : malloc failed\n");
1594 return(NULL);
1595 }
1596 memset(cur, 0, sizeof(xmlNode));
1597 cur->type = XML_ENTITY_REF_NODE;
1598
1599 cur->doc = doc;
1600 if (name[0] == '&') {
1601 int len;
1602 name++;
1603 len = xmlStrlen(name);
1604 if (name[len - 1] == ';')
1605 cur->name = xmlStrndup(name, len - 1);
1606 else
1607 cur->name = xmlStrndup(name, len);
1608 } else
1609 cur->name = xmlStrdup(name);
1610
1611 ent = xmlGetDocEntity(doc, cur->name);
1612 if (ent != NULL) {
1613#ifndef XML_USE_BUFFER_CONTENT
1614 cur->content = ent->content;
1615#else
1616 /*
1617 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1618 * a copy of this pointer. Let's hope we don't manipulate it
1619 * later
1620 */
1621 cur->content = xmlBufferCreateSize(0);
1622 xmlBufferSetAllocationScheme(cur->content,
1623 xmlGetBufferAllocationScheme());
1624 if (ent->content != NULL)
1625 xmlBufferAdd(cur->content, ent->content, -1);
1626#endif
1627 /*
1628 * The parent pointer in entity is a Dtd pointer and thus is NOT
1629 * updated. Not sure if this is 100% correct.
1630 * -George
1631 */
1632 cur->children = (xmlNodePtr) ent;
1633 cur->last = (xmlNodePtr) ent;
1634 }
1635 return(cur);
1636}
1637
1638/**
1639 * xmlNewDocText:
1640 * @doc: the document
1641 * @content: the text content
1642 *
1643 * Creation of a new text node within a document.
1644 * Returns a pointer to the new node object.
1645 */
1646xmlNodePtr
1647xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1648 xmlNodePtr cur;
1649
1650 cur = xmlNewText(content);
1651 if (cur != NULL) cur->doc = doc;
1652 return(cur);
1653}
1654
1655/**
1656 * xmlNewTextLen:
1657 * @content: the text content
1658 * @len: the text len.
1659 *
1660 * Creation of a new text node with an extra parameter for the content's lenght
1661 * Returns a pointer to the new node object.
1662 */
1663xmlNodePtr
1664xmlNewTextLen(const xmlChar *content, int len) {
1665 xmlNodePtr cur;
1666
1667 /*
1668 * Allocate a new node and fill the fields.
1669 */
1670 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1671 if (cur == NULL) {
1672 xmlGenericError(xmlGenericErrorContext,
1673 "xmlNewText : malloc failed\n");
1674 return(NULL);
1675 }
1676 memset(cur, 0, sizeof(xmlNode));
1677 cur->type = XML_TEXT_NODE;
1678
1679 cur->name = xmlStringText;
1680 if (content != NULL) {
1681#ifndef XML_USE_BUFFER_CONTENT
1682 cur->content = xmlStrndup(content, len);
1683#else
1684 cur->content = xmlBufferCreateSize(len);
1685 xmlBufferSetAllocationScheme(cur->content,
1686 xmlGetBufferAllocationScheme());
1687 xmlBufferAdd(cur->content, content, len);
1688#endif
1689 }
1690 return(cur);
1691}
1692
1693/**
1694 * xmlNewDocTextLen:
1695 * @doc: the document
1696 * @content: the text content
1697 * @len: the text len.
1698 *
1699 * Creation of a new text node with an extra content lenght parameter. The
1700 * 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) {
1737#ifndef XML_USE_BUFFER_CONTENT
1738 cur->content = xmlStrdup(content);
1739#else
1740 cur->content = xmlBufferCreateSize(0);
1741 xmlBufferSetAllocationScheme(cur->content,
1742 xmlGetBufferAllocationScheme());
1743 xmlBufferAdd(cur->content, content, -1);
1744#endif
1745 }
1746 return(cur);
1747}
1748
1749/**
1750 * xmlNewCDataBlock:
1751 * @doc: the document
1752 * @content: the CData block content content
1753 * @len: the length of the block
1754 *
1755 * Creation of a new node containing a CData block.
1756 * Returns a pointer to the new node object.
1757 */
1758xmlNodePtr
1759xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1760 xmlNodePtr cur;
1761
1762 /*
1763 * Allocate a new node and fill the fields.
1764 */
1765 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1766 if (cur == NULL) {
1767 xmlGenericError(xmlGenericErrorContext,
1768 "xmlNewCDataBlock : malloc failed\n");
1769 return(NULL);
1770 }
1771 memset(cur, 0, sizeof(xmlNode));
1772 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001773 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001774
1775 if (content != NULL) {
1776#ifndef XML_USE_BUFFER_CONTENT
1777 cur->content = xmlStrndup(content, len);
1778#else
1779 cur->content = xmlBufferCreateSize(len);
1780 xmlBufferSetAllocationScheme(cur->content,
1781 xmlGetBufferAllocationScheme());
1782 xmlBufferAdd(cur->content, content, len);
1783#endif
1784 }
1785 return(cur);
1786}
1787
1788/**
1789 * xmlNewDocComment:
1790 * @doc: the document
1791 * @content: the comment content
1792 *
1793 * Creation of a new node containing a commentwithin a document.
1794 * Returns a pointer to the new node object.
1795 */
1796xmlNodePtr
1797xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1798 xmlNodePtr cur;
1799
1800 cur = xmlNewComment(content);
1801 if (cur != NULL) cur->doc = doc;
1802 return(cur);
1803}
1804
1805/**
1806 * xmlSetTreeDoc:
1807 * @tree: the top element
1808 * @doc: the document
1809 *
1810 * update all nodes under the tree to point to the right document
1811 */
1812void
1813xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001814 xmlAttrPtr prop;
1815
Owen Taylor3473f882001-02-23 17:55:21 +00001816 if (tree == NULL)
1817 return;
1818 if (tree->type == XML_ENTITY_DECL)
1819 return;
1820 if (tree->doc != doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001821 prop = tree->properties;
1822 while (prop != NULL) {
1823 prop->doc = doc;
1824 xmlSetListDoc(prop->children, doc);
1825 prop = prop->next;
1826 }
Owen Taylor3473f882001-02-23 17:55:21 +00001827 if (tree->children != NULL)
1828 xmlSetListDoc(tree->children, doc);
1829 tree->doc = doc;
1830 }
1831}
1832
1833/**
1834 * xmlSetListDoc:
1835 * @tree: the first element
1836 * @doc: the document
1837 *
1838 * update all nodes in the list to point to the right document
1839 */
1840void
1841xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1842 xmlNodePtr cur;
1843
1844 if (list == NULL)
1845 return;
1846 cur = list;
1847 while (cur != NULL) {
1848 if (cur->doc != doc)
1849 xmlSetTreeDoc(cur, doc);
1850 cur = cur->next;
1851 }
1852}
1853
1854
1855/**
1856 * xmlNewChild:
1857 * @parent: the parent node
1858 * @ns: a namespace if any
1859 * @name: the name of the child
1860 * @content: the XML content of the child if any.
1861 *
1862 * Creation of a new child element, added at the end of @parent children list.
1863 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1864 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1865 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1866 * references, but XML special chars need to be escaped first by using
1867 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1868 * support is not needed.
1869 *
1870 * Returns a pointer to the new node object.
1871 */
1872xmlNodePtr
1873xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1874 const xmlChar *name, const xmlChar *content) {
1875 xmlNodePtr cur, prev;
1876
1877 if (parent == NULL) {
1878#ifdef DEBUG_TREE
1879 xmlGenericError(xmlGenericErrorContext,
1880 "xmlNewChild : parent == NULL\n");
1881#endif
1882 return(NULL);
1883 }
1884
1885 if (name == NULL) {
1886#ifdef DEBUG_TREE
1887 xmlGenericError(xmlGenericErrorContext,
1888 "xmlNewChild : name == NULL\n");
1889#endif
1890 return(NULL);
1891 }
1892
1893 /*
1894 * Allocate a new node
1895 */
1896 if (ns == NULL)
1897 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1898 else
1899 cur = xmlNewDocNode(parent->doc, ns, name, content);
1900 if (cur == NULL) return(NULL);
1901
1902 /*
1903 * add the new element at the end of the children list.
1904 */
1905 cur->type = XML_ELEMENT_NODE;
1906 cur->parent = parent;
1907 cur->doc = parent->doc;
1908 if (parent->children == NULL) {
1909 parent->children = cur;
1910 parent->last = cur;
1911 } else {
1912 prev = parent->last;
1913 prev->next = cur;
1914 cur->prev = prev;
1915 parent->last = cur;
1916 }
1917
1918 return(cur);
1919}
1920
1921/**
1922 * xmlAddNextSibling:
1923 * @cur: the child node
1924 * @elem: the new node
1925 *
1926 * Add a new element @elem as the next siblings of @cur
1927 * If the new element was already inserted in a document it is
1928 * first unlinked from its existing context.
1929 * As a result of text merging @elem may be freed.
1930 *
1931 * Returns the new element or NULL in case of error.
1932 */
1933xmlNodePtr
1934xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1935 if (cur == NULL) {
1936#ifdef DEBUG_TREE
1937 xmlGenericError(xmlGenericErrorContext,
1938 "xmlAddNextSibling : cur == NULL\n");
1939#endif
1940 return(NULL);
1941 }
1942 if (elem == NULL) {
1943#ifdef DEBUG_TREE
1944 xmlGenericError(xmlGenericErrorContext,
1945 "xmlAddNextSibling : elem == NULL\n");
1946#endif
1947 return(NULL);
1948 }
1949
1950 xmlUnlinkNode(elem);
1951
1952 if (elem->type == XML_TEXT_NODE) {
1953 if (cur->type == XML_TEXT_NODE) {
1954#ifndef XML_USE_BUFFER_CONTENT
1955 xmlNodeAddContent(cur, elem->content);
1956#else
1957 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1958#endif
1959 xmlFreeNode(elem);
1960 return(cur);
1961 }
1962 if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
1963#ifndef XML_USE_BUFFER_CONTENT
1964 xmlChar *tmp;
1965
1966 tmp = xmlStrdup(elem->content);
1967 tmp = xmlStrcat(tmp, cur->next->content);
1968 xmlNodeSetContent(cur->next, tmp);
1969 xmlFree(tmp);
1970#else
1971 xmlBufferAddHead(cur->next->content,
1972 xmlBufferContent(elem->content),
1973 xmlBufferLength(elem->content));
1974#endif
1975 xmlFreeNode(elem);
1976 return(cur->next);
1977 }
1978 }
1979
1980 if (elem->doc != cur->doc) {
1981 xmlSetTreeDoc(elem, cur->doc);
1982 }
1983 elem->parent = cur->parent;
1984 elem->prev = cur;
1985 elem->next = cur->next;
1986 cur->next = elem;
1987 if (elem->next != NULL)
1988 elem->next->prev = elem;
1989 if ((elem->parent != NULL) && (elem->parent->last == cur))
1990 elem->parent->last = elem;
1991 return(elem);
1992}
1993
1994/**
1995 * xmlAddPrevSibling:
1996 * @cur: the child node
1997 * @elem: the new node
1998 *
1999 * Add a new element @elem as the previous siblings of @cur
2000 * merging adjacent TEXT nodes (@elem may be freed)
2001 * If the new element was already inserted in a document it is
2002 * first unlinked from its existing context.
2003 *
2004 * Returns the new element or NULL in case of error.
2005 */
2006xmlNodePtr
2007xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2008 if (cur == NULL) {
2009#ifdef DEBUG_TREE
2010 xmlGenericError(xmlGenericErrorContext,
2011 "xmlAddPrevSibling : cur == NULL\n");
2012#endif
2013 return(NULL);
2014 }
2015 if (elem == NULL) {
2016#ifdef DEBUG_TREE
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlAddPrevSibling : elem == NULL\n");
2019#endif
2020 return(NULL);
2021 }
2022
2023 xmlUnlinkNode(elem);
2024
2025 if (elem->type == XML_TEXT_NODE) {
2026 if (cur->type == XML_TEXT_NODE) {
2027#ifndef XML_USE_BUFFER_CONTENT
2028 xmlChar *tmp;
2029
2030 tmp = xmlStrdup(elem->content);
2031 tmp = xmlStrcat(tmp, cur->content);
2032 xmlNodeSetContent(cur, tmp);
2033 xmlFree(tmp);
2034#else
2035 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2036 xmlBufferLength(elem->content));
2037#endif
2038 xmlFreeNode(elem);
2039 return(cur);
2040 }
2041 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
2042#ifndef XML_USE_BUFFER_CONTENT
2043 xmlNodeAddContent(cur->prev, elem->content);
2044#else
2045 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2046#endif
2047 xmlFreeNode(elem);
2048 return(cur->prev);
2049 }
2050 }
2051
2052 if (elem->doc != cur->doc) {
2053 xmlSetTreeDoc(elem, cur->doc);
2054 }
2055 elem->parent = cur->parent;
2056 elem->next = cur;
2057 elem->prev = cur->prev;
2058 cur->prev = elem;
2059 if (elem->prev != NULL)
2060 elem->prev->next = elem;
2061 if ((elem->parent != NULL) && (elem->parent->children == cur))
2062 elem->parent->children = elem;
2063 return(elem);
2064}
2065
2066/**
2067 * xmlAddSibling:
2068 * @cur: the child node
2069 * @elem: the new node
2070 *
2071 * Add a new element @elem to the list of siblings of @cur
2072 * merging adjacent TEXT nodes (@elem may be freed)
2073 * If the new element was already inserted in a document it is
2074 * first unlinked from its existing context.
2075 *
2076 * Returns the new element or NULL in case of error.
2077 */
2078xmlNodePtr
2079xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2080 xmlNodePtr parent;
2081
2082 if (cur == NULL) {
2083#ifdef DEBUG_TREE
2084 xmlGenericError(xmlGenericErrorContext,
2085 "xmlAddSibling : cur == NULL\n");
2086#endif
2087 return(NULL);
2088 }
2089
2090 if (elem == NULL) {
2091#ifdef DEBUG_TREE
2092 xmlGenericError(xmlGenericErrorContext,
2093 "xmlAddSibling : elem == NULL\n");
2094#endif
2095 return(NULL);
2096 }
2097
2098 /*
2099 * Constant time is we can rely on the ->parent->last to find
2100 * the last sibling.
2101 */
2102 if ((cur->parent != NULL) &&
2103 (cur->parent->children != NULL) &&
2104 (cur->parent->last != NULL) &&
2105 (cur->parent->last->next == NULL)) {
2106 cur = cur->parent->last;
2107 } else {
2108 while (cur->next != NULL) cur = cur->next;
2109 }
2110
2111 xmlUnlinkNode(elem);
2112
2113 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2114#ifndef XML_USE_BUFFER_CONTENT
2115 xmlNodeAddContent(cur, elem->content);
2116#else
2117 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2118#endif
2119 xmlFreeNode(elem);
2120 return(cur);
2121 }
2122
2123 if (elem->doc != cur->doc) {
2124 xmlSetTreeDoc(elem, cur->doc);
2125 }
2126 parent = cur->parent;
2127 elem->prev = cur;
2128 elem->next = NULL;
2129 elem->parent = parent;
2130 cur->next = elem;
2131 if (parent != NULL)
2132 parent->last = elem;
2133
2134 return(elem);
2135}
2136
2137/**
2138 * xmlAddChildList:
2139 * @parent: the parent node
2140 * @cur: the first node in the list
2141 *
2142 * Add a list of node at the end of the child list of the parent
2143 * merging adjacent TEXT nodes (@cur may be freed)
2144 *
2145 * Returns the last child or NULL in case of error.
2146 */
2147xmlNodePtr
2148xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2149 xmlNodePtr prev;
2150
2151 if (parent == NULL) {
2152#ifdef DEBUG_TREE
2153 xmlGenericError(xmlGenericErrorContext,
2154 "xmlAddChild : parent == NULL\n");
2155#endif
2156 return(NULL);
2157 }
2158
2159 if (cur == NULL) {
2160#ifdef DEBUG_TREE
2161 xmlGenericError(xmlGenericErrorContext,
2162 "xmlAddChild : child == NULL\n");
2163#endif
2164 return(NULL);
2165 }
2166
2167 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2168 (cur->doc != parent->doc)) {
2169#ifdef DEBUG_TREE
2170 xmlGenericError(xmlGenericErrorContext,
2171 "Elements moved to a different document\n");
2172#endif
2173 }
2174
2175 /*
2176 * add the first element at the end of the children list.
2177 */
2178 if (parent->children == NULL) {
2179 parent->children = cur;
2180 } else {
2181 /*
2182 * If cur and parent->last both are TEXT nodes, then merge them.
2183 */
2184 if ((cur->type == XML_TEXT_NODE) &&
2185 (parent->last->type == XML_TEXT_NODE) &&
2186 (cur->name == parent->last->name)) {
2187#ifndef XML_USE_BUFFER_CONTENT
2188 xmlNodeAddContent(parent->last, cur->content);
2189#else
2190 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2191#endif
2192 /*
2193 * if it's the only child, nothing more to be done.
2194 */
2195 if (cur->next == NULL) {
2196 xmlFreeNode(cur);
2197 return(parent->last);
2198 }
2199 prev = cur;
2200 cur = cur->next;
2201 xmlFreeNode(prev);
2202 }
2203 prev = parent->last;
2204 prev->next = cur;
2205 cur->prev = prev;
2206 }
2207 while (cur->next != NULL) {
2208 cur->parent = parent;
2209 if (cur->doc != parent->doc) {
2210 xmlSetTreeDoc(cur, parent->doc);
2211 }
2212 cur = cur->next;
2213 }
2214 cur->parent = parent;
2215 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2216 parent->last = cur;
2217
2218 return(cur);
2219}
2220
2221/**
2222 * xmlAddChild:
2223 * @parent: the parent node
2224 * @cur: the child node
2225 *
2226 * Add a new child element, to @parent, at the end of the child list
2227 * merging adjacent TEXT nodes (in which case @cur is freed)
2228 * Returns the child or NULL in case of error.
2229 */
2230xmlNodePtr
2231xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2232 xmlNodePtr prev;
2233
2234 if (parent == NULL) {
2235#ifdef DEBUG_TREE
2236 xmlGenericError(xmlGenericErrorContext,
2237 "xmlAddChild : parent == NULL\n");
2238#endif
2239 return(NULL);
2240 }
2241
2242 if (cur == NULL) {
2243#ifdef DEBUG_TREE
2244 xmlGenericError(xmlGenericErrorContext,
2245 "xmlAddChild : child == NULL\n");
2246#endif
2247 return(NULL);
2248 }
2249
Owen Taylor3473f882001-02-23 17:55:21 +00002250 /*
2251 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002252 * cur is then freed.
2253 */
2254 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002255 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002256 (parent->content != NULL)) {
2257#ifndef XML_USE_BUFFER_CONTENT
2258 xmlNodeAddContent(parent, cur->content);
2259#else
2260 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2261#endif
2262 xmlFreeNode(cur);
2263 return(parent);
2264 }
2265 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2266 (parent->last->name == cur->name)) {
2267#ifndef XML_USE_BUFFER_CONTENT
2268 xmlNodeAddContent(parent->last, cur->content);
2269#else
2270 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2271#endif
2272 xmlFreeNode(cur);
2273 return(parent->last);
2274 }
2275 }
2276
2277 /*
2278 * add the new element at the end of the children list.
2279 */
2280 cur->parent = parent;
2281 if (cur->doc != parent->doc) {
2282 xmlSetTreeDoc(cur, parent->doc);
2283 }
2284
2285 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002286 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002287 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002288 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002289 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002290#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002291 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002292#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002293 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002294#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002295 xmlFreeNode(cur);
2296 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002297 }
2298 if (parent->children == NULL) {
2299 parent->children = cur;
2300 parent->last = cur;
2301 } else {
2302 prev = parent->last;
2303 prev->next = cur;
2304 cur->prev = prev;
2305 parent->last = cur;
2306 }
2307
2308 return(cur);
2309}
2310
2311/**
2312 * xmlGetLastChild:
2313 * @parent: the parent node
2314 *
2315 * Search the last child of a node.
2316 * Returns the last child or NULL if none.
2317 */
2318xmlNodePtr
2319xmlGetLastChild(xmlNodePtr parent) {
2320 if (parent == NULL) {
2321#ifdef DEBUG_TREE
2322 xmlGenericError(xmlGenericErrorContext,
2323 "xmlGetLastChild : parent == NULL\n");
2324#endif
2325 return(NULL);
2326 }
2327 return(parent->last);
2328}
2329
2330/**
2331 * xmlFreeNodeList:
2332 * @cur: the first node in the list
2333 *
2334 * Free a node and all its siblings, this is a recursive behaviour, all
2335 * the children are freed too.
2336 */
2337void
2338xmlFreeNodeList(xmlNodePtr cur) {
2339 xmlNodePtr next;
2340 if (cur == NULL) {
2341#ifdef DEBUG_TREE
2342 xmlGenericError(xmlGenericErrorContext,
2343 "xmlFreeNodeList : node == NULL\n");
2344#endif
2345 return;
2346 }
2347 while (cur != NULL) {
2348 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002349 /* unroll to speed up freeing the document */
2350 if (cur->type != XML_DTD_NODE) {
2351 if ((cur->children != NULL) &&
2352 (cur->type != XML_ENTITY_REF_NODE))
2353 xmlFreeNodeList(cur->children);
2354 if (cur->properties != NULL)
2355 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002356 if ((cur->type != XML_ELEMENT_NODE) &&
2357 (cur->type != XML_XINCLUDE_START) &&
2358 (cur->type != XML_XINCLUDE_END) &&
2359 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002360#ifndef XML_USE_BUFFER_CONTENT
2361 if (cur->content != NULL) xmlFree(cur->content);
2362#else
2363 if (cur->content != NULL) xmlBufferFree(cur->content);
2364#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002365 }
2366 if (((cur->type == XML_ELEMENT_NODE) ||
2367 (cur->type == XML_XINCLUDE_START) ||
2368 (cur->type == XML_XINCLUDE_END)) &&
2369 (cur->nsDef != NULL))
2370 xmlFreeNsList(cur->nsDef);
2371
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002372 /*
2373 * When a node is a text node or a comment, it uses a global static
2374 * variable for the name of the node.
2375 *
2376 * The xmlStrEqual comparisons need to be done when (happened with
2377 * XML::libXML and XML::libXSLT) the library is included twice
2378 * statically in the binary and a tree allocated by one occurent
2379 * of the lib gets freed by the other occurence, in this case
2380 * the string addresses compare are not sufficient.
2381 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002382 if ((cur->name != NULL) &&
2383 (cur->name != xmlStringText) &&
2384 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002385 (cur->name != xmlStringComment)) {
2386 if (cur->type == XML_TEXT_NODE) {
2387 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2388 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2389 xmlFree((char *) cur->name);
2390 } else if (cur->type == XML_COMMENT_NODE) {
2391 if (!xmlStrEqual(cur->name, xmlStringComment))
2392 xmlFree((char *) cur->name);
2393 } else
2394 xmlFree((char *) cur->name);
2395 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002396 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002397 xmlFree(cur);
2398 }
Owen Taylor3473f882001-02-23 17:55:21 +00002399 cur = next;
2400 }
2401}
2402
2403/**
2404 * xmlFreeNode:
2405 * @cur: the node
2406 *
2407 * Free a node, this is a recursive behaviour, all the children are freed too.
2408 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2409 */
2410void
2411xmlFreeNode(xmlNodePtr cur) {
2412 if (cur == NULL) {
2413#ifdef DEBUG_TREE
2414 xmlGenericError(xmlGenericErrorContext,
2415 "xmlFreeNode : node == NULL\n");
2416#endif
2417 return;
2418 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002419 /* use xmlFreeDtd for DTD nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002420 if (cur->type == XML_DTD_NODE)
2421 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002422 if ((cur->children != NULL) &&
2423 (cur->type != XML_ENTITY_REF_NODE))
2424 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002425 if (cur->properties != NULL)
2426 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002427 if ((cur->type != XML_ELEMENT_NODE) &&
2428 (cur->content != NULL) &&
2429 (cur->type != XML_ENTITY_REF_NODE) &&
2430 (cur->type != XML_XINCLUDE_END) &&
2431 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002432#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002433 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002434#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002435 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002436#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002437 }
2438
Daniel Veillardacd370f2001-06-09 17:17:51 +00002439 /*
2440 * When a node is a text node or a comment, it uses a global static
2441 * variable for the name of the node.
2442 *
2443 * The xmlStrEqual comparisons need to be done when (happened with
2444 * XML::libXML and XML::libXSLT) the library is included twice statically
2445 * in the binary and a tree allocated by one occurent of the lib gets
2446 * freed by the other occurence, in this case the string addresses compare
2447 * are not sufficient.
2448 */
Owen Taylor3473f882001-02-23 17:55:21 +00002449 if ((cur->name != NULL) &&
2450 (cur->name != xmlStringText) &&
2451 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002452 (cur->name != xmlStringComment)) {
2453 if (cur->type == XML_TEXT_NODE) {
2454 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2455 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2456 xmlFree((char *) cur->name);
2457 } else if (cur->type == XML_COMMENT_NODE) {
2458 if (!xmlStrEqual(cur->name, xmlStringComment))
2459 xmlFree((char *) cur->name);
2460 } else
2461 xmlFree((char *) cur->name);
2462 }
2463
Owen Taylor3473f882001-02-23 17:55:21 +00002464 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002465 xmlFree(cur);
2466}
2467
2468/**
2469 * xmlUnlinkNode:
2470 * @cur: the node
2471 *
2472 * Unlink a node from it's current context, the node is not freed
2473 */
2474void
2475xmlUnlinkNode(xmlNodePtr cur) {
2476 if (cur == NULL) {
2477#ifdef DEBUG_TREE
2478 xmlGenericError(xmlGenericErrorContext,
2479 "xmlUnlinkNode : node == NULL\n");
2480#endif
2481 return;
2482 }
2483 if ((cur->parent != NULL) && (cur->parent->children == cur))
2484 cur->parent->children = cur->next;
2485 if ((cur->parent != NULL) && (cur->parent->last == cur))
2486 cur->parent->last = cur->prev;
2487 if (cur->next != NULL)
2488 cur->next->prev = cur->prev;
2489 if (cur->prev != NULL)
2490 cur->prev->next = cur->next;
2491 cur->next = cur->prev = NULL;
2492 cur->parent = NULL;
2493}
2494
2495/**
2496 * xmlReplaceNode:
2497 * @old: the old node
2498 * @cur: the node
2499 *
2500 * Unlink the old node from it's current context, prune the new one
2501 * at the same place. If cur was already inserted in a document it is
2502 * first unlinked from its existing context.
2503 *
2504 * Returns the old node
2505 */
2506xmlNodePtr
2507xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2508 if (old == NULL) {
2509#ifdef DEBUG_TREE
2510 xmlGenericError(xmlGenericErrorContext,
2511 "xmlReplaceNode : old == NULL\n");
2512#endif
2513 return(NULL);
2514 }
2515 if (cur == NULL) {
2516 xmlUnlinkNode(old);
2517 return(old);
2518 }
2519 if (cur == old) {
2520 return(old);
2521 }
2522 xmlUnlinkNode(cur);
2523 cur->doc = old->doc;
2524 cur->parent = old->parent;
2525 cur->next = old->next;
2526 if (cur->next != NULL)
2527 cur->next->prev = cur;
2528 cur->prev = old->prev;
2529 if (cur->prev != NULL)
2530 cur->prev->next = cur;
2531 if (cur->parent != NULL) {
2532 if (cur->parent->children == old)
2533 cur->parent->children = cur;
2534 if (cur->parent->last == old)
2535 cur->parent->last = cur;
2536 }
2537 old->next = old->prev = NULL;
2538 old->parent = NULL;
2539 return(old);
2540}
2541
2542/************************************************************************
2543 * *
2544 * Copy operations *
2545 * *
2546 ************************************************************************/
2547
2548/**
2549 * xmlCopyNamespace:
2550 * @cur: the namespace
2551 *
2552 * Do a copy of the namespace.
2553 *
2554 * Returns: a new xmlNsPtr, or NULL in case of error.
2555 */
2556xmlNsPtr
2557xmlCopyNamespace(xmlNsPtr cur) {
2558 xmlNsPtr ret;
2559
2560 if (cur == NULL) return(NULL);
2561 switch (cur->type) {
2562 case XML_LOCAL_NAMESPACE:
2563 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2564 break;
2565 default:
2566#ifdef DEBUG_TREE
2567 xmlGenericError(xmlGenericErrorContext,
2568 "xmlCopyNamespace: invalid type %d\n", cur->type);
2569#endif
2570 return(NULL);
2571 }
2572 return(ret);
2573}
2574
2575/**
2576 * xmlCopyNamespaceList:
2577 * @cur: the first namespace
2578 *
2579 * Do a copy of an namespace list.
2580 *
2581 * Returns: a new xmlNsPtr, or NULL in case of error.
2582 */
2583xmlNsPtr
2584xmlCopyNamespaceList(xmlNsPtr cur) {
2585 xmlNsPtr ret = NULL;
2586 xmlNsPtr p = NULL,q;
2587
2588 while (cur != NULL) {
2589 q = xmlCopyNamespace(cur);
2590 if (p == NULL) {
2591 ret = p = q;
2592 } else {
2593 p->next = q;
2594 p = q;
2595 }
2596 cur = cur->next;
2597 }
2598 return(ret);
2599}
2600
2601static xmlNodePtr
2602xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2603/**
2604 * xmlCopyProp:
2605 * @target: the element where the attribute will be grafted
2606 * @cur: the attribute
2607 *
2608 * Do a copy of the attribute.
2609 *
2610 * Returns: a new xmlAttrPtr, or NULL in case of error.
2611 */
2612xmlAttrPtr
2613xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2614 xmlAttrPtr ret;
2615
2616 if (cur == NULL) return(NULL);
2617 if (target != NULL)
2618 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2619 else if (cur->parent != NULL)
2620 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2621 else if (cur->children != NULL)
2622 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2623 else
2624 ret = xmlNewDocProp(NULL, cur->name, NULL);
2625 if (ret == NULL) return(NULL);
2626 ret->parent = target;
2627
2628 if ((cur->ns != NULL) && (target != NULL)) {
2629 xmlNsPtr ns;
2630
2631 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2632 ret->ns = ns;
2633 } else
2634 ret->ns = NULL;
2635
2636 if (cur->children != NULL) {
2637 xmlNodePtr tmp;
2638
2639 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2640 ret->last = NULL;
2641 tmp = ret->children;
2642 while (tmp != NULL) {
2643 /* tmp->parent = (xmlNodePtr)ret; */
2644 if (tmp->next == NULL)
2645 ret->last = tmp;
2646 tmp = tmp->next;
2647 }
2648 }
2649 return(ret);
2650}
2651
2652/**
2653 * xmlCopyPropList:
2654 * @target: the element where the attributes will be grafted
2655 * @cur: the first attribute
2656 *
2657 * Do a copy of an attribute list.
2658 *
2659 * Returns: a new xmlAttrPtr, or NULL in case of error.
2660 */
2661xmlAttrPtr
2662xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2663 xmlAttrPtr ret = NULL;
2664 xmlAttrPtr p = NULL,q;
2665
2666 while (cur != NULL) {
2667 q = xmlCopyProp(target, cur);
2668 if (p == NULL) {
2669 ret = p = q;
2670 } else {
2671 p->next = q;
2672 q->prev = p;
2673 p = q;
2674 }
2675 cur = cur->next;
2676 }
2677 return(ret);
2678}
2679
2680/*
2681 * NOTE abeut the CopyNode operations !
2682 *
2683 * They are splitted into external and internal parts for one
2684 * tricky reason: namespaces. Doing a direct copy of a node
2685 * say RPM:Copyright without changing the namespace pointer to
2686 * something else can produce stale links. One way to do it is
2687 * to keep a reference counter but this doesn't work as soon
2688 * as one move the element or the subtree out of the scope of
2689 * the existing namespace. The actual solution seems to add
2690 * a copy of the namespace at the top of the copied tree if
2691 * not available in the subtree.
2692 * Hence two functions, the public front-end call the inner ones
2693 */
2694
2695static xmlNodePtr
2696xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2697
2698static xmlNodePtr
2699xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2700 int recursive) {
2701 xmlNodePtr ret;
2702
2703 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002704 switch (node->type) {
2705 case XML_TEXT_NODE:
2706 case XML_CDATA_SECTION_NODE:
2707 case XML_ELEMENT_NODE:
2708 case XML_ENTITY_REF_NODE:
2709 case XML_ENTITY_NODE:
2710 case XML_PI_NODE:
2711 case XML_COMMENT_NODE:
2712 case XML_DOCUMENT_NODE:
2713 case XML_HTML_DOCUMENT_NODE:
2714#ifdef LIBXML_DOCB_ENABLED
2715 case XML_DOCB_DOCUMENT_NODE:
2716#endif
2717 case XML_XINCLUDE_START:
2718 case XML_XINCLUDE_END:
2719 break;
2720 case XML_ATTRIBUTE_NODE:
2721 return((xmlNodePtr)
2722 xmlCopyProp(parent, (xmlAttrPtr) node));
2723 case XML_NAMESPACE_DECL:
2724 return((xmlNodePtr)
2725 xmlCopyNamespaceList((xmlNsPtr) node));
2726
2727 case XML_DOCUMENT_TYPE_NODE:
2728 case XML_DOCUMENT_FRAG_NODE:
2729 case XML_NOTATION_NODE:
2730 case XML_DTD_NODE:
2731 case XML_ELEMENT_DECL:
2732 case XML_ATTRIBUTE_DECL:
2733 case XML_ENTITY_DECL:
2734 return(NULL);
2735 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002736
Owen Taylor3473f882001-02-23 17:55:21 +00002737 /*
2738 * Allocate a new node and fill the fields.
2739 */
2740 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2741 if (ret == NULL) {
2742 xmlGenericError(xmlGenericErrorContext,
2743 "xmlStaticCopyNode : malloc failed\n");
2744 return(NULL);
2745 }
2746 memset(ret, 0, sizeof(xmlNode));
2747 ret->type = node->type;
2748
2749 ret->doc = doc;
2750 ret->parent = parent;
2751 if (node->name == xmlStringText)
2752 ret->name = xmlStringText;
2753 else if (node->name == xmlStringTextNoenc)
2754 ret->name = xmlStringTextNoenc;
2755 else if (node->name == xmlStringComment)
2756 ret->name = xmlStringComment;
2757 else if (node->name != NULL)
2758 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002759 if ((node->type != XML_ELEMENT_NODE) &&
2760 (node->content != NULL) &&
2761 (node->type != XML_ENTITY_REF_NODE) &&
2762 (node->type != XML_XINCLUDE_END) &&
2763 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002764#ifndef XML_USE_BUFFER_CONTENT
2765 ret->content = xmlStrdup(node->content);
2766#else
2767 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2768 xmlBufferSetAllocationScheme(ret->content,
2769 xmlGetBufferAllocationScheme());
2770 xmlBufferAdd(ret->content,
2771 xmlBufferContent(node->content),
2772 xmlBufferLength(node->content));
2773#endif
2774 }
2775 if (parent != NULL)
2776 xmlAddChild(parent, ret);
2777
2778 if (!recursive) return(ret);
2779 if (node->nsDef != NULL)
2780 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2781
2782 if (node->ns != NULL) {
2783 xmlNsPtr ns;
2784
2785 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2786 if (ns == NULL) {
2787 /*
2788 * Humm, we are copying an element whose namespace is defined
2789 * out of the new tree scope. Search it in the original tree
2790 * and add it at the top of the new tree
2791 */
2792 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2793 if (ns != NULL) {
2794 xmlNodePtr root = ret;
2795
2796 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002797 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002798 }
2799 } else {
2800 /*
2801 * reference the existing namespace definition in our own tree.
2802 */
2803 ret->ns = ns;
2804 }
2805 }
2806 if (node->properties != NULL)
2807 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002808 if (node->type == XML_ENTITY_REF_NODE) {
2809 if ((doc == NULL) || (node->doc != doc)) {
2810 /*
2811 * The copied node will go into a separate document, so
2812 * to havoid dandling references to the ENTITY_DECL node
2813 * we cannot keep the reference. Try to find it in the
2814 * target document.
2815 */
2816 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2817 } else {
2818 ret->children = node->children;
2819 }
2820 } else if (node->children != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002821 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
2822 UPDATE_LAST_CHILD_AND_PARENT(ret)
2823 return(ret);
2824}
2825
2826static xmlNodePtr
2827xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2828 xmlNodePtr ret = NULL;
2829 xmlNodePtr p = NULL,q;
2830
2831 while (node != NULL) {
Daniel Veillardb33c2012001-04-25 12:59:04 +00002832 if( node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002833 if (doc == NULL) {
2834 node = node->next;
2835 continue;
2836 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002837 if (doc->intSubset == NULL) {
2838 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2839 q->doc = doc;
2840 q->parent = parent;
2841 doc->intSubset = (xmlDtdPtr) q;
2842 } else {
2843 q = (xmlNodePtr) doc->intSubset;
2844 }
2845 } else
2846 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002847 if (ret == NULL) {
2848 q->prev = NULL;
2849 ret = p = q;
2850 } else {
2851 p->next = q;
2852 q->prev = p;
2853 p = q;
2854 }
2855 node = node->next;
2856 }
2857 return(ret);
2858}
2859
2860/**
2861 * xmlCopyNode:
2862 * @node: the node
2863 * @recursive: if 1 do a recursive copy.
2864 *
2865 * Do a copy of the node.
2866 *
2867 * Returns: a new xmlNodePtr, or NULL in case of error.
2868 */
2869xmlNodePtr
2870xmlCopyNode(xmlNodePtr node, int recursive) {
2871 xmlNodePtr ret;
2872
2873 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2874 return(ret);
2875}
2876
2877/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002878 * xmlDocCopyNode:
2879 * @node: the node
2880 * @recursive: if 1 do a recursive copy.
2881 *
2882 * Do a copy of the node to a given document.
2883 *
2884 * Returns: a new xmlNodePtr, or NULL in case of error.
2885 */
2886xmlNodePtr
2887xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int recursive) {
2888 xmlNodePtr ret;
2889
2890 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2891 return(ret);
2892}
2893
2894/**
Owen Taylor3473f882001-02-23 17:55:21 +00002895 * xmlCopyNodeList:
2896 * @node: the first node in the list.
2897 *
2898 * Do a recursive copy of the node list.
2899 *
2900 * Returns: a new xmlNodePtr, or NULL in case of error.
2901 */
2902xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2903 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2904 return(ret);
2905}
2906
2907/**
Owen Taylor3473f882001-02-23 17:55:21 +00002908 * xmlCopyDtd:
2909 * @dtd: the dtd
2910 *
2911 * Do a copy of the dtd.
2912 *
2913 * Returns: a new xmlDtdPtr, or NULL in case of error.
2914 */
2915xmlDtdPtr
2916xmlCopyDtd(xmlDtdPtr dtd) {
2917 xmlDtdPtr ret;
2918
2919 if (dtd == NULL) return(NULL);
2920 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2921 if (ret == NULL) return(NULL);
2922 if (dtd->entities != NULL)
2923 ret->entities = (void *) xmlCopyEntitiesTable(
2924 (xmlEntitiesTablePtr) dtd->entities);
2925 if (dtd->notations != NULL)
2926 ret->notations = (void *) xmlCopyNotationTable(
2927 (xmlNotationTablePtr) dtd->notations);
2928 if (dtd->elements != NULL)
2929 ret->elements = (void *) xmlCopyElementTable(
2930 (xmlElementTablePtr) dtd->elements);
2931 if (dtd->attributes != NULL)
2932 ret->attributes = (void *) xmlCopyAttributeTable(
2933 (xmlAttributeTablePtr) dtd->attributes);
2934 return(ret);
2935}
2936
2937/**
2938 * xmlCopyDoc:
2939 * @doc: the document
2940 * @recursive: if 1 do a recursive copy.
2941 *
2942 * Do a copy of the document info. If recursive, the content tree will
2943 * be copied too as well as Dtd, namespaces and entities.
2944 *
2945 * Returns: a new xmlDocPtr, or NULL in case of error.
2946 */
2947xmlDocPtr
2948xmlCopyDoc(xmlDocPtr doc, int recursive) {
2949 xmlDocPtr ret;
2950
2951 if (doc == NULL) return(NULL);
2952 ret = xmlNewDoc(doc->version);
2953 if (ret == NULL) return(NULL);
2954 if (doc->name != NULL)
2955 ret->name = xmlMemStrdup(doc->name);
2956 if (doc->encoding != NULL)
2957 ret->encoding = xmlStrdup(doc->encoding);
2958 ret->charset = doc->charset;
2959 ret->compression = doc->compression;
2960 ret->standalone = doc->standalone;
2961 if (!recursive) return(ret);
2962
Daniel Veillardb33c2012001-04-25 12:59:04 +00002963 ret->last = NULL;
2964 ret->children = NULL;
2965 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002966 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002967 ret->intSubset->doc = ret;
2968 ret->intSubset->parent = ret;
2969 }
Owen Taylor3473f882001-02-23 17:55:21 +00002970 if (doc->oldNs != NULL)
2971 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2972 if (doc->children != NULL) {
2973 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002974
2975 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2976 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002977 ret->last = NULL;
2978 tmp = ret->children;
2979 while (tmp != NULL) {
2980 if (tmp->next == NULL)
2981 ret->last = tmp;
2982 tmp = tmp->next;
2983 }
2984 }
2985 return(ret);
2986}
2987
2988/************************************************************************
2989 * *
2990 * Content access functions *
2991 * *
2992 ************************************************************************/
2993
2994/**
2995 * xmlDocGetRootElement:
2996 * @doc: the document
2997 *
2998 * Get the root element of the document (doc->children is a list
2999 * containing possibly comments, PIs, etc ...).
3000 *
3001 * Returns the xmlNodePtr for the root or NULL
3002 */
3003xmlNodePtr
3004xmlDocGetRootElement(xmlDocPtr doc) {
3005 xmlNodePtr ret;
3006
3007 if (doc == NULL) return(NULL);
3008 ret = doc->children;
3009 while (ret != NULL) {
3010 if (ret->type == XML_ELEMENT_NODE)
3011 return(ret);
3012 ret = ret->next;
3013 }
3014 return(ret);
3015}
3016
3017/**
3018 * xmlDocSetRootElement:
3019 * @doc: the document
3020 * @root: the new document root element
3021 *
3022 * Set the root element of the document (doc->children is a list
3023 * containing possibly comments, PIs, etc ...).
3024 *
3025 * Returns the old root element if any was found
3026 */
3027xmlNodePtr
3028xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3029 xmlNodePtr old = NULL;
3030
3031 if (doc == NULL) return(NULL);
3032 old = doc->children;
3033 while (old != NULL) {
3034 if (old->type == XML_ELEMENT_NODE)
3035 break;
3036 old = old->next;
3037 }
3038 if (old == NULL) {
3039 if (doc->children == NULL) {
3040 doc->children = root;
3041 doc->last = root;
3042 } else {
3043 xmlAddSibling(doc->children, root);
3044 }
3045 } else {
3046 xmlReplaceNode(old, root);
3047 }
3048 return(old);
3049}
3050
3051/**
3052 * xmlNodeSetLang:
3053 * @cur: the node being changed
3054 * @lang: the langage description
3055 *
3056 * Set the language of a node, i.e. the values of the xml:lang
3057 * attribute.
3058 */
3059void
3060xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3061 if (cur == NULL) return;
3062 switch(cur->type) {
3063 case XML_TEXT_NODE:
3064 case XML_CDATA_SECTION_NODE:
3065 case XML_COMMENT_NODE:
3066 case XML_DOCUMENT_NODE:
3067 case XML_DOCUMENT_TYPE_NODE:
3068 case XML_DOCUMENT_FRAG_NODE:
3069 case XML_NOTATION_NODE:
3070 case XML_HTML_DOCUMENT_NODE:
3071 case XML_DTD_NODE:
3072 case XML_ELEMENT_DECL:
3073 case XML_ATTRIBUTE_DECL:
3074 case XML_ENTITY_DECL:
3075 case XML_PI_NODE:
3076 case XML_ENTITY_REF_NODE:
3077 case XML_ENTITY_NODE:
3078 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003079#ifdef LIBXML_DOCB_ENABLED
3080 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003081#endif
3082 case XML_XINCLUDE_START:
3083 case XML_XINCLUDE_END:
3084 return;
3085 case XML_ELEMENT_NODE:
3086 case XML_ATTRIBUTE_NODE:
3087 break;
3088 }
3089 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3090}
3091
3092/**
3093 * xmlNodeGetLang:
3094 * @cur: the node being checked
3095 *
3096 * Searches the language of a node, i.e. the values of the xml:lang
3097 * attribute or the one carried by the nearest ancestor.
3098 *
3099 * Returns a pointer to the lang value, or NULL if not found
3100 * It's up to the caller to free the memory.
3101 */
3102xmlChar *
3103xmlNodeGetLang(xmlNodePtr cur) {
3104 xmlChar *lang;
3105
3106 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003107 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003108 if (lang != NULL)
3109 return(lang);
3110 cur = cur->parent;
3111 }
3112 return(NULL);
3113}
3114
3115
3116/**
3117 * xmlNodeSetSpacePreserve:
3118 * @cur: the node being changed
3119 * @val: the xml:space value ("0": default, 1: "preserve")
3120 *
3121 * Set (or reset) the space preserving behaviour of a node, i.e. the
3122 * value of the xml:space attribute.
3123 */
3124void
3125xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3126 if (cur == NULL) return;
3127 switch(cur->type) {
3128 case XML_TEXT_NODE:
3129 case XML_CDATA_SECTION_NODE:
3130 case XML_COMMENT_NODE:
3131 case XML_DOCUMENT_NODE:
3132 case XML_DOCUMENT_TYPE_NODE:
3133 case XML_DOCUMENT_FRAG_NODE:
3134 case XML_NOTATION_NODE:
3135 case XML_HTML_DOCUMENT_NODE:
3136 case XML_DTD_NODE:
3137 case XML_ELEMENT_DECL:
3138 case XML_ATTRIBUTE_DECL:
3139 case XML_ENTITY_DECL:
3140 case XML_PI_NODE:
3141 case XML_ENTITY_REF_NODE:
3142 case XML_ENTITY_NODE:
3143 case XML_NAMESPACE_DECL:
3144 case XML_XINCLUDE_START:
3145 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003146#ifdef LIBXML_DOCB_ENABLED
3147 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003148#endif
3149 return;
3150 case XML_ELEMENT_NODE:
3151 case XML_ATTRIBUTE_NODE:
3152 break;
3153 }
3154 switch (val) {
3155 case 0:
3156 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3157 break;
3158 case 1:
3159 xmlSetProp(cur, BAD_CAST "xml:space",
3160 BAD_CAST "preserve");
3161 break;
3162 }
3163}
3164
3165/**
3166 * xmlNodeGetSpacePreserve:
3167 * @cur: the node being checked
3168 *
3169 * Searches the space preserving behaviour of a node, i.e. the values
3170 * of the xml:space attribute or the one carried by the nearest
3171 * ancestor.
3172 *
3173 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
3174 */
3175int
3176xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3177 xmlChar *space;
3178
3179 while (cur != NULL) {
3180 space = xmlGetProp(cur, BAD_CAST "xml:space");
3181 if (space != NULL) {
3182 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3183 xmlFree(space);
3184 return(1);
3185 }
3186 if (xmlStrEqual(space, BAD_CAST "default")) {
3187 xmlFree(space);
3188 return(0);
3189 }
3190 xmlFree(space);
3191 }
3192 cur = cur->parent;
3193 }
3194 return(-1);
3195}
3196
3197/**
3198 * xmlNodeSetName:
3199 * @cur: the node being changed
3200 * @name: the new tag name
3201 *
3202 * Set (or reset) the name of a node.
3203 */
3204void
3205xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3206 if (cur == NULL) return;
3207 if (name == NULL) return;
3208 switch(cur->type) {
3209 case XML_TEXT_NODE:
3210 case XML_CDATA_SECTION_NODE:
3211 case XML_COMMENT_NODE:
3212 case XML_DOCUMENT_TYPE_NODE:
3213 case XML_DOCUMENT_FRAG_NODE:
3214 case XML_NOTATION_NODE:
3215 case XML_HTML_DOCUMENT_NODE:
3216 case XML_NAMESPACE_DECL:
3217 case XML_XINCLUDE_START:
3218 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003219#ifdef LIBXML_DOCB_ENABLED
3220 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003221#endif
3222 return;
3223 case XML_ELEMENT_NODE:
3224 case XML_ATTRIBUTE_NODE:
3225 case XML_PI_NODE:
3226 case XML_ENTITY_REF_NODE:
3227 case XML_ENTITY_NODE:
3228 case XML_DTD_NODE:
3229 case XML_DOCUMENT_NODE:
3230 case XML_ELEMENT_DECL:
3231 case XML_ATTRIBUTE_DECL:
3232 case XML_ENTITY_DECL:
3233 break;
3234 }
3235 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3236 cur->name = xmlStrdup(name);
3237}
3238
3239/**
3240 * xmlNodeSetBase:
3241 * @cur: the node being changed
3242 * @uri: the new base URI
3243 *
3244 * Set (or reset) the base URI of a node, i.e. the value of the
3245 * xml:base attribute.
3246 */
3247void
3248xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3249 if (cur == NULL) return;
3250 switch(cur->type) {
3251 case XML_TEXT_NODE:
3252 case XML_CDATA_SECTION_NODE:
3253 case XML_COMMENT_NODE:
3254 case XML_DOCUMENT_NODE:
3255 case XML_DOCUMENT_TYPE_NODE:
3256 case XML_DOCUMENT_FRAG_NODE:
3257 case XML_NOTATION_NODE:
3258 case XML_HTML_DOCUMENT_NODE:
3259 case XML_DTD_NODE:
3260 case XML_ELEMENT_DECL:
3261 case XML_ATTRIBUTE_DECL:
3262 case XML_ENTITY_DECL:
3263 case XML_PI_NODE:
3264 case XML_ENTITY_REF_NODE:
3265 case XML_ENTITY_NODE:
3266 case XML_NAMESPACE_DECL:
3267 case XML_XINCLUDE_START:
3268 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003269#ifdef LIBXML_DOCB_ENABLED
3270 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003271#endif
3272 return;
3273 case XML_ELEMENT_NODE:
3274 case XML_ATTRIBUTE_NODE:
3275 break;
3276 }
3277 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3278}
3279
3280/**
Owen Taylor3473f882001-02-23 17:55:21 +00003281 * xmlNodeGetBase:
3282 * @doc: the document the node pertains to
3283 * @cur: the node being checked
3284 *
3285 * Searches for the BASE URL. The code should work on both XML
3286 * and HTML document even if base mechanisms are completely different.
3287 * It returns the base as defined in RFC 2396 sections
3288 * 5.1.1. Base URI within Document Content
3289 * and
3290 * 5.1.2. Base URI from the Encapsulating Entity
3291 * However it does not return the document base (5.1.3), use
3292 * xmlDocumentGetBase() for this
3293 *
3294 * Returns a pointer to the base URL, or NULL if not found
3295 * It's up to the caller to free the memory.
3296 */
3297xmlChar *
3298xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003299 xmlChar *oldbase = NULL;
3300 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003301
3302 if ((cur == NULL) && (doc == NULL))
3303 return(NULL);
3304 if (doc == NULL) doc = cur->doc;
3305 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3306 cur = doc->children;
3307 while ((cur != NULL) && (cur->name != NULL)) {
3308 if (cur->type != XML_ELEMENT_NODE) {
3309 cur = cur->next;
3310 continue;
3311 }
3312 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3313 cur = cur->children;
3314 continue;
3315 }
3316 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3317 cur = cur->children;
3318 continue;
3319 }
3320 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3321 return(xmlGetProp(cur, BAD_CAST "href"));
3322 }
3323 cur = cur->next;
3324 }
3325 return(NULL);
3326 }
3327 while (cur != NULL) {
3328 if (cur->type == XML_ENTITY_DECL) {
3329 xmlEntityPtr ent = (xmlEntityPtr) cur;
3330 return(xmlStrdup(ent->URI));
3331 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003332 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003333 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003334 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003335 if (oldbase != NULL) {
3336 newbase = xmlBuildURI(oldbase, base);
3337 if (newbase != NULL) {
3338 xmlFree(oldbase);
3339 xmlFree(base);
3340 oldbase = newbase;
3341 } else {
3342 xmlFree(oldbase);
3343 xmlFree(base);
3344 return(NULL);
3345 }
3346 } else {
3347 oldbase = base;
3348 }
3349 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3350 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3351 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3352 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003353 }
3354 }
Owen Taylor3473f882001-02-23 17:55:21 +00003355 cur = cur->parent;
3356 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003357 if ((doc != NULL) && (doc->URL != NULL)) {
3358 if (oldbase == NULL)
3359 return(xmlStrdup(doc->URL));
3360 newbase = xmlBuildURI(oldbase, doc->URL);
3361 xmlFree(oldbase);
3362 return(newbase);
3363 }
3364 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003365}
3366
3367/**
3368 * xmlNodeGetContent:
3369 * @cur: the node being read
3370 *
3371 * Read the value of a node, this can be either the text carried
3372 * directly by this node if it's a TEXT node or the aggregate string
3373 * of the values carried by this node child's (TEXT and ENTITY_REF).
3374 * Entity references are substitued.
3375 * Returns a new xmlChar * or NULL if no content is available.
3376 * It's up to the caller to free the memory.
3377 */
3378xmlChar *
3379xmlNodeGetContent(xmlNodePtr cur) {
3380 if (cur == NULL) return(NULL);
3381 switch (cur->type) {
3382 case XML_DOCUMENT_FRAG_NODE:
3383 case XML_ELEMENT_NODE: {
3384 xmlNodePtr tmp = cur;
3385 xmlBufferPtr buffer;
3386 xmlChar *ret;
3387
3388 buffer = xmlBufferCreate();
3389 if (buffer == NULL)
3390 return(NULL);
3391 while (tmp != NULL) {
3392 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003393 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003394 case XML_TEXT_NODE:
3395 if (tmp->content != NULL)
3396#ifndef XML_USE_BUFFER_CONTENT
3397 xmlBufferCat(buffer, tmp->content);
3398#else
3399 xmlBufferCat(buffer,
3400 xmlBufferContent(tmp->content));
3401#endif
3402 break;
3403 case XML_ENTITY_REF_NODE: {
3404 xmlEntityPtr ent;
3405
3406 ent = xmlGetDocEntity(cur->doc, tmp->name);
3407 if (ent != NULL)
3408 xmlBufferCat(buffer, ent->content);
3409 }
3410 default:
3411 break;
3412 }
3413 /*
3414 * Skip to next node
3415 */
3416 if (tmp->children != NULL) {
3417 if (tmp->children->type != XML_ENTITY_DECL) {
3418 tmp = tmp->children;
3419 continue;
3420 }
3421 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003422 if (tmp == cur)
3423 break;
3424
Owen Taylor3473f882001-02-23 17:55:21 +00003425 if (tmp->next != NULL) {
3426 tmp = tmp->next;
3427 continue;
3428 }
3429
3430 do {
3431 tmp = tmp->parent;
3432 if (tmp == NULL)
3433 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003434 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003435 tmp = NULL;
3436 break;
3437 }
3438 if (tmp->next != NULL) {
3439 tmp = tmp->next;
3440 break;
3441 }
3442 } while (tmp != NULL);
3443 }
3444 ret = buffer->content;
3445 buffer->content = NULL;
3446 xmlBufferFree(buffer);
3447 return(ret);
3448 }
3449 case XML_ATTRIBUTE_NODE: {
3450 xmlAttrPtr attr = (xmlAttrPtr) cur;
3451 if (attr->parent != NULL)
3452 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3453 else
3454 return(xmlNodeListGetString(NULL, attr->children, 1));
3455 break;
3456 }
3457 case XML_COMMENT_NODE:
3458 case XML_PI_NODE:
3459 if (cur->content != NULL)
3460#ifndef XML_USE_BUFFER_CONTENT
3461 return(xmlStrdup(cur->content));
3462#else
3463 return(xmlStrdup(xmlBufferContent(cur->content)));
3464#endif
3465 return(NULL);
3466 case XML_ENTITY_REF_NODE:
3467 /*
3468 * Locate the entity, and get it's content
3469 * @@@
3470 */
3471 return(NULL);
3472 case XML_ENTITY_NODE:
3473 case XML_DOCUMENT_NODE:
3474 case XML_HTML_DOCUMENT_NODE:
3475 case XML_DOCUMENT_TYPE_NODE:
3476 case XML_NOTATION_NODE:
3477 case XML_DTD_NODE:
3478 case XML_XINCLUDE_START:
3479 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003480#ifdef LIBXML_DOCB_ENABLED
3481 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003482#endif
3483 return(NULL);
3484 case XML_NAMESPACE_DECL:
3485 return(xmlStrdup(((xmlNsPtr)cur)->href));
3486 case XML_ELEMENT_DECL:
3487 /* TODO !!! */
3488 return(NULL);
3489 case XML_ATTRIBUTE_DECL:
3490 /* TODO !!! */
3491 return(NULL);
3492 case XML_ENTITY_DECL:
3493 /* TODO !!! */
3494 return(NULL);
3495 case XML_CDATA_SECTION_NODE:
3496 case XML_TEXT_NODE:
3497 if (cur->content != NULL)
3498#ifndef XML_USE_BUFFER_CONTENT
3499 return(xmlStrdup(cur->content));
3500#else
3501 return(xmlStrdup(xmlBufferContent(cur->content)));
3502#endif
3503 return(NULL);
3504 }
3505 return(NULL);
3506}
3507
3508/**
3509 * xmlNodeSetContent:
3510 * @cur: the node being modified
3511 * @content: the new value of the content
3512 *
3513 * Replace the content of a node.
3514 */
3515void
3516xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3517 if (cur == NULL) {
3518#ifdef DEBUG_TREE
3519 xmlGenericError(xmlGenericErrorContext,
3520 "xmlNodeSetContent : node == NULL\n");
3521#endif
3522 return;
3523 }
3524 switch (cur->type) {
3525 case XML_DOCUMENT_FRAG_NODE:
3526 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003527 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3528 cur->children = xmlStringGetNodeList(cur->doc, content);
3529 UPDATE_LAST_CHILD_AND_PARENT(cur)
3530 break;
3531 case XML_ATTRIBUTE_NODE:
3532 break;
3533 case XML_TEXT_NODE:
3534 case XML_CDATA_SECTION_NODE:
3535 case XML_ENTITY_REF_NODE:
3536 case XML_ENTITY_NODE:
3537 case XML_PI_NODE:
3538 case XML_COMMENT_NODE:
3539 if (cur->content != NULL) {
3540#ifndef XML_USE_BUFFER_CONTENT
3541 xmlFree(cur->content);
3542#else
3543 xmlBufferFree(cur->content);
3544#endif
3545 }
3546 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3547 cur->last = cur->children = NULL;
3548 if (content != NULL) {
3549#ifndef XML_USE_BUFFER_CONTENT
3550 cur->content = xmlStrdup(content);
3551#else
3552 cur->content = xmlBufferCreateSize(0);
3553 xmlBufferSetAllocationScheme(cur->content,
3554 xmlGetBufferAllocationScheme());
3555 xmlBufferAdd(cur->content, content, -1);
3556#endif
3557 } else
3558 cur->content = NULL;
3559 break;
3560 case XML_DOCUMENT_NODE:
3561 case XML_HTML_DOCUMENT_NODE:
3562 case XML_DOCUMENT_TYPE_NODE:
3563 case XML_XINCLUDE_START:
3564 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003565#ifdef LIBXML_DOCB_ENABLED
3566 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003567#endif
3568 break;
3569 case XML_NOTATION_NODE:
3570 break;
3571 case XML_DTD_NODE:
3572 break;
3573 case XML_NAMESPACE_DECL:
3574 break;
3575 case XML_ELEMENT_DECL:
3576 /* TODO !!! */
3577 break;
3578 case XML_ATTRIBUTE_DECL:
3579 /* TODO !!! */
3580 break;
3581 case XML_ENTITY_DECL:
3582 /* TODO !!! */
3583 break;
3584 }
3585}
3586
3587/**
3588 * xmlNodeSetContentLen:
3589 * @cur: the node being modified
3590 * @content: the new value of the content
3591 * @len: the size of @content
3592 *
3593 * Replace the content of a node.
3594 */
3595void
3596xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3597 if (cur == NULL) {
3598#ifdef DEBUG_TREE
3599 xmlGenericError(xmlGenericErrorContext,
3600 "xmlNodeSetContentLen : node == NULL\n");
3601#endif
3602 return;
3603 }
3604 switch (cur->type) {
3605 case XML_DOCUMENT_FRAG_NODE:
3606 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003607 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3608 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3609 UPDATE_LAST_CHILD_AND_PARENT(cur)
3610 break;
3611 case XML_ATTRIBUTE_NODE:
3612 break;
3613 case XML_TEXT_NODE:
3614 case XML_CDATA_SECTION_NODE:
3615 case XML_ENTITY_REF_NODE:
3616 case XML_ENTITY_NODE:
3617 case XML_PI_NODE:
3618 case XML_COMMENT_NODE:
3619 case XML_NOTATION_NODE:
3620 if (cur->content != NULL) {
3621#ifndef XML_USE_BUFFER_CONTENT
3622 xmlFree(cur->content);
3623#else
3624 xmlBufferFree(cur->content);
3625#endif
3626 }
3627 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3628 cur->children = cur->last = NULL;
3629 if (content != NULL) {
3630#ifndef XML_USE_BUFFER_CONTENT
3631 cur->content = xmlStrndup(content, len);
3632#else
3633 cur->content = xmlBufferCreateSize(len);
3634 xmlBufferSetAllocationScheme(cur->content,
3635 xmlGetBufferAllocationScheme());
3636 xmlBufferAdd(cur->content, content, len);
3637#endif
3638 } else
3639 cur->content = NULL;
3640 break;
3641 case XML_DOCUMENT_NODE:
3642 case XML_DTD_NODE:
3643 case XML_HTML_DOCUMENT_NODE:
3644 case XML_DOCUMENT_TYPE_NODE:
3645 case XML_NAMESPACE_DECL:
3646 case XML_XINCLUDE_START:
3647 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003648#ifdef LIBXML_DOCB_ENABLED
3649 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003650#endif
3651 break;
3652 case XML_ELEMENT_DECL:
3653 /* TODO !!! */
3654 break;
3655 case XML_ATTRIBUTE_DECL:
3656 /* TODO !!! */
3657 break;
3658 case XML_ENTITY_DECL:
3659 /* TODO !!! */
3660 break;
3661 }
3662}
3663
3664/**
3665 * xmlNodeAddContentLen:
3666 * @cur: the node being modified
3667 * @content: extra content
3668 * @len: the size of @content
3669 *
3670 * Append the extra substring to the node content.
3671 */
3672void
3673xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3674 if (cur == NULL) {
3675#ifdef DEBUG_TREE
3676 xmlGenericError(xmlGenericErrorContext,
3677 "xmlNodeAddContentLen : node == NULL\n");
3678#endif
3679 return;
3680 }
3681 if (len <= 0) return;
3682 switch (cur->type) {
3683 case XML_DOCUMENT_FRAG_NODE:
3684 case XML_ELEMENT_NODE: {
Daniel Veillard7db37732001-07-12 01:20:08 +00003685 xmlNodePtr last, newNode;
Owen Taylor3473f882001-02-23 17:55:21 +00003686
Daniel Veillard7db37732001-07-12 01:20:08 +00003687 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003688 newNode = xmlNewTextLen(content, len);
3689 if (newNode != NULL) {
3690 xmlAddChild(cur, newNode);
3691 if ((last != NULL) && (last->next == newNode)) {
3692 xmlTextMerge(last, newNode);
3693 }
3694 }
3695 break;
3696 }
3697 case XML_ATTRIBUTE_NODE:
3698 break;
3699 case XML_TEXT_NODE:
3700 case XML_CDATA_SECTION_NODE:
3701 case XML_ENTITY_REF_NODE:
3702 case XML_ENTITY_NODE:
3703 case XML_PI_NODE:
3704 case XML_COMMENT_NODE:
3705 case XML_NOTATION_NODE:
3706 if (content != NULL) {
3707#ifndef XML_USE_BUFFER_CONTENT
3708 cur->content = xmlStrncat(cur->content, content, len);
3709#else
3710 xmlBufferAdd(cur->content, content, len);
3711#endif
3712 }
3713 case XML_DOCUMENT_NODE:
3714 case XML_DTD_NODE:
3715 case XML_HTML_DOCUMENT_NODE:
3716 case XML_DOCUMENT_TYPE_NODE:
3717 case XML_NAMESPACE_DECL:
3718 case XML_XINCLUDE_START:
3719 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003720#ifdef LIBXML_DOCB_ENABLED
3721 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003722#endif
3723 break;
3724 case XML_ELEMENT_DECL:
3725 case XML_ATTRIBUTE_DECL:
3726 case XML_ENTITY_DECL:
3727 break;
3728 }
3729}
3730
3731/**
3732 * xmlNodeAddContent:
3733 * @cur: the node being modified
3734 * @content: extra content
3735 *
3736 * Append the extra substring to the node content.
3737 */
3738void
3739xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3740 int len;
3741
3742 if (cur == NULL) {
3743#ifdef DEBUG_TREE
3744 xmlGenericError(xmlGenericErrorContext,
3745 "xmlNodeAddContent : node == NULL\n");
3746#endif
3747 return;
3748 }
3749 if (content == NULL) return;
3750 len = xmlStrlen(content);
3751 xmlNodeAddContentLen(cur, content, len);
3752}
3753
3754/**
3755 * xmlTextMerge:
3756 * @first: the first text node
3757 * @second: the second text node being merged
3758 *
3759 * Merge two text nodes into one
3760 * Returns the first text node augmented
3761 */
3762xmlNodePtr
3763xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3764 if (first == NULL) return(second);
3765 if (second == NULL) return(first);
3766 if (first->type != XML_TEXT_NODE) return(first);
3767 if (second->type != XML_TEXT_NODE) return(first);
3768 if (second->name != first->name)
3769 return(first);
3770#ifndef XML_USE_BUFFER_CONTENT
3771 xmlNodeAddContent(first, second->content);
3772#else
3773 xmlNodeAddContent(first, xmlBufferContent(second->content));
3774#endif
3775 xmlUnlinkNode(second);
3776 xmlFreeNode(second);
3777 return(first);
3778}
3779
3780/**
3781 * xmlGetNsList:
3782 * @doc: the document
3783 * @node: the current node
3784 *
3785 * Search all the namespace applying to a given element.
3786 * Returns an NULL terminated array of all the xmlNsPtr found
3787 * that need to be freed by the caller or NULL if no
3788 * namespace if defined
3789 */
3790xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003791xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3792{
Owen Taylor3473f882001-02-23 17:55:21 +00003793 xmlNsPtr cur;
3794 xmlNsPtr *ret = NULL;
3795 int nbns = 0;
3796 int maxns = 10;
3797 int i;
3798
3799 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00003800 if (node->type == XML_ELEMENT_NODE) {
3801 cur = node->nsDef;
3802 while (cur != NULL) {
3803 if (ret == NULL) {
3804 ret =
3805 (xmlNsPtr *) xmlMalloc((maxns + 1) *
3806 sizeof(xmlNsPtr));
3807 if (ret == NULL) {
3808 xmlGenericError(xmlGenericErrorContext,
3809 "xmlGetNsList : out of memory!\n");
3810 return (NULL);
3811 }
3812 ret[nbns] = NULL;
3813 }
3814 for (i = 0; i < nbns; i++) {
3815 if ((cur->prefix == ret[i]->prefix) ||
3816 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
3817 break;
3818 }
3819 if (i >= nbns) {
3820 if (nbns >= maxns) {
3821 maxns *= 2;
3822 ret = (xmlNsPtr *) xmlRealloc(ret,
3823 (maxns +
3824 1) *
3825 sizeof(xmlNsPtr));
3826 if (ret == NULL) {
3827 xmlGenericError(xmlGenericErrorContext,
3828 "xmlGetNsList : realloc failed!\n");
3829 return (NULL);
3830 }
3831 }
3832 ret[nbns++] = cur;
3833 ret[nbns] = NULL;
3834 }
Owen Taylor3473f882001-02-23 17:55:21 +00003835
Daniel Veillard77044732001-06-29 21:31:07 +00003836 cur = cur->next;
3837 }
3838 }
3839 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003840 }
Daniel Veillard77044732001-06-29 21:31:07 +00003841 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003842}
3843
3844/**
3845 * xmlSearchNs:
3846 * @doc: the document
3847 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00003848 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00003849 *
3850 * Search a Ns registered under a given name space for a document.
3851 * recurse on the parents until it finds the defined namespace
3852 * or return NULL otherwise.
3853 * @nameSpace can be NULL, this is a search for the default namespace.
3854 * We don't allow to cross entities boundaries. If you don't declare
3855 * the namespace within those you will be in troubles !!! A warning
3856 * is generated to cover this case.
3857 *
3858 * Returns the namespace pointer or NULL.
3859 */
3860xmlNsPtr
3861xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
3862 xmlNsPtr cur;
3863
3864 if (node == NULL) return(NULL);
3865 if ((nameSpace != NULL) &&
3866 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
3867 if (doc->oldNs == NULL) {
3868 /*
3869 * Allocate a new Namespace and fill the fields.
3870 */
3871 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3872 if (doc->oldNs == NULL) {
3873 xmlGenericError(xmlGenericErrorContext,
3874 "xmlSearchNsByHref : malloc failed\n");
3875 return(NULL);
3876 }
3877 memset(doc->oldNs, 0, sizeof(xmlNs));
3878 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3879
3880 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3881 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3882 }
3883 return(doc->oldNs);
3884 }
3885 while (node != NULL) {
3886 if ((node->type == XML_ENTITY_REF_NODE) ||
3887 (node->type == XML_ENTITY_NODE) ||
3888 (node->type == XML_ENTITY_DECL))
3889 return(NULL);
3890 if (node->type == XML_ELEMENT_NODE) {
3891 cur = node->nsDef;
3892 while (cur != NULL) {
3893 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3894 (cur->href != NULL))
3895 return(cur);
3896 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
3897 (cur->href != NULL) &&
3898 (xmlStrEqual(cur->prefix, nameSpace)))
3899 return(cur);
3900 cur = cur->next;
3901 }
3902 }
3903 node = node->parent;
3904 }
3905 return(NULL);
3906}
3907
3908/**
3909 * xmlSearchNsByHref:
3910 * @doc: the document
3911 * @node: the current node
3912 * @href: the namespace value
3913 *
3914 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3915 * the defined namespace or return NULL otherwise.
3916 * Returns the namespace pointer or NULL.
3917 */
3918xmlNsPtr
3919xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
3920 xmlNsPtr cur;
3921 xmlNodePtr orig = node;
3922
3923 if ((node == NULL) || (href == NULL)) return(NULL);
3924 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
3925 if (doc->oldNs == NULL) {
3926 /*
3927 * Allocate a new Namespace and fill the fields.
3928 */
3929 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3930 if (doc->oldNs == NULL) {
3931 xmlGenericError(xmlGenericErrorContext,
3932 "xmlSearchNsByHref : malloc failed\n");
3933 return(NULL);
3934 }
3935 memset(doc->oldNs, 0, sizeof(xmlNs));
3936 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3937
3938 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3939 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3940 }
3941 return(doc->oldNs);
3942 }
3943 while (node != NULL) {
3944 cur = node->nsDef;
3945 while (cur != NULL) {
3946 if ((cur->href != NULL) && (href != NULL) &&
3947 (xmlStrEqual(cur->href, href))) {
3948 /*
3949 * Check that the prefix is not shadowed between orig and node
3950 */
3951 xmlNodePtr check = orig;
3952 xmlNsPtr tst;
3953
3954 while (check != node) {
3955 tst = check->nsDef;
3956 while (tst != NULL) {
3957 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3958 goto shadowed;
3959 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
3960 (xmlStrEqual(tst->prefix, cur->prefix)))
3961 goto shadowed;
3962 tst = tst->next;
3963 }
3964 check = check->parent;
3965 }
3966 return(cur);
3967 }
3968shadowed:
3969 cur = cur->next;
3970 }
3971 node = node->parent;
3972 }
3973 return(NULL);
3974}
3975
3976/**
3977 * xmlNewReconciliedNs
3978 * @doc: the document
3979 * @tree: a node expected to hold the new namespace
3980 * @ns: the original namespace
3981 *
3982 * This function tries to locate a namespace definition in a tree
3983 * ancestors, or create a new namespace definition node similar to
3984 * @ns trying to reuse the same prefix. However if the given prefix is
3985 * null (default namespace) or reused within the subtree defined by
3986 * @tree or on one of its ancestors then a new prefix is generated.
3987 * Returns the (new) namespace definition or NULL in case of error
3988 */
3989xmlNsPtr
3990xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3991 xmlNsPtr def;
3992 xmlChar prefix[50];
3993 int counter = 1;
3994
3995 if (tree == NULL) {
3996#ifdef DEBUG_TREE
3997 xmlGenericError(xmlGenericErrorContext,
3998 "xmlNewReconciliedNs : tree == NULL\n");
3999#endif
4000 return(NULL);
4001 }
4002 if (ns == NULL) {
4003#ifdef DEBUG_TREE
4004 xmlGenericError(xmlGenericErrorContext,
4005 "xmlNewReconciliedNs : ns == NULL\n");
4006#endif
4007 return(NULL);
4008 }
4009 /*
4010 * Search an existing namespace definition inherited.
4011 */
4012 def = xmlSearchNsByHref(doc, tree, ns->href);
4013 if (def != NULL)
4014 return(def);
4015
4016 /*
4017 * Find a close prefix which is not already in use.
4018 * Let's strip namespace prefixes longer than 20 chars !
4019 */
4020 sprintf((char *) prefix, "%.20s", ns->prefix);
4021 def = xmlSearchNs(doc, tree, prefix);
4022 while (def != NULL) {
4023 if (counter > 1000) return(NULL);
4024 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4025 def = xmlSearchNs(doc, tree, prefix);
4026 }
4027
4028 /*
4029 * Ok, now we are ready to create a new one.
4030 */
4031 def = xmlNewNs(tree, ns->href, prefix);
4032 return(def);
4033}
4034
4035/**
4036 * xmlReconciliateNs
4037 * @doc: the document
4038 * @tree: a node defining the subtree to reconciliate
4039 *
4040 * This function checks that all the namespaces declared within the given
4041 * tree are properly declared. This is needed for example after Copy or Cut
4042 * and then paste operations. The subtree may still hold pointers to
4043 * namespace declarations outside the subtree or invalid/masked. As much
4044 * as possible the function try tu reuse the existing namespaces found in
4045 * the new environment. If not possible the new namespaces are redeclared
4046 * on @tree at the top of the given subtree.
4047 * Returns the number of namespace declarations created or -1 in case of error.
4048 */
4049int
4050xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4051 xmlNsPtr *oldNs = NULL;
4052 xmlNsPtr *newNs = NULL;
4053 int sizeCache = 0;
4054 int nbCache = 0;
4055
4056 xmlNsPtr n;
4057 xmlNodePtr node = tree;
4058 xmlAttrPtr attr;
4059 int ret = 0, i;
4060
4061 while (node != NULL) {
4062 /*
4063 * Reconciliate the node namespace
4064 */
4065 if (node->ns != NULL) {
4066 /*
4067 * initialize the cache if needed
4068 */
4069 if (sizeCache == 0) {
4070 sizeCache = 10;
4071 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4072 sizeof(xmlNsPtr));
4073 if (oldNs == NULL) {
4074 xmlGenericError(xmlGenericErrorContext,
4075 "xmlReconciliateNs : memory pbm\n");
4076 return(-1);
4077 }
4078 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4079 sizeof(xmlNsPtr));
4080 if (newNs == NULL) {
4081 xmlGenericError(xmlGenericErrorContext,
4082 "xmlReconciliateNs : memory pbm\n");
4083 xmlFree(oldNs);
4084 return(-1);
4085 }
4086 }
4087 for (i = 0;i < nbCache;i++) {
4088 if (oldNs[i] == node->ns) {
4089 node->ns = newNs[i];
4090 break;
4091 }
4092 }
4093 if (i == nbCache) {
4094 /*
4095 * Ok we need to recreate a new namespace definition
4096 */
4097 n = xmlNewReconciliedNs(doc, tree, node->ns);
4098 if (n != NULL) { /* :-( what if else ??? */
4099 /*
4100 * check if we need to grow the cache buffers.
4101 */
4102 if (sizeCache <= nbCache) {
4103 sizeCache *= 2;
4104 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4105 sizeof(xmlNsPtr));
4106 if (oldNs == NULL) {
4107 xmlGenericError(xmlGenericErrorContext,
4108 "xmlReconciliateNs : memory pbm\n");
4109 xmlFree(newNs);
4110 return(-1);
4111 }
4112 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4113 sizeof(xmlNsPtr));
4114 if (newNs == NULL) {
4115 xmlGenericError(xmlGenericErrorContext,
4116 "xmlReconciliateNs : memory pbm\n");
4117 xmlFree(oldNs);
4118 return(-1);
4119 }
4120 }
4121 newNs[nbCache] = n;
4122 oldNs[nbCache++] = node->ns;
4123 node->ns = n;
4124 }
4125 }
4126 }
4127 /*
4128 * now check for namespace hold by attributes on the node.
4129 */
4130 attr = node->properties;
4131 while (attr != NULL) {
4132 if (attr->ns != NULL) {
4133 /*
4134 * initialize the cache if needed
4135 */
4136 if (sizeCache == 0) {
4137 sizeCache = 10;
4138 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4139 sizeof(xmlNsPtr));
4140 if (oldNs == NULL) {
4141 xmlGenericError(xmlGenericErrorContext,
4142 "xmlReconciliateNs : memory pbm\n");
4143 return(-1);
4144 }
4145 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4146 sizeof(xmlNsPtr));
4147 if (newNs == NULL) {
4148 xmlGenericError(xmlGenericErrorContext,
4149 "xmlReconciliateNs : memory pbm\n");
4150 xmlFree(oldNs);
4151 return(-1);
4152 }
4153 }
4154 for (i = 0;i < nbCache;i++) {
4155 if (oldNs[i] == attr->ns) {
4156 node->ns = newNs[i];
4157 break;
4158 }
4159 }
4160 if (i == nbCache) {
4161 /*
4162 * Ok we need to recreate a new namespace definition
4163 */
4164 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4165 if (n != NULL) { /* :-( what if else ??? */
4166 /*
4167 * check if we need to grow the cache buffers.
4168 */
4169 if (sizeCache <= nbCache) {
4170 sizeCache *= 2;
4171 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4172 sizeof(xmlNsPtr));
4173 if (oldNs == NULL) {
4174 xmlGenericError(xmlGenericErrorContext,
4175 "xmlReconciliateNs : memory pbm\n");
4176 xmlFree(newNs);
4177 return(-1);
4178 }
4179 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4180 sizeof(xmlNsPtr));
4181 if (newNs == NULL) {
4182 xmlGenericError(xmlGenericErrorContext,
4183 "xmlReconciliateNs : memory pbm\n");
4184 xmlFree(oldNs);
4185 return(-1);
4186 }
4187 }
4188 newNs[nbCache] = n;
4189 oldNs[nbCache++] = attr->ns;
4190 attr->ns = n;
4191 }
4192 }
4193 }
4194 attr = attr->next;
4195 }
4196
4197 /*
4198 * Browse the full subtree, deep first
4199 */
4200 if (node->children != NULL) {
4201 /* deep first */
4202 node = node->children;
4203 } else if ((node != tree) && (node->next != NULL)) {
4204 /* then siblings */
4205 node = node->next;
4206 } else if (node != tree) {
4207 /* go up to parents->next if needed */
4208 while (node != tree) {
4209 if (node->parent != NULL)
4210 node = node->parent;
4211 if ((node != tree) && (node->next != NULL)) {
4212 node = node->next;
4213 break;
4214 }
4215 if (node->parent == NULL) {
4216 node = NULL;
4217 break;
4218 }
4219 }
4220 /* exit condition */
4221 if (node == tree)
4222 node = NULL;
4223 }
4224 }
4225 return(ret);
4226}
4227
4228/**
4229 * xmlHasProp:
4230 * @node: the node
4231 * @name: the attribute name
4232 *
4233 * Search an attribute associated to a node
4234 * This function also looks in DTD attribute declaration for #FIXED or
4235 * default declaration values unless DTD use has been turned off.
4236 *
4237 * Returns the attribute or the attribute declaration or NULL if
4238 * neither was found.
4239 */
4240xmlAttrPtr
4241xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4242 xmlAttrPtr prop;
4243 xmlDocPtr doc;
4244
4245 if ((node == NULL) || (name == NULL)) return(NULL);
4246 /*
4247 * Check on the properties attached to the node
4248 */
4249 prop = node->properties;
4250 while (prop != NULL) {
4251 if (xmlStrEqual(prop->name, name)) {
4252 return(prop);
4253 }
4254 prop = prop->next;
4255 }
4256 if (!xmlCheckDTD) return(NULL);
4257
4258 /*
4259 * Check if there is a default declaration in the internal
4260 * or external subsets
4261 */
4262 doc = node->doc;
4263 if (doc != NULL) {
4264 xmlAttributePtr attrDecl;
4265 if (doc->intSubset != NULL) {
4266 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4267 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4268 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4269 if (attrDecl != NULL)
4270 return((xmlAttrPtr) attrDecl);
4271 }
4272 }
4273 return(NULL);
4274}
4275
4276/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004277 * xmlHasNsProp:
4278 * @node: the node
4279 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004280 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004281 *
4282 * Search for an attribute associated to a node
4283 * This attribute has to be anchored in the namespace specified.
4284 * This does the entity substitution.
4285 * This function looks in DTD attribute declaration for #FIXED or
4286 * default declaration values unless DTD use has been turned off.
4287 *
4288 * Returns the attribute or the attribute declaration or NULL
4289 * if neither was found.
4290 */
4291xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004292xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004293 xmlAttrPtr prop;
4294 xmlDocPtr doc;
4295 xmlNsPtr ns;
4296
4297 if (node == NULL)
4298 return(NULL);
4299
4300 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004301 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004302 return(xmlHasProp(node, name));
4303 while (prop != NULL) {
4304 /*
4305 * One need to have
4306 * - same attribute names
4307 * - and the attribute carrying that namespace
4308 * or
4309 * no namespace on the attribute and the element carrying it
4310 */
4311 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004312 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4313 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004314 }
4315 prop = prop->next;
4316 }
4317 if (!xmlCheckDTD) return(NULL);
4318
4319 /*
4320 * Check if there is a default declaration in the internal
4321 * or external subsets
4322 */
4323 doc = node->doc;
4324 if (doc != NULL) {
4325 if (doc->intSubset != NULL) {
4326 xmlAttributePtr attrDecl;
4327
4328 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4329 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4330 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4331
4332 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4333 /*
4334 * The DTD declaration only allows a prefix search
4335 */
4336 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004337 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004338 return((xmlAttrPtr) attrDecl);
4339 }
4340 }
4341 }
4342 return(NULL);
4343}
4344
4345/**
Owen Taylor3473f882001-02-23 17:55:21 +00004346 * xmlGetProp:
4347 * @node: the node
4348 * @name: the attribute name
4349 *
4350 * Search and get the value of an attribute associated to a node
4351 * This does the entity substitution.
4352 * This function looks in DTD attribute declaration for #FIXED or
4353 * default declaration values unless DTD use has been turned off.
4354 *
4355 * Returns the attribute value or NULL if not found.
4356 * It's up to the caller to free the memory.
4357 */
4358xmlChar *
4359xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4360 xmlAttrPtr prop;
4361 xmlDocPtr doc;
4362
4363 if ((node == NULL) || (name == NULL)) return(NULL);
4364 /*
4365 * Check on the properties attached to the node
4366 */
4367 prop = node->properties;
4368 while (prop != NULL) {
4369 if (xmlStrEqual(prop->name, name)) {
4370 xmlChar *ret;
4371
4372 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4373 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4374 return(ret);
4375 }
4376 prop = prop->next;
4377 }
4378 if (!xmlCheckDTD) return(NULL);
4379
4380 /*
4381 * Check if there is a default declaration in the internal
4382 * or external subsets
4383 */
4384 doc = node->doc;
4385 if (doc != NULL) {
4386 xmlAttributePtr attrDecl;
4387 if (doc->intSubset != NULL) {
4388 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4389 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4390 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4391 if (attrDecl != NULL)
4392 return(xmlStrdup(attrDecl->defaultValue));
4393 }
4394 }
4395 return(NULL);
4396}
4397
4398/**
4399 * xmlGetNsProp:
4400 * @node: the node
4401 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004402 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004403 *
4404 * Search and get the value of an attribute associated to a node
4405 * This attribute has to be anchored in the namespace specified.
4406 * This does the entity substitution.
4407 * This function looks in DTD attribute declaration for #FIXED or
4408 * default declaration values unless DTD use has been turned off.
4409 *
4410 * Returns the attribute value or NULL if not found.
4411 * It's up to the caller to free the memory.
4412 */
4413xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004414xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004415 xmlAttrPtr prop;
4416 xmlDocPtr doc;
4417 xmlNsPtr ns;
4418
4419 if (node == NULL)
4420 return(NULL);
4421
4422 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004423 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004424 return(xmlGetProp(node, name));
4425 while (prop != NULL) {
4426 /*
4427 * One need to have
4428 * - same attribute names
4429 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004430 */
4431 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004432 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004433 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004434 xmlChar *ret;
4435
4436 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4437 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4438 return(ret);
4439 }
4440 prop = prop->next;
4441 }
4442 if (!xmlCheckDTD) return(NULL);
4443
4444 /*
4445 * Check if there is a default declaration in the internal
4446 * or external subsets
4447 */
4448 doc = node->doc;
4449 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004450 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004451 xmlAttributePtr attrDecl;
4452
Owen Taylor3473f882001-02-23 17:55:21 +00004453 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4454 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4455 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4456
4457 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4458 /*
4459 * The DTD declaration only allows a prefix search
4460 */
4461 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004462 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004463 return(xmlStrdup(attrDecl->defaultValue));
4464 }
4465 }
4466 }
4467 return(NULL);
4468}
4469
4470/**
4471 * xmlSetProp:
4472 * @node: the node
4473 * @name: the attribute name
4474 * @value: the attribute value
4475 *
4476 * Set (or reset) an attribute carried by a node.
4477 * Returns the attribute pointer.
4478 */
4479xmlAttrPtr
4480xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
4481 xmlAttrPtr prop = node->properties;
4482 xmlDocPtr doc = NULL;
4483
4484 if ((node == NULL) || (name == NULL))
4485 return(NULL);
4486 doc = node->doc;
4487 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004488 if ((xmlStrEqual(prop->name, name)) &&
4489 (prop->ns == NULL)){
Owen Taylor3473f882001-02-23 17:55:21 +00004490 if (prop->children != NULL)
4491 xmlFreeNodeList(prop->children);
4492 prop->children = NULL;
4493 prop->last = NULL;
4494 if (value != NULL) {
4495 xmlChar *buffer;
4496 xmlNodePtr tmp;
4497
4498 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4499 prop->children = xmlStringGetNodeList(node->doc, buffer);
4500 prop->last = NULL;
4501 prop->doc = doc;
4502 tmp = prop->children;
4503 while (tmp != NULL) {
4504 tmp->parent = (xmlNodePtr) prop;
4505 tmp->doc = doc;
4506 if (tmp->next == NULL)
4507 prop->last = tmp;
4508 tmp = tmp->next;
4509 }
4510 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004511 }
Owen Taylor3473f882001-02-23 17:55:21 +00004512 return(prop);
4513 }
4514 prop = prop->next;
4515 }
4516 prop = xmlNewProp(node, name, value);
4517 return(prop);
4518}
4519
4520/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004521 * xmlUnsetProp:
4522 * @node: the node
4523 * @name: the attribute name
4524 *
4525 * Remove an attribute carried by a node.
4526 * Returns 0 if successful, -1 if not found
4527 */
4528int
4529xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4530 xmlAttrPtr prop = node->properties, prev = NULL;;
4531
4532 if ((node == NULL) || (name == NULL))
4533 return(-1);
4534 while (prop != NULL) {
4535 if ((xmlStrEqual(prop->name, name)) &&
4536 (prop->ns == NULL)) {
4537 if (prev == NULL)
4538 node->properties = prop->next;
4539 else
4540 prev->next = prop->next;
4541 xmlFreeProp(prop);
4542 return(0);
4543 }
4544 prev = prop;
4545 prop = prop->next;
4546 }
4547 return(-1);
4548}
4549
4550/**
Owen Taylor3473f882001-02-23 17:55:21 +00004551 * xmlSetNsProp:
4552 * @node: the node
4553 * @ns: the namespace definition
4554 * @name: the attribute name
4555 * @value: the attribute value
4556 *
4557 * Set (or reset) an attribute carried by a node.
4558 * The ns structure must be in scope, this is not checked.
4559 *
4560 * Returns the attribute pointer.
4561 */
4562xmlAttrPtr
4563xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4564 const xmlChar *value) {
4565 xmlAttrPtr prop;
4566
4567 if ((node == NULL) || (name == NULL))
4568 return(NULL);
4569
4570 if (ns == NULL)
4571 return(xmlSetProp(node, name, value));
4572 if (ns->href == NULL)
4573 return(NULL);
4574 prop = node->properties;
4575
4576 while (prop != NULL) {
4577 /*
4578 * One need to have
4579 * - same attribute names
4580 * - and the attribute carrying that namespace
4581 * or
4582 * no namespace on the attribute and the element carrying it
4583 */
4584 if ((xmlStrEqual(prop->name, name)) &&
4585 (((prop->ns == NULL) && (node->ns != NULL) &&
4586 (xmlStrEqual(node->ns->href, ns->href))) ||
4587 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4588 if (prop->children != NULL)
4589 xmlFreeNodeList(prop->children);
4590 prop->children = NULL;
4591 prop->last = NULL;
4592 prop->ns = ns;
4593 if (value != NULL) {
4594 xmlChar *buffer;
4595 xmlNodePtr tmp;
4596
4597 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4598 prop->children = xmlStringGetNodeList(node->doc, buffer);
4599 prop->last = NULL;
4600 tmp = prop->children;
4601 while (tmp != NULL) {
4602 tmp->parent = (xmlNodePtr) prop;
4603 if (tmp->next == NULL)
4604 prop->last = tmp;
4605 tmp = tmp->next;
4606 }
4607 xmlFree(buffer);
4608 }
4609 return(prop);
4610 }
4611 prop = prop->next;
4612 }
4613 prop = xmlNewNsProp(node, ns, name, value);
4614 return(prop);
4615}
4616
4617/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004618 * xmlUnsetNsProp:
4619 * @node: the node
4620 * @ns: the namespace definition
4621 * @name: the attribute name
4622 *
4623 * Remove an attribute carried by a node.
4624 * Returns 0 if successful, -1 if not found
4625 */
4626int
4627xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4628 xmlAttrPtr prop = node->properties, prev = NULL;;
4629
4630 if ((node == NULL) || (name == NULL))
4631 return(-1);
4632 if (ns == NULL)
4633 return(xmlUnsetProp(node, name));
4634 if (ns->href == NULL)
4635 return(-1);
4636 while (prop != NULL) {
4637 if ((xmlStrEqual(prop->name, name)) &&
4638 (((prop->ns == NULL) && (node->ns != NULL) &&
4639 (xmlStrEqual(node->ns->href, ns->href))) ||
4640 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4641 if (prev == NULL)
4642 node->properties = prop->next;
4643 else
4644 prev->next = prop->next;
4645 xmlFreeProp(prop);
4646 return(0);
4647 }
4648 prev = prop;
4649 prop = prop->next;
4650 }
4651 return(-1);
4652}
4653
4654/**
Owen Taylor3473f882001-02-23 17:55:21 +00004655 * xmlNodeIsText:
4656 * @node: the node
4657 *
4658 * Is this node a Text node ?
4659 * Returns 1 yes, 0 no
4660 */
4661int
4662xmlNodeIsText(xmlNodePtr node) {
4663 if (node == NULL) return(0);
4664
4665 if (node->type == XML_TEXT_NODE) return(1);
4666 return(0);
4667}
4668
4669/**
4670 * xmlIsBlankNode:
4671 * @node: the node
4672 *
4673 * Checks whether this node is an empty or whitespace only
4674 * (and possibly ignorable) text-node.
4675 *
4676 * Returns 1 yes, 0 no
4677 */
4678int
4679xmlIsBlankNode(xmlNodePtr node) {
4680 const xmlChar *cur;
4681 if (node == NULL) return(0);
4682
Daniel Veillard7db37732001-07-12 01:20:08 +00004683 if ((node->type != XML_TEXT_NODE) &&
4684 (node->type != XML_CDATA_SECTION_NODE))
4685 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004686 if (node->content == NULL) return(1);
4687#ifndef XML_USE_BUFFER_CONTENT
4688 cur = node->content;
4689#else
4690 cur = xmlBufferContent(node->content);
4691#endif
4692 while (*cur != 0) {
4693 if (!IS_BLANK(*cur)) return(0);
4694 cur++;
4695 }
4696
4697 return(1);
4698}
4699
4700/**
4701 * xmlTextConcat:
4702 * @node: the node
4703 * @content: the content
4704 * @len: @content lenght
4705 *
4706 * Concat the given string at the end of the existing node content
4707 */
4708
4709void
4710xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4711 if (node == NULL) return;
4712
4713 if ((node->type != XML_TEXT_NODE) &&
4714 (node->type != XML_CDATA_SECTION_NODE)) {
4715#ifdef DEBUG_TREE
4716 xmlGenericError(xmlGenericErrorContext,
4717 "xmlTextConcat: node is not text nor cdata\n");
4718#endif
4719 return;
4720 }
4721#ifndef XML_USE_BUFFER_CONTENT
4722 node->content = xmlStrncat(node->content, content, len);
4723#else
4724 xmlBufferAdd(node->content, content, len);
4725#endif
4726}
4727
4728/************************************************************************
4729 * *
4730 * Output : to a FILE or in memory *
4731 * *
4732 ************************************************************************/
4733
4734#define BASE_BUFFER_SIZE 4000
4735
Daniel Veillarde356c282001-03-10 12:32:04 +00004736int xmlDefaultBufferSize = BASE_BUFFER_SIZE;
4737
Owen Taylor3473f882001-02-23 17:55:21 +00004738/**
4739 * xmlBufferCreate:
4740 *
4741 * routine to create an XML buffer.
4742 * returns the new structure.
4743 */
4744xmlBufferPtr
4745xmlBufferCreate(void) {
4746 xmlBufferPtr ret;
4747
4748 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4749 if (ret == NULL) {
4750 xmlGenericError(xmlGenericErrorContext,
4751 "xmlBufferCreate : out of memory!\n");
4752 return(NULL);
4753 }
4754 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004755 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004756 ret->alloc = xmlBufferAllocScheme;
4757 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4758 if (ret->content == NULL) {
4759 xmlGenericError(xmlGenericErrorContext,
4760 "xmlBufferCreate : out of memory!\n");
4761 xmlFree(ret);
4762 return(NULL);
4763 }
4764 ret->content[0] = 0;
4765 return(ret);
4766}
4767
4768/**
4769 * xmlBufferCreateSize:
4770 * @size: initial size of buffer
4771 *
4772 * routine to create an XML buffer.
4773 * returns the new structure.
4774 */
4775xmlBufferPtr
4776xmlBufferCreateSize(size_t size) {
4777 xmlBufferPtr ret;
4778
4779 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4780 if (ret == NULL) {
4781 xmlGenericError(xmlGenericErrorContext,
4782 "xmlBufferCreate : out of memory!\n");
4783 return(NULL);
4784 }
4785 ret->use = 0;
4786 ret->alloc = xmlBufferAllocScheme;
4787 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4788 if (ret->size){
4789 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4790 if (ret->content == NULL) {
4791 xmlGenericError(xmlGenericErrorContext,
4792 "xmlBufferCreate : out of memory!\n");
4793 xmlFree(ret);
4794 return(NULL);
4795 }
4796 ret->content[0] = 0;
4797 } else
4798 ret->content = NULL;
4799 return(ret);
4800}
4801
4802/**
4803 * xmlBufferSetAllocationScheme:
4804 * @buf: the buffer to free
4805 * @scheme: allocation scheme to use
4806 *
4807 * Sets the allocation scheme for this buffer
4808 */
4809void
4810xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4811 xmlBufferAllocationScheme scheme) {
4812 if (buf == NULL) {
4813#ifdef DEBUG_BUFFER
4814 xmlGenericError(xmlGenericErrorContext,
4815 "xmlBufferSetAllocationScheme: buf == NULL\n");
4816#endif
4817 return;
4818 }
4819
4820 buf->alloc = scheme;
4821}
4822
4823/**
4824 * xmlBufferFree:
4825 * @buf: the buffer to free
4826 *
4827 * Frees an XML buffer.
4828 */
4829void
4830xmlBufferFree(xmlBufferPtr buf) {
4831 if (buf == NULL) {
4832#ifdef DEBUG_BUFFER
4833 xmlGenericError(xmlGenericErrorContext,
4834 "xmlBufferFree: buf == NULL\n");
4835#endif
4836 return;
4837 }
4838 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004839 xmlFree(buf->content);
4840 }
Owen Taylor3473f882001-02-23 17:55:21 +00004841 xmlFree(buf);
4842}
4843
4844/**
4845 * xmlBufferEmpty:
4846 * @buf: the buffer
4847 *
4848 * empty a buffer.
4849 */
4850void
4851xmlBufferEmpty(xmlBufferPtr buf) {
4852 if (buf->content == NULL) return;
4853 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004854 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004855}
4856
4857/**
4858 * xmlBufferShrink:
4859 * @buf: the buffer to dump
4860 * @len: the number of xmlChar to remove
4861 *
4862 * Remove the beginning of an XML buffer.
4863 *
4864 * Returns the number of xmlChar removed, or -1 in case of failure.
4865 */
4866int
4867xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
4868 if (len == 0) return(0);
4869 if (len > buf->use) return(-1);
4870
4871 buf->use -= len;
4872 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
4873
4874 buf->content[buf->use] = 0;
4875 return(len);
4876}
4877
4878/**
4879 * xmlBufferGrow:
4880 * @buf: the buffer
4881 * @len: the minimum free size to allocate
4882 *
4883 * Grow the available space of an XML buffer.
4884 *
4885 * Returns the new available space or -1 in case of error
4886 */
4887int
4888xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
4889 int size;
4890 xmlChar *newbuf;
4891
4892 if (len + buf->use < buf->size) return(0);
4893
4894 size = buf->use + len + 100;
4895
4896 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
4897 if (newbuf == NULL) return(-1);
4898 buf->content = newbuf;
4899 buf->size = size;
4900 return(buf->size - buf->use);
4901}
4902
4903/**
4904 * xmlBufferDump:
4905 * @file: the file output
4906 * @buf: the buffer to dump
4907 *
4908 * Dumps an XML buffer to a FILE *.
4909 * Returns the number of xmlChar written
4910 */
4911int
4912xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4913 int ret;
4914
4915 if (buf == NULL) {
4916#ifdef DEBUG_BUFFER
4917 xmlGenericError(xmlGenericErrorContext,
4918 "xmlBufferDump: buf == NULL\n");
4919#endif
4920 return(0);
4921 }
4922 if (buf->content == NULL) {
4923#ifdef DEBUG_BUFFER
4924 xmlGenericError(xmlGenericErrorContext,
4925 "xmlBufferDump: buf->content == NULL\n");
4926#endif
4927 return(0);
4928 }
4929 if (file == NULL) file = stdout;
4930 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
4931 return(ret);
4932}
4933
4934/**
4935 * xmlBufferContent:
4936 * @buf: the buffer
4937 *
4938 * Returns the internal content
4939 */
4940
4941const xmlChar*
4942xmlBufferContent(const xmlBufferPtr buf)
4943{
4944 if(!buf)
4945 return NULL;
4946
4947 return buf->content;
4948}
4949
4950/**
4951 * xmlBufferLength:
4952 * @buf: the buffer
4953 *
4954 * Returns the length of data in the internal content
4955 */
4956
4957int
4958xmlBufferLength(const xmlBufferPtr buf)
4959{
4960 if(!buf)
4961 return 0;
4962
4963 return buf->use;
4964}
4965
4966/**
4967 * xmlBufferResize:
4968 * @buf: the buffer to resize
4969 * @size: the desired size
4970 *
4971 * Resize a buffer to accomodate minimum size of @size.
4972 *
4973 * Returns 0 in case of problems, 1 otherwise
4974 */
4975int
4976xmlBufferResize(xmlBufferPtr buf, unsigned int size)
4977{
4978 unsigned int newSize;
4979 xmlChar* rebuf = NULL;
4980
4981 /*take care of empty case*/
4982 newSize = (buf->size ? buf->size*2 : size);
4983
4984 /* Don't resize if we don't have to */
4985 if (size < buf->size)
4986 return 1;
4987
4988 /* figure out new size */
4989 switch (buf->alloc){
4990 case XML_BUFFER_ALLOC_DOUBLEIT:
4991 while (size > newSize) newSize *= 2;
4992 break;
4993 case XML_BUFFER_ALLOC_EXACT:
4994 newSize = size+10;
4995 break;
4996 default:
4997 newSize = size+10;
4998 break;
4999 }
5000
5001 if (buf->content == NULL)
5002 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5003 else
5004 rebuf = (xmlChar *) xmlRealloc(buf->content,
5005 newSize * sizeof(xmlChar));
5006 if (rebuf == NULL) {
5007 xmlGenericError(xmlGenericErrorContext,
5008 "xmlBufferAdd : out of memory!\n");
5009 return 0;
5010 }
5011 buf->content = rebuf;
5012 buf->size = newSize;
5013
5014 return 1;
5015}
5016
5017/**
5018 * xmlBufferAdd:
5019 * @buf: the buffer to dump
5020 * @str: the xmlChar string
5021 * @len: the number of xmlChar to add
5022 *
5023 * Add a string range to an XML buffer. if len == -1, the lenght of
5024 * str is recomputed.
5025 */
5026void
5027xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5028 unsigned int needSize;
5029
5030 if (str == NULL) {
5031#ifdef DEBUG_BUFFER
5032 xmlGenericError(xmlGenericErrorContext,
5033 "xmlBufferAdd: str == NULL\n");
5034#endif
5035 return;
5036 }
5037 if (len < -1) {
5038#ifdef DEBUG_BUFFER
5039 xmlGenericError(xmlGenericErrorContext,
5040 "xmlBufferAdd: len < 0\n");
5041#endif
5042 return;
5043 }
5044 if (len == 0) return;
5045
5046 if (len < 0)
5047 len = xmlStrlen(str);
5048
5049 if (len <= 0) return;
5050
5051 needSize = buf->use + len + 2;
5052 if (needSize > buf->size){
5053 if (!xmlBufferResize(buf, needSize)){
5054 xmlGenericError(xmlGenericErrorContext,
5055 "xmlBufferAdd : out of memory!\n");
5056 return;
5057 }
5058 }
5059
5060 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5061 buf->use += len;
5062 buf->content[buf->use] = 0;
5063}
5064
5065/**
5066 * xmlBufferAddHead:
5067 * @buf: the buffer
5068 * @str: the xmlChar string
5069 * @len: the number of xmlChar to add
5070 *
5071 * Add a string range to the beginning of an XML buffer.
5072 * if len == -1, the lenght of @str is recomputed.
5073 */
5074void
5075xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5076 unsigned int needSize;
5077
5078 if (str == NULL) {
5079#ifdef DEBUG_BUFFER
5080 xmlGenericError(xmlGenericErrorContext,
5081 "xmlBufferAdd: str == NULL\n");
5082#endif
5083 return;
5084 }
5085 if (len < -1) {
5086#ifdef DEBUG_BUFFER
5087 xmlGenericError(xmlGenericErrorContext,
5088 "xmlBufferAdd: len < 0\n");
5089#endif
5090 return;
5091 }
5092 if (len == 0) return;
5093
5094 if (len < 0)
5095 len = xmlStrlen(str);
5096
5097 if (len <= 0) return;
5098
5099 needSize = buf->use + len + 2;
5100 if (needSize > buf->size){
5101 if (!xmlBufferResize(buf, needSize)){
5102 xmlGenericError(xmlGenericErrorContext,
5103 "xmlBufferAddHead : out of memory!\n");
5104 return;
5105 }
5106 }
5107
5108 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5109 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5110 buf->use += len;
5111 buf->content[buf->use] = 0;
5112}
5113
5114/**
5115 * xmlBufferCat:
5116 * @buf: the buffer to dump
5117 * @str: the xmlChar string
5118 *
5119 * Append a zero terminated string to an XML buffer.
5120 */
5121void
5122xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5123 if (str != NULL)
5124 xmlBufferAdd(buf, str, -1);
5125}
5126
5127/**
5128 * xmlBufferCCat:
5129 * @buf: the buffer to dump
5130 * @str: the C char string
5131 *
5132 * Append a zero terminated C string to an XML buffer.
5133 */
5134void
5135xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5136 const char *cur;
5137
5138 if (str == NULL) {
5139#ifdef DEBUG_BUFFER
5140 xmlGenericError(xmlGenericErrorContext,
5141 "xmlBufferAdd: str == NULL\n");
5142#endif
5143 return;
5144 }
5145 for (cur = str;*cur != 0;cur++) {
5146 if (buf->use + 10 >= buf->size) {
5147 if (!xmlBufferResize(buf, buf->use+10)){
5148 xmlGenericError(xmlGenericErrorContext,
5149 "xmlBufferCCat : out of memory!\n");
5150 return;
5151 }
5152 }
5153 buf->content[buf->use++] = *cur;
5154 }
5155 buf->content[buf->use] = 0;
5156}
5157
5158/**
5159 * xmlBufferWriteCHAR:
5160 * @buf: the XML buffer
5161 * @string: the string to add
5162 *
5163 * routine which manages and grows an output buffer. This one adds
5164 * xmlChars at the end of the buffer.
5165 */
5166void
5167#ifdef VMS
5168xmlBufferWriteXmlCHAR
5169#else
5170xmlBufferWriteCHAR
5171#endif
5172(xmlBufferPtr buf, const xmlChar *string) {
5173 xmlBufferCat(buf, string);
5174}
5175
5176/**
5177 * xmlBufferWriteChar:
5178 * @buf: the XML buffer output
5179 * @string: the string to add
5180 *
5181 * routine which manage and grows an output buffer. This one add
5182 * C chars at the end of the array.
5183 */
5184void
5185xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5186 xmlBufferCCat(buf, string);
5187}
5188
5189
5190/**
5191 * xmlBufferWriteQuotedString:
5192 * @buf: the XML buffer output
5193 * @string: the string to add
5194 *
5195 * routine which manage and grows an output buffer. This one writes
5196 * a quoted or double quoted xmlChar string, checking first if it holds
5197 * quote or double-quotes internally
5198 */
5199void
5200xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5201 if (xmlStrchr(string, '"')) {
5202 if (xmlStrchr(string, '\'')) {
5203#ifdef DEBUG_BUFFER
5204 xmlGenericError(xmlGenericErrorContext,
5205 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5206#endif
5207 }
5208 xmlBufferCCat(buf, "'");
5209 xmlBufferCat(buf, string);
5210 xmlBufferCCat(buf, "'");
5211 } else {
5212 xmlBufferCCat(buf, "\"");
5213 xmlBufferCat(buf, string);
5214 xmlBufferCCat(buf, "\"");
5215 }
5216}
5217
5218
5219/************************************************************************
5220 * *
5221 * Dumping XML tree content to a simple buffer *
5222 * *
5223 ************************************************************************/
5224
5225void
5226xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5227 int format);
5228static void
5229xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5230 int format);
5231void
5232htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5233
5234/**
5235 * xmlNsDump:
5236 * @buf: the XML buffer output
5237 * @cur: a namespace
5238 *
5239 * Dump a local Namespace definition.
5240 * Should be called in the context of attributes dumps.
5241 */
5242static void
5243xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5244 if (cur == NULL) {
5245#ifdef DEBUG_TREE
5246 xmlGenericError(xmlGenericErrorContext,
5247 "xmlNsDump : Ns == NULL\n");
5248#endif
5249 return;
5250 }
5251 if (cur->type == XML_LOCAL_NAMESPACE) {
5252 /* Within the context of an element attributes */
5253 if (cur->prefix != NULL) {
5254 xmlBufferWriteChar(buf, " xmlns:");
5255 xmlBufferWriteCHAR(buf, cur->prefix);
5256 } else
5257 xmlBufferWriteChar(buf, " xmlns");
5258 xmlBufferWriteChar(buf, "=");
5259 xmlBufferWriteQuotedString(buf, cur->href);
5260 }
5261}
5262
5263/**
5264 * xmlNsListDump:
5265 * @buf: the XML buffer output
5266 * @cur: the first namespace
5267 *
5268 * Dump a list of local Namespace definitions.
5269 * Should be called in the context of attributes dumps.
5270 */
5271static void
5272xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5273 while (cur != NULL) {
5274 xmlNsDump(buf, cur);
5275 cur = cur->next;
5276 }
5277}
5278
5279/**
5280 * xmlDtdDump:
5281 * @buf: the XML buffer output
5282 * @doc: the document
5283 *
5284 * Dump the XML document DTD, if any.
5285 */
5286static void
5287xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5288 if (dtd == NULL) {
5289#ifdef DEBUG_TREE
5290 xmlGenericError(xmlGenericErrorContext,
5291 "xmlDtdDump : no internal subset\n");
5292#endif
5293 return;
5294 }
5295 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5296 xmlBufferWriteCHAR(buf, dtd->name);
5297 if (dtd->ExternalID != NULL) {
5298 xmlBufferWriteChar(buf, " PUBLIC ");
5299 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5300 xmlBufferWriteChar(buf, " ");
5301 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5302 } else if (dtd->SystemID != NULL) {
5303 xmlBufferWriteChar(buf, " SYSTEM ");
5304 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5305 }
5306 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5307 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5308 xmlBufferWriteChar(buf, ">");
5309 return;
5310 }
5311 xmlBufferWriteChar(buf, " [\n");
5312 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5313#if 0
5314 if (dtd->entities != NULL)
5315 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5316 if (dtd->notations != NULL)
5317 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5318 if (dtd->elements != NULL)
5319 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5320 if (dtd->attributes != NULL)
5321 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5322#endif
5323 xmlBufferWriteChar(buf, "]>");
5324}
5325
5326/**
5327 * xmlAttrDump:
5328 * @buf: the XML buffer output
5329 * @doc: the document
5330 * @cur: the attribute pointer
5331 *
5332 * Dump an XML attribute
5333 */
5334static void
5335xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5336 xmlChar *value;
5337
5338 if (cur == NULL) {
5339#ifdef DEBUG_TREE
5340 xmlGenericError(xmlGenericErrorContext,
5341 "xmlAttrDump : property == NULL\n");
5342#endif
5343 return;
5344 }
5345 xmlBufferWriteChar(buf, " ");
5346 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5347 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5348 xmlBufferWriteChar(buf, ":");
5349 }
5350 xmlBufferWriteCHAR(buf, cur->name);
5351 value = xmlNodeListGetString(doc, cur->children, 0);
5352 if (value != NULL) {
5353 xmlBufferWriteChar(buf, "=");
5354 xmlBufferWriteQuotedString(buf, value);
5355 xmlFree(value);
5356 } else {
5357 xmlBufferWriteChar(buf, "=\"\"");
5358 }
5359}
5360
5361/**
5362 * xmlAttrListDump:
5363 * @buf: the XML buffer output
5364 * @doc: the document
5365 * @cur: the first attribute pointer
5366 *
5367 * Dump a list of XML attributes
5368 */
5369static void
5370xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5371 if (cur == NULL) {
5372#ifdef DEBUG_TREE
5373 xmlGenericError(xmlGenericErrorContext,
5374 "xmlAttrListDump : property == NULL\n");
5375#endif
5376 return;
5377 }
5378 while (cur != NULL) {
5379 xmlAttrDump(buf, doc, cur);
5380 cur = cur->next;
5381 }
5382}
5383
5384
5385
5386/**
5387 * xmlNodeListDump:
5388 * @buf: the XML buffer output
5389 * @doc: the document
5390 * @cur: the first node
5391 * @level: the imbrication level for indenting
5392 * @format: is formatting allowed
5393 *
5394 * Dump an XML node list, recursive behaviour,children are printed too.
5395 */
5396static void
5397xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5398 int format) {
5399 int i;
5400
5401 if (cur == NULL) {
5402#ifdef DEBUG_TREE
5403 xmlGenericError(xmlGenericErrorContext,
5404 "xmlNodeListDump : node == NULL\n");
5405#endif
5406 return;
5407 }
5408 while (cur != NULL) {
5409 if ((format) && (xmlIndentTreeOutput) &&
5410 (cur->type == XML_ELEMENT_NODE))
5411 for (i = 0;i < level;i++)
5412 xmlBufferWriteChar(buf, " ");
5413 xmlNodeDump(buf, doc, cur, level, format);
5414 if (format) {
5415 xmlBufferWriteChar(buf, "\n");
5416 }
5417 cur = cur->next;
5418 }
5419}
5420
5421/**
5422 * xmlNodeDump:
5423 * @buf: the XML buffer output
5424 * @doc: the document
5425 * @cur: the current node
5426 * @level: the imbrication level for indenting
5427 * @format: is formatting allowed
5428 *
5429 * Dump an XML node, recursive behaviour,children are printed too.
5430 */
5431void
5432xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5433 int format) {
5434 int i;
5435 xmlNodePtr tmp;
5436
5437 if (cur == NULL) {
5438#ifdef DEBUG_TREE
5439 xmlGenericError(xmlGenericErrorContext,
5440 "xmlNodeDump : node == NULL\n");
5441#endif
5442 return;
5443 }
5444 if (cur->type == XML_XINCLUDE_START)
5445 return;
5446 if (cur->type == XML_XINCLUDE_END)
5447 return;
5448 if (cur->type == XML_DTD_NODE) {
5449 xmlDtdDump(buf, (xmlDtdPtr) cur);
5450 return;
5451 }
5452 if (cur->type == XML_ELEMENT_DECL) {
5453 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5454 return;
5455 }
5456 if (cur->type == XML_ATTRIBUTE_DECL) {
5457 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5458 return;
5459 }
5460 if (cur->type == XML_ENTITY_DECL) {
5461 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5462 return;
5463 }
5464 if (cur->type == XML_TEXT_NODE) {
5465 if (cur->content != NULL) {
5466 if ((cur->name == xmlStringText) ||
5467 (cur->name != xmlStringTextNoenc)) {
5468 xmlChar *buffer;
5469
5470#ifndef XML_USE_BUFFER_CONTENT
5471 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5472#else
5473 buffer = xmlEncodeEntitiesReentrant(doc,
5474 xmlBufferContent(cur->content));
5475#endif
5476 if (buffer != NULL) {
5477 xmlBufferWriteCHAR(buf, buffer);
5478 xmlFree(buffer);
5479 }
5480 } else {
5481 /*
5482 * Disable escaping, needed for XSLT
5483 */
5484#ifndef XML_USE_BUFFER_CONTENT
5485 xmlBufferWriteCHAR(buf, cur->content);
5486#else
5487 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5488#endif
5489 }
5490 }
5491 return;
5492 }
5493 if (cur->type == XML_PI_NODE) {
5494 if (cur->content != NULL) {
5495 xmlBufferWriteChar(buf, "<?");
5496 xmlBufferWriteCHAR(buf, cur->name);
5497 if (cur->content != NULL) {
5498 xmlBufferWriteChar(buf, " ");
5499#ifndef XML_USE_BUFFER_CONTENT
5500 xmlBufferWriteCHAR(buf, cur->content);
5501#else
5502 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5503#endif
5504 }
5505 xmlBufferWriteChar(buf, "?>");
5506 } else {
5507 xmlBufferWriteChar(buf, "<?");
5508 xmlBufferWriteCHAR(buf, cur->name);
5509 xmlBufferWriteChar(buf, "?>");
5510 }
5511 return;
5512 }
5513 if (cur->type == XML_COMMENT_NODE) {
5514 if (cur->content != NULL) {
5515 xmlBufferWriteChar(buf, "<!--");
5516#ifndef XML_USE_BUFFER_CONTENT
5517 xmlBufferWriteCHAR(buf, cur->content);
5518#else
5519 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5520#endif
5521 xmlBufferWriteChar(buf, "-->");
5522 }
5523 return;
5524 }
5525 if (cur->type == XML_ENTITY_REF_NODE) {
5526 xmlBufferWriteChar(buf, "&");
5527 xmlBufferWriteCHAR(buf, cur->name);
5528 xmlBufferWriteChar(buf, ";");
5529 return;
5530 }
5531 if (cur->type == XML_CDATA_SECTION_NODE) {
5532 xmlBufferWriteChar(buf, "<![CDATA[");
5533 if (cur->content != NULL)
5534#ifndef XML_USE_BUFFER_CONTENT
5535 xmlBufferWriteCHAR(buf, cur->content);
5536#else
5537 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5538#endif
5539 xmlBufferWriteChar(buf, "]]>");
5540 return;
5541 }
5542
5543 if (format == 1) {
5544 tmp = cur->children;
5545 while (tmp != NULL) {
5546 if ((tmp->type == XML_TEXT_NODE) ||
5547 (tmp->type == XML_ENTITY_REF_NODE)) {
5548 format = 0;
5549 break;
5550 }
5551 tmp = tmp->next;
5552 }
5553 }
5554 xmlBufferWriteChar(buf, "<");
5555 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5556 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5557 xmlBufferWriteChar(buf, ":");
5558 }
5559
5560 xmlBufferWriteCHAR(buf, cur->name);
5561 if (cur->nsDef)
5562 xmlNsListDump(buf, cur->nsDef);
5563 if (cur->properties != NULL)
5564 xmlAttrListDump(buf, doc, cur->properties);
5565
Daniel Veillard7db37732001-07-12 01:20:08 +00005566 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5567 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005568 (!xmlSaveNoEmptyTags)) {
5569 xmlBufferWriteChar(buf, "/>");
5570 return;
5571 }
5572 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005573 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005574 xmlChar *buffer;
5575
5576#ifndef XML_USE_BUFFER_CONTENT
5577 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5578#else
5579 buffer = xmlEncodeEntitiesReentrant(doc,
5580 xmlBufferContent(cur->content));
5581#endif
5582 if (buffer != NULL) {
5583 xmlBufferWriteCHAR(buf, buffer);
5584 xmlFree(buffer);
5585 }
5586 }
5587 if (cur->children != NULL) {
5588 if (format) xmlBufferWriteChar(buf, "\n");
5589 xmlNodeListDump(buf, doc, cur->children,
5590 (level >= 0?level+1:-1), format);
5591 if ((xmlIndentTreeOutput) && (format))
5592 for (i = 0;i < level;i++)
5593 xmlBufferWriteChar(buf, " ");
5594 }
5595 xmlBufferWriteChar(buf, "</");
5596 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5597 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5598 xmlBufferWriteChar(buf, ":");
5599 }
5600
5601 xmlBufferWriteCHAR(buf, cur->name);
5602 xmlBufferWriteChar(buf, ">");
5603}
5604
5605/**
5606 * xmlElemDump:
5607 * @f: the FILE * for the output
5608 * @doc: the document
5609 * @cur: the current node
5610 *
5611 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5612 */
5613void
5614xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5615 xmlBufferPtr buf;
5616
5617 if (cur == NULL) {
5618#ifdef DEBUG_TREE
5619 xmlGenericError(xmlGenericErrorContext,
5620 "xmlElemDump : cur == NULL\n");
5621#endif
5622 return;
5623 }
Owen Taylor3473f882001-02-23 17:55:21 +00005624#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005625 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005626 xmlGenericError(xmlGenericErrorContext,
5627 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005628 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005629#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005630 buf = xmlBufferCreate();
5631 if (buf == NULL) return;
5632 if ((doc != NULL) &&
5633 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5634#ifdef LIBXML_HTML_ENABLED
5635 htmlNodeDump(buf, doc, cur);
5636#else
5637 xmlGenericError(xmlGenericErrorContext,
5638 "HTML support not compiled in\n");
5639#endif /* LIBXML_HTML_ENABLED */
5640 } else
5641 xmlNodeDump(buf, doc, cur, 0, 1);
5642 xmlBufferDump(f, buf);
5643 xmlBufferFree(buf);
5644}
5645
5646/************************************************************************
5647 * *
5648 * Dumping XML tree content to an I/O output buffer *
5649 * *
5650 ************************************************************************/
5651
5652void
5653xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5654 int level, int format, const char *encoding);
5655static void
5656xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5657 int level, int format, const char *encoding);
5658/**
5659 * xmlNsDumpOutput:
5660 * @buf: the XML buffer output
5661 * @cur: a namespace
5662 *
5663 * Dump a local Namespace definition.
5664 * Should be called in the context of attributes dumps.
5665 */
5666static void
5667xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5668 if (cur == NULL) {
5669#ifdef DEBUG_TREE
5670 xmlGenericError(xmlGenericErrorContext,
5671 "xmlNsDump : Ns == NULL\n");
5672#endif
5673 return;
5674 }
5675 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5676 /* Within the context of an element attributes */
5677 if (cur->prefix != NULL) {
5678 xmlOutputBufferWriteString(buf, " xmlns:");
5679 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5680 } else
5681 xmlOutputBufferWriteString(buf, " xmlns");
5682 xmlOutputBufferWriteString(buf, "=");
5683 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5684 }
5685}
5686
5687/**
5688 * xmlNsListDumpOutput:
5689 * @buf: the XML buffer output
5690 * @cur: the first namespace
5691 *
5692 * Dump a list of local Namespace definitions.
5693 * Should be called in the context of attributes dumps.
5694 */
5695static void
5696xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5697 while (cur != NULL) {
5698 xmlNsDumpOutput(buf, cur);
5699 cur = cur->next;
5700 }
5701}
5702
5703/**
5704 * xmlDtdDumpOutput:
5705 * @buf: the XML buffer output
5706 * @doc: the document
5707 * @encoding: an optional encoding string
5708 *
5709 * Dump the XML document DTD, if any.
5710 */
5711static void
5712xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5713 if (dtd == NULL) {
5714#ifdef DEBUG_TREE
5715 xmlGenericError(xmlGenericErrorContext,
5716 "xmlDtdDump : no internal subset\n");
5717#endif
5718 return;
5719 }
5720 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5721 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5722 if (dtd->ExternalID != NULL) {
5723 xmlOutputBufferWriteString(buf, " PUBLIC ");
5724 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5725 xmlOutputBufferWriteString(buf, " ");
5726 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5727 } else if (dtd->SystemID != NULL) {
5728 xmlOutputBufferWriteString(buf, " SYSTEM ");
5729 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5730 }
5731 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5732 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5733 xmlOutputBufferWriteString(buf, ">");
5734 return;
5735 }
5736 xmlOutputBufferWriteString(buf, " [\n");
5737 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5738 xmlOutputBufferWriteString(buf, "]>");
5739}
5740
5741/**
5742 * xmlAttrDumpOutput:
5743 * @buf: the XML buffer output
5744 * @doc: the document
5745 * @cur: the attribute pointer
5746 * @encoding: an optional encoding string
5747 *
5748 * Dump an XML attribute
5749 */
5750static void
5751xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005752 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005753 xmlChar *value;
5754
5755 if (cur == NULL) {
5756#ifdef DEBUG_TREE
5757 xmlGenericError(xmlGenericErrorContext,
5758 "xmlAttrDump : property == NULL\n");
5759#endif
5760 return;
5761 }
5762 xmlOutputBufferWriteString(buf, " ");
5763 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5764 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5765 xmlOutputBufferWriteString(buf, ":");
5766 }
5767 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5768 value = xmlNodeListGetString(doc, cur->children, 0);
5769 if (value) {
5770 xmlOutputBufferWriteString(buf, "=");
5771 xmlBufferWriteQuotedString(buf->buffer, value);
5772 xmlFree(value);
5773 } else {
5774 xmlOutputBufferWriteString(buf, "=\"\"");
5775 }
5776}
5777
5778/**
5779 * xmlAttrListDumpOutput:
5780 * @buf: the XML buffer output
5781 * @doc: the document
5782 * @cur: the first attribute pointer
5783 * @encoding: an optional encoding string
5784 *
5785 * Dump a list of XML attributes
5786 */
5787static void
5788xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5789 xmlAttrPtr cur, const char *encoding) {
5790 if (cur == NULL) {
5791#ifdef DEBUG_TREE
5792 xmlGenericError(xmlGenericErrorContext,
5793 "xmlAttrListDump : property == NULL\n");
5794#endif
5795 return;
5796 }
5797 while (cur != NULL) {
5798 xmlAttrDumpOutput(buf, doc, cur, encoding);
5799 cur = cur->next;
5800 }
5801}
5802
5803
5804
5805/**
5806 * xmlNodeListDumpOutput:
5807 * @buf: the XML buffer output
5808 * @doc: the document
5809 * @cur: the first node
5810 * @level: the imbrication level for indenting
5811 * @format: is formatting allowed
5812 * @encoding: an optional encoding string
5813 *
5814 * Dump an XML node list, recursive behaviour,children are printed too.
5815 */
5816static void
5817xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5818 xmlNodePtr cur, int level, int format, const char *encoding) {
5819 int i;
5820
5821 if (cur == NULL) {
5822#ifdef DEBUG_TREE
5823 xmlGenericError(xmlGenericErrorContext,
5824 "xmlNodeListDump : node == NULL\n");
5825#endif
5826 return;
5827 }
5828 while (cur != NULL) {
5829 if ((format) && (xmlIndentTreeOutput) &&
5830 (cur->type == XML_ELEMENT_NODE))
5831 for (i = 0;i < level;i++)
5832 xmlOutputBufferWriteString(buf, " ");
5833 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5834 if (format) {
5835 xmlOutputBufferWriteString(buf, "\n");
5836 }
5837 cur = cur->next;
5838 }
5839}
5840
5841/**
5842 * xmlNodeDumpOutput:
5843 * @buf: the XML buffer output
5844 * @doc: the document
5845 * @cur: the current node
5846 * @level: the imbrication level for indenting
5847 * @format: is formatting allowed
5848 * @encoding: an optional encoding string
5849 *
5850 * Dump an XML node, recursive behaviour,children are printed too.
5851 */
5852void
5853xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5854 int level, int format, const char *encoding) {
5855 int i;
5856 xmlNodePtr tmp;
5857
5858 if (cur == NULL) {
5859#ifdef DEBUG_TREE
5860 xmlGenericError(xmlGenericErrorContext,
5861 "xmlNodeDump : node == NULL\n");
5862#endif
5863 return;
5864 }
5865 if (cur->type == XML_XINCLUDE_START)
5866 return;
5867 if (cur->type == XML_XINCLUDE_END)
5868 return;
5869 if (cur->type == XML_DTD_NODE) {
5870 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5871 return;
5872 }
5873 if (cur->type == XML_ELEMENT_DECL) {
5874 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5875 return;
5876 }
5877 if (cur->type == XML_ATTRIBUTE_DECL) {
5878 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5879 return;
5880 }
5881 if (cur->type == XML_ENTITY_DECL) {
5882 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5883 return;
5884 }
5885 if (cur->type == XML_TEXT_NODE) {
5886 if (cur->content != NULL) {
5887 if ((cur->name == xmlStringText) ||
5888 (cur->name != xmlStringTextNoenc)) {
5889 xmlChar *buffer;
5890
5891#ifndef XML_USE_BUFFER_CONTENT
5892 if (encoding == NULL)
5893 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5894 else
5895 buffer = xmlEncodeSpecialChars(doc, cur->content);
5896#else
5897 if (encoding == NULL)
5898 buffer = xmlEncodeEntitiesReentrant(doc,
5899 xmlBufferContent(cur->content));
5900 else
5901 buffer = xmlEncodeSpecialChars(doc,
5902 xmlBufferContent(cur->content));
5903#endif
5904 if (buffer != NULL) {
5905 xmlOutputBufferWriteString(buf, (const char *)buffer);
5906 xmlFree(buffer);
5907 }
5908 } else {
5909 /*
5910 * Disable escaping, needed for XSLT
5911 */
5912#ifndef XML_USE_BUFFER_CONTENT
5913 xmlOutputBufferWriteString(buf, (const char *) cur->content);
5914#else
5915 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5916#endif
5917 }
5918 }
5919
5920 return;
5921 }
5922 if (cur->type == XML_PI_NODE) {
5923 if (cur->content != NULL) {
5924 xmlOutputBufferWriteString(buf, "<?");
5925 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5926 if (cur->content != NULL) {
5927 xmlOutputBufferWriteString(buf, " ");
5928#ifndef XML_USE_BUFFER_CONTENT
5929 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5930#else
5931 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5932#endif
5933 }
5934 xmlOutputBufferWriteString(buf, "?>");
5935 } else {
5936 xmlOutputBufferWriteString(buf, "<?");
5937 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5938 xmlOutputBufferWriteString(buf, "?>");
5939 }
5940 return;
5941 }
5942 if (cur->type == XML_COMMENT_NODE) {
5943 if (cur->content != NULL) {
5944 xmlOutputBufferWriteString(buf, "<!--");
5945#ifndef XML_USE_BUFFER_CONTENT
5946 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5947#else
5948 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5949#endif
5950 xmlOutputBufferWriteString(buf, "-->");
5951 }
5952 return;
5953 }
5954 if (cur->type == XML_ENTITY_REF_NODE) {
5955 xmlOutputBufferWriteString(buf, "&");
5956 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5957 xmlOutputBufferWriteString(buf, ";");
5958 return;
5959 }
5960 if (cur->type == XML_CDATA_SECTION_NODE) {
5961 xmlOutputBufferWriteString(buf, "<![CDATA[");
5962 if (cur->content != NULL)
5963#ifndef XML_USE_BUFFER_CONTENT
5964 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5965#else
5966 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5967#endif
5968 xmlOutputBufferWriteString(buf, "]]>");
5969 return;
5970 }
5971
5972 if (format == 1) {
5973 tmp = cur->children;
5974 while (tmp != NULL) {
5975 if ((tmp->type == XML_TEXT_NODE) ||
5976 (tmp->type == XML_ENTITY_REF_NODE)) {
5977 format = 0;
5978 break;
5979 }
5980 tmp = tmp->next;
5981 }
5982 }
5983 xmlOutputBufferWriteString(buf, "<");
5984 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5985 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5986 xmlOutputBufferWriteString(buf, ":");
5987 }
5988
5989 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5990 if (cur->nsDef)
5991 xmlNsListDumpOutput(buf, cur->nsDef);
5992 if (cur->properties != NULL)
5993 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5994
Daniel Veillard7db37732001-07-12 01:20:08 +00005995 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5996 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005997 xmlOutputBufferWriteString(buf, "/>");
5998 return;
5999 }
6000 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006001 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006002 xmlChar *buffer;
6003
6004#ifndef XML_USE_BUFFER_CONTENT
6005 if (encoding == NULL)
6006 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6007 else
6008 buffer = xmlEncodeSpecialChars(doc, cur->content);
6009#else
6010 if (encoding == NULL)
6011 buffer = xmlEncodeEntitiesReentrant(doc,
6012 xmlBufferContent(cur->content));
6013 else
6014 buffer = xmlEncodeSpecialChars(doc,
6015 xmlBufferContent(cur->content));
6016#endif
6017 if (buffer != NULL) {
6018 xmlOutputBufferWriteString(buf, (const char *)buffer);
6019 xmlFree(buffer);
6020 }
6021 }
6022 if (cur->children != NULL) {
6023 if (format) xmlOutputBufferWriteString(buf, "\n");
6024 xmlNodeListDumpOutput(buf, doc, cur->children,
6025 (level >= 0?level+1:-1), format, encoding);
6026 if ((xmlIndentTreeOutput) && (format))
6027 for (i = 0;i < level;i++)
6028 xmlOutputBufferWriteString(buf, " ");
6029 }
6030 xmlOutputBufferWriteString(buf, "</");
6031 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6032 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6033 xmlOutputBufferWriteString(buf, ":");
6034 }
6035
6036 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6037 xmlOutputBufferWriteString(buf, ">");
6038}
6039
6040/**
6041 * xmlDocContentDumpOutput:
6042 * @buf: the XML buffer output
6043 * @cur: the document
6044 * @encoding: an optional encoding string
6045 * @format: should formatting spaces been added
6046 *
6047 * Dump an XML document.
6048 */
6049static void
6050xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6051 const char *encoding, int format) {
6052 xmlOutputBufferWriteString(buf, "<?xml version=");
6053 if (cur->version != NULL)
6054 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6055 else
6056 xmlOutputBufferWriteString(buf, "\"1.0\"");
6057 if (encoding == NULL) {
6058 if (cur->encoding != NULL)
6059 encoding = (const char *) cur->encoding;
6060 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6061 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6062 }
6063 if (encoding != NULL) {
6064 xmlOutputBufferWriteString(buf, " encoding=");
6065 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6066 }
6067 switch (cur->standalone) {
6068 case 0:
6069 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6070 break;
6071 case 1:
6072 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6073 break;
6074 }
6075 xmlOutputBufferWriteString(buf, "?>\n");
6076 if (cur->children != NULL) {
6077 xmlNodePtr child = cur->children;
6078
6079 while (child != NULL) {
6080 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6081 xmlOutputBufferWriteString(buf, "\n");
6082 child = child->next;
6083 }
6084 }
6085}
6086
6087/************************************************************************
6088 * *
6089 * Saving functions front-ends *
6090 * *
6091 ************************************************************************/
6092
6093/**
6094 * xmlDocDumpMemoryEnc:
6095 * @out_doc: Document to generate XML text from
6096 * @doc_txt_ptr: Memory pointer for allocated XML text
6097 * @doc_txt_len: Length of the generated XML text
6098 * @txt_encoding: Character encoding to use when generating XML text
6099 * @format: should formatting spaces been added
6100 *
6101 * Dump the current DOM tree into memory using the character encoding specified
6102 * by the caller. Note it is up to the caller of this function to free the
6103 * allocated memory.
6104 */
6105
6106void
6107xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006108 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006109 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006110 int dummy = 0;
6111
6112 xmlCharEncoding doc_charset;
6113 xmlOutputBufferPtr out_buff = NULL;
6114 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6115
6116 if (doc_txt_len == NULL) {
6117 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6118 }
6119
6120 if (doc_txt_ptr == NULL) {
6121 *doc_txt_len = 0;
6122 xmlGenericError(xmlGenericErrorContext,
6123 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6124 return;
6125 }
6126
6127 *doc_txt_ptr = NULL;
6128 *doc_txt_len = 0;
6129
6130 if (out_doc == NULL) {
6131 /* No document, no output */
6132 xmlGenericError(xmlGenericErrorContext,
6133 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6134 return;
6135 }
6136
6137 /*
6138 * Validate the encoding value, if provided.
6139 * This logic is copied from xmlSaveFileEnc.
6140 */
6141
6142 if (txt_encoding == NULL)
6143 txt_encoding = (const char *) out_doc->encoding;
6144 if (txt_encoding != NULL) {
6145 doc_charset = xmlParseCharEncoding(txt_encoding);
6146
6147 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6148 xmlGenericError(xmlGenericErrorContext,
6149 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6150 return;
6151
6152 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6153 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6154 if ( conv_hdlr == NULL ) {
6155 xmlGenericError(xmlGenericErrorContext,
6156 "%s: %s %s '%s'\n",
6157 "xmlDocDumpFormatMemoryEnc",
6158 "Failed to identify encoding handler for",
6159 "character set",
6160 txt_encoding);
6161 return;
6162 }
6163 }
6164 }
6165
6166 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6167 xmlGenericError(xmlGenericErrorContext,
6168 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6169 return;
6170 }
6171
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006172 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006173 xmlOutputBufferFlush(out_buff);
6174 if (out_buff->conv != NULL) {
6175 *doc_txt_len = out_buff->conv->use;
6176 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6177 } else {
6178 *doc_txt_len = out_buff->buffer->use;
6179 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6180 }
6181 (void)xmlOutputBufferClose(out_buff);
6182
6183 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6184 *doc_txt_len = 0;
6185 xmlGenericError(xmlGenericErrorContext,
6186 "xmlDocDumpFormatMemoryEnc: %s\n",
6187 "Failed to allocate memory for document text representation.");
6188 }
6189
6190 return;
6191}
6192
6193/**
6194 * xmlDocDumpMemory:
6195 * @cur: the document
6196 * @mem: OUT: the memory pointer
6197 * @size: OUT: the memory lenght
6198 *
6199 * Dump an XML document in memory and return the xmlChar * and it's size.
6200 * It's up to the caller to free the memory.
6201 */
6202void
6203xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6204 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6205}
6206
6207/**
6208 * xmlDocDumpFormatMemory:
6209 * @cur: the document
6210 * @mem: OUT: the memory pointer
6211 * @size: OUT: the memory lenght
6212 * @format: should formatting spaces been added
6213 *
6214 *
6215 * Dump an XML document in memory and return the xmlChar * and it's size.
6216 * It's up to the caller to free the memory.
6217 */
6218void
6219xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6220 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6221}
6222
6223/**
6224 * xmlDocDumpMemoryEnc:
6225 * @out_doc: Document to generate XML text from
6226 * @doc_txt_ptr: Memory pointer for allocated XML text
6227 * @doc_txt_len: Length of the generated XML text
6228 * @txt_encoding: Character encoding to use when generating XML text
6229 *
6230 * Dump the current DOM tree into memory using the character encoding specified
6231 * by the caller. Note it is up to the caller of this function to free the
6232 * allocated memory.
6233 */
6234
6235void
6236xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6237 int * doc_txt_len, const char * txt_encoding) {
6238 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006239 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006240}
6241
6242/**
6243 * xmlGetDocCompressMode:
6244 * @doc: the document
6245 *
6246 * get the compression ratio for a document, ZLIB based
6247 * Returns 0 (uncompressed) to 9 (max compression)
6248 */
6249int
6250xmlGetDocCompressMode (xmlDocPtr doc) {
6251 if (doc == NULL) return(-1);
6252 return(doc->compression);
6253}
6254
6255/**
6256 * xmlSetDocCompressMode:
6257 * @doc: the document
6258 * @mode: the compression ratio
6259 *
6260 * set the compression ratio for a document, ZLIB based
6261 * Correct values: 0 (uncompressed) to 9 (max compression)
6262 */
6263void
6264xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6265 if (doc == NULL) return;
6266 if (mode < 0) doc->compression = 0;
6267 else if (mode > 9) doc->compression = 9;
6268 else doc->compression = mode;
6269}
6270
6271/**
6272 * xmlGetCompressMode:
6273 *
6274 * get the default compression mode used, ZLIB based.
6275 * Returns 0 (uncompressed) to 9 (max compression)
6276 */
6277int
6278 xmlGetCompressMode(void) {
6279 return(xmlCompressMode);
6280}
6281
6282/**
6283 * xmlSetCompressMode:
6284 * @mode: the compression ratio
6285 *
6286 * set the default compression mode used, ZLIB based
6287 * Correct values: 0 (uncompressed) to 9 (max compression)
6288 */
6289void
6290xmlSetCompressMode(int mode) {
6291 if (mode < 0) xmlCompressMode = 0;
6292 else if (mode > 9) xmlCompressMode = 9;
6293 else xmlCompressMode = mode;
6294}
6295
6296/**
6297 * xmlDocDump:
6298 * @f: the FILE*
6299 * @cur: the document
6300 *
6301 * Dump an XML document to an open FILE.
6302 *
6303 * returns: the number of byte written or -1 in case of failure.
6304 */
6305int
6306xmlDocDump(FILE *f, xmlDocPtr cur) {
6307 xmlOutputBufferPtr buf;
6308 const char * encoding;
6309 xmlCharEncodingHandlerPtr handler = NULL;
6310 int ret;
6311
6312 if (cur == NULL) {
6313#ifdef DEBUG_TREE
6314 xmlGenericError(xmlGenericErrorContext,
6315 "xmlDocDump : document == NULL\n");
6316#endif
6317 return(-1);
6318 }
6319 encoding = (const char *) cur->encoding;
6320
6321 if (encoding != NULL) {
6322 xmlCharEncoding enc;
6323
6324 enc = xmlParseCharEncoding(encoding);
6325
6326 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6327 xmlGenericError(xmlGenericErrorContext,
6328 "xmlDocDump: document not in UTF8\n");
6329 return(-1);
6330 }
6331 if (enc != XML_CHAR_ENCODING_UTF8) {
6332 handler = xmlFindCharEncodingHandler(encoding);
6333 if (handler == NULL) {
6334 xmlFree((char *) cur->encoding);
6335 cur->encoding = NULL;
6336 }
6337 }
6338 }
6339 buf = xmlOutputBufferCreateFile(f, handler);
6340 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006341 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006342
6343 ret = xmlOutputBufferClose(buf);
6344 return(ret);
6345}
6346
6347/**
6348 * xmlSaveFileTo:
6349 * @buf: an output I/O buffer
6350 * @cur: the document
6351 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6352 *
6353 * Dump an XML document to an I/O buffer.
6354 *
6355 * returns: the number of byte written or -1 in case of failure.
6356 */
6357int
6358xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
6359 int ret;
6360
6361 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006362 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006363 ret = xmlOutputBufferClose(buf);
6364 return(ret);
6365}
6366
6367/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006368 * xmlSaveFormatFileTo:
6369 * @buf: an output I/O buffer
6370 * @cur: the document
6371 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6372 * @format: should formatting spaces been added
6373 *
6374 * Dump an XML document to an I/O buffer.
6375 *
6376 * returns: the number of byte written or -1 in case of failure.
6377 */
6378int
6379xmlSaveFormatFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding, int format) {
6380 int ret;
6381
6382 if (buf == NULL) return(0);
6383 xmlDocContentDumpOutput(buf, cur, encoding, format);
6384 ret = xmlOutputBufferClose(buf);
6385 return(ret);
6386}
6387
6388/**
Owen Taylor3473f882001-02-23 17:55:21 +00006389 * xmlSaveFileEnc:
6390 * @filename: the filename (or URL)
6391 * @cur: the document
6392 * @encoding: the name of an encoding (or NULL)
6393 *
6394 * Dump an XML document, converting it to the given encoding
6395 *
6396 * returns: the number of byte written or -1 in case of failure.
6397 */
6398int
6399xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6400 xmlOutputBufferPtr buf;
6401 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006402 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006403 int ret;
6404
6405 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006406
6407 enc = xmlParseCharEncoding(encoding);
6408 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6409 xmlGenericError(xmlGenericErrorContext,
6410 "xmlSaveFileEnc: document not in UTF8\n");
6411 return(-1);
6412 }
6413 if (enc != XML_CHAR_ENCODING_UTF8) {
6414 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006415 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006416 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006417 }
6418 }
6419
6420 /*
6421 * save the content to a temp buffer.
6422 */
6423 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
6424 if (buf == NULL) return(-1);
6425
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006426 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006427
6428 ret = xmlOutputBufferClose(buf);
6429 return(ret);
6430}
6431
6432/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006433 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006434 * @filename: the filename (or URL)
6435 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006436 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006437 *
6438 * Dump an XML document to a file. Will use compression if
6439 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillard67fee942001-04-26 18:59:03 +00006440 * used. If format is set then the document will be indented on output.
6441 *
Owen Taylor3473f882001-02-23 17:55:21 +00006442 * returns: the number of byte written or -1 in case of failure.
6443 */
6444int
Daniel Veillard67fee942001-04-26 18:59:03 +00006445xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006446 xmlOutputBufferPtr buf;
6447 const char *encoding;
6448 xmlCharEncodingHandlerPtr handler = NULL;
6449 int ret;
6450
6451 if (cur == NULL)
6452 return(-1);
6453 encoding = (const char *) cur->encoding;
6454
6455 /*
6456 * save the content to a temp buffer.
6457 */
6458#ifdef HAVE_ZLIB_H
6459 if (cur->compression < 0) cur->compression = xmlCompressMode;
6460#endif
6461 if (encoding != NULL) {
6462 xmlCharEncoding enc;
6463
6464 enc = xmlParseCharEncoding(encoding);
6465
6466 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6467 xmlGenericError(xmlGenericErrorContext,
6468 "xmlSaveFile: document not in UTF8\n");
6469 return(-1);
6470 }
6471 if (enc != XML_CHAR_ENCODING_UTF8) {
6472 handler = xmlFindCharEncodingHandler(encoding);
6473 if (handler == NULL) {
6474 xmlFree((char *) cur->encoding);
6475 cur->encoding = NULL;
6476 }
6477 }
6478 }
6479
6480 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
6481 if (buf == NULL) return(-1);
6482
Daniel Veillard67fee942001-04-26 18:59:03 +00006483 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006484
6485 ret = xmlOutputBufferClose(buf);
6486 return(ret);
6487}
6488
Daniel Veillard67fee942001-04-26 18:59:03 +00006489/**
6490 * xmlSaveFile:
6491 * @filename: the filename (or URL)
6492 * @cur: the document
6493 *
6494 * Dump an XML document to a file. Will use compression if
6495 * compiled in and enabled. If @filename is "-" the stdout file is
6496 * used.
6497 * returns: the number of byte written or -1 in case of failure.
6498 */
6499int
6500xmlSaveFile(const char *filename, xmlDocPtr cur) {
6501 return(xmlSaveFormatFile(filename, cur, 0));
6502}
6503