blob: db2259119e4ecb08b5b8677ea30b96b44f9ffea5 [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) {
907 if (node->type == XML_TEXT_NODE) {
908 if (inLine) {
909#ifndef XML_USE_BUFFER_CONTENT
910 ret = xmlStrcat(ret, node->content);
911#else
912 ret = xmlStrcat(ret, xmlBufferContent(node->content));
913#endif
914 } else {
915 xmlChar *buffer;
916
917#ifndef XML_USE_BUFFER_CONTENT
918 buffer = xmlEncodeSpecialChars(doc, node->content);
919#else
920 buffer = xmlEncodeSpecialChars(doc,
921 xmlBufferContent(node->content));
922#endif
923 if (buffer != NULL) {
924 ret = xmlStrcat(ret, buffer);
925 xmlFree(buffer);
926 }
927 }
928 } else if (node->type == XML_ENTITY_REF_NODE) {
929 if (inLine) {
930 ent = xmlGetDocEntity(doc, node->name);
931 if (ent != NULL)
932 ret = xmlStrcat(ret, ent->content);
933 else {
934#ifndef XML_USE_BUFFER_CONTENT
935 ret = xmlStrcat(ret, node->content);
936#else
937 ret = xmlStrcat(ret, xmlBufferContent(node->content));
938#endif
939 }
940 } else {
941 xmlChar buf[2];
942 buf[0] = '&'; buf[1] = 0;
943 ret = xmlStrncat(ret, buf, 1);
944 ret = xmlStrcat(ret, node->name);
945 buf[0] = ';'; buf[1] = 0;
946 ret = xmlStrncat(ret, buf, 1);
947 }
948 }
949#if 0
950 else {
951 xmlGenericError(xmlGenericErrorContext,
952 "xmlGetNodeListString : invalide node type %d\n",
953 node->type);
954 }
955#endif
956 node = node->next;
957 }
958 return(ret);
959}
960
961/**
962 * xmlNewProp:
963 * @node: the holding node
964 * @name: the name of the attribute
965 * @value: the value of the attribute
966 *
967 * Create a new property carried by a node.
968 * Returns a pointer to the attribute
969 */
970xmlAttrPtr
971xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
972 xmlAttrPtr cur;
973 xmlDocPtr doc = NULL;
974
975 if (name == NULL) {
976#ifdef DEBUG_TREE
977 xmlGenericError(xmlGenericErrorContext,
978 "xmlNewProp : name == NULL\n");
979#endif
980 return(NULL);
981 }
982
983 /*
984 * Allocate a new property and fill the fields.
985 */
986 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
987 if (cur == NULL) {
988 xmlGenericError(xmlGenericErrorContext,
989 "xmlNewProp : malloc failed\n");
990 return(NULL);
991 }
992 memset(cur, 0, sizeof(xmlAttr));
993 cur->type = XML_ATTRIBUTE_NODE;
994
995 cur->parent = node;
996 if (node != NULL) {
997 doc = node->doc;
998 cur->doc = doc;
999 }
1000 cur->name = xmlStrdup(name);
1001 if (value != NULL) {
1002 xmlChar *buffer;
1003 xmlNodePtr tmp;
1004
1005 buffer = xmlEncodeEntitiesReentrant(doc, value);
1006 cur->children = xmlStringGetNodeList(doc, buffer);
1007 cur->last = NULL;
1008 tmp = cur->children;
1009 while (tmp != NULL) {
1010 tmp->parent = (xmlNodePtr) cur;
1011 tmp->doc = doc;
1012 if (tmp->next == NULL)
1013 cur->last = tmp;
1014 tmp = tmp->next;
1015 }
1016 xmlFree(buffer);
1017 }
1018
1019 /*
1020 * Add it at the end to preserve parsing order ...
1021 */
1022 if (node != NULL) {
1023 if (node->properties == NULL) {
1024 node->properties = cur;
1025 } else {
1026 xmlAttrPtr prev = node->properties;
1027
1028 while (prev->next != NULL) prev = prev->next;
1029 prev->next = cur;
1030 cur->prev = prev;
1031 }
1032 }
1033 return(cur);
1034}
1035
1036/**
1037 * xmlNewNsProp:
1038 * @node: the holding node
1039 * @ns: the namespace
1040 * @name: the name of the attribute
1041 * @value: the value of the attribute
1042 *
1043 * Create a new property tagged with a namespace and carried by a node.
1044 * Returns a pointer to the attribute
1045 */
1046xmlAttrPtr
1047xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1048 const xmlChar *value) {
1049 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001050 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001051
1052 if (name == NULL) {
1053#ifdef DEBUG_TREE
1054 xmlGenericError(xmlGenericErrorContext,
1055 "xmlNewProp : name == NULL\n");
1056#endif
1057 return(NULL);
1058 }
1059
1060 /*
1061 * Allocate a new property and fill the fields.
1062 */
1063 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1064 if (cur == NULL) {
1065 xmlGenericError(xmlGenericErrorContext,
1066 "xmlNewProp : malloc failed\n");
1067 return(NULL);
1068 }
1069 memset(cur, 0, sizeof(xmlAttr));
1070 cur->type = XML_ATTRIBUTE_NODE;
1071
1072 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001073 if (node != NULL) {
1074 doc = node->doc;
1075 cur->doc = doc;
1076 }
Owen Taylor3473f882001-02-23 17:55:21 +00001077 cur->ns = ns;
1078 cur->name = xmlStrdup(name);
1079 if (value != NULL) {
1080 xmlChar *buffer;
1081 xmlNodePtr tmp;
1082
Daniel Veillarda682b212001-06-07 19:59:42 +00001083 buffer = xmlEncodeEntitiesReentrant(doc, value);
1084 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001085 cur->last = NULL;
1086 tmp = cur->children;
1087 while (tmp != NULL) {
1088 tmp->parent = (xmlNodePtr) cur;
1089 if (tmp->next == NULL)
1090 cur->last = tmp;
1091 tmp = tmp->next;
1092 }
1093 xmlFree(buffer);
1094 }
1095
1096 /*
1097 * Add it at the end to preserve parsing order ...
1098 */
1099 if (node != NULL) {
1100 if (node->properties == NULL) {
1101 node->properties = cur;
1102 } else {
1103 xmlAttrPtr prev = node->properties;
1104
1105 while (prev->next != NULL) prev = prev->next;
1106 prev->next = cur;
1107 cur->prev = prev;
1108 }
1109 }
1110 return(cur);
1111}
1112
1113/**
1114 * xmlNewDocProp:
1115 * @doc: the document
1116 * @name: the name of the attribute
1117 * @value: the value of the attribute
1118 *
1119 * Create a new property carried by a document.
1120 * Returns a pointer to the attribute
1121 */
1122xmlAttrPtr
1123xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1124 xmlAttrPtr cur;
1125
1126 if (name == NULL) {
1127#ifdef DEBUG_TREE
1128 xmlGenericError(xmlGenericErrorContext,
1129 "xmlNewProp : name == NULL\n");
1130#endif
1131 return(NULL);
1132 }
1133
1134 /*
1135 * Allocate a new property and fill the fields.
1136 */
1137 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1138 if (cur == NULL) {
1139 xmlGenericError(xmlGenericErrorContext,
1140 "xmlNewProp : malloc failed\n");
1141 return(NULL);
1142 }
1143 memset(cur, 0, sizeof(xmlAttr));
1144 cur->type = XML_ATTRIBUTE_NODE;
1145
1146 cur->name = xmlStrdup(name);
1147 cur->doc = doc;
1148 if (value != NULL) {
1149 xmlNodePtr tmp;
1150
1151 cur->children = xmlStringGetNodeList(doc, value);
1152 cur->last = NULL;
1153
1154 tmp = cur->children;
1155 while (tmp != NULL) {
1156 tmp->parent = (xmlNodePtr) cur;
1157 if (tmp->next == NULL)
1158 cur->last = tmp;
1159 tmp = tmp->next;
1160 }
1161 }
1162 return(cur);
1163}
1164
1165/**
1166 * xmlFreePropList:
1167 * @cur: the first property in the list
1168 *
1169 * Free a property and all its siblings, all the children are freed too.
1170 */
1171void
1172xmlFreePropList(xmlAttrPtr cur) {
1173 xmlAttrPtr next;
1174 if (cur == NULL) {
1175#ifdef DEBUG_TREE
1176 xmlGenericError(xmlGenericErrorContext,
1177 "xmlFreePropList : property == NULL\n");
1178#endif
1179 return;
1180 }
1181 while (cur != NULL) {
1182 next = cur->next;
1183 xmlFreeProp(cur);
1184 cur = next;
1185 }
1186}
1187
1188/**
1189 * xmlFreeProp:
1190 * @cur: an attribute
1191 *
1192 * Free one attribute, all the content is freed too
1193 */
1194void
1195xmlFreeProp(xmlAttrPtr cur) {
1196 if (cur == NULL) {
1197#ifdef DEBUG_TREE
1198 xmlGenericError(xmlGenericErrorContext,
1199 "xmlFreeProp : property == NULL\n");
1200#endif
1201 return;
1202 }
1203 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001204 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1205 ((cur->parent->doc->intSubset != NULL) ||
1206 (cur->parent->doc->extSubset != NULL))) {
1207 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1208 xmlRemoveID(cur->parent->doc, cur);
1209 }
Owen Taylor3473f882001-02-23 17:55:21 +00001210 if (cur->name != NULL) xmlFree((char *) cur->name);
1211 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001212 xmlFree(cur);
1213}
1214
1215/**
1216 * xmlRemoveProp:
1217 * @cur: an attribute
1218 *
1219 * Unlink and free one attribute, all the content is freed too
1220 * Note this doesn't work for namespace definition attributes
1221 *
1222 * Returns 0 if success and -1 in case of error.
1223 */
1224int
1225xmlRemoveProp(xmlAttrPtr cur) {
1226 xmlAttrPtr tmp;
1227 if (cur == NULL) {
1228#ifdef DEBUG_TREE
1229 xmlGenericError(xmlGenericErrorContext,
1230 "xmlRemoveProp : cur == NULL\n");
1231#endif
1232 return(-1);
1233 }
1234 if (cur->parent == NULL) {
1235#ifdef DEBUG_TREE
1236 xmlGenericError(xmlGenericErrorContext,
1237 "xmlRemoveProp : cur->parent == NULL\n");
1238#endif
1239 return(-1);
1240 }
1241 tmp = cur->parent->properties;
1242 if (tmp == cur) {
1243 cur->parent->properties = cur->next;
1244 xmlFreeProp(cur);
1245 return(0);
1246 }
1247 while (tmp != NULL) {
1248 if (tmp->next == cur) {
1249 tmp->next = cur->next;
1250 if (tmp->next != NULL)
1251 tmp->next->prev = tmp;
1252 xmlFreeProp(cur);
1253 return(0);
1254 }
1255 tmp = tmp->next;
1256 }
1257#ifdef DEBUG_TREE
1258 xmlGenericError(xmlGenericErrorContext,
1259 "xmlRemoveProp : attribute not owned by its node\n");
1260#endif
1261 return(-1);
1262}
1263
1264/**
1265 * xmlNewPI:
1266 * @name: the processing instruction name
1267 * @content: the PI content
1268 *
1269 * Creation of a processing instruction element.
1270 * Returns a pointer to the new node object.
1271 */
1272xmlNodePtr
1273xmlNewPI(const xmlChar *name, const xmlChar *content) {
1274 xmlNodePtr cur;
1275
1276 if (name == NULL) {
1277#ifdef DEBUG_TREE
1278 xmlGenericError(xmlGenericErrorContext,
1279 "xmlNewPI : name == NULL\n");
1280#endif
1281 return(NULL);
1282 }
1283
1284 /*
1285 * Allocate a new node and fill the fields.
1286 */
1287 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1288 if (cur == NULL) {
1289 xmlGenericError(xmlGenericErrorContext,
1290 "xmlNewPI : malloc failed\n");
1291 return(NULL);
1292 }
1293 memset(cur, 0, sizeof(xmlNode));
1294 cur->type = XML_PI_NODE;
1295
1296 cur->name = xmlStrdup(name);
1297 if (content != NULL) {
1298#ifndef XML_USE_BUFFER_CONTENT
1299 cur->content = xmlStrdup(content);
1300#else
1301 cur->content = xmlBufferCreateSize(0);
1302 xmlBufferSetAllocationScheme(cur->content,
1303 xmlGetBufferAllocationScheme());
1304 xmlBufferAdd(cur->content, content, -1);
1305#endif
1306 }
1307 return(cur);
1308}
1309
1310/**
1311 * xmlNewNode:
1312 * @ns: namespace if any
1313 * @name: the node name
1314 *
1315 * Creation of a new node element. @ns is optionnal (NULL).
1316 *
1317 * Returns a pointer to the new node object.
1318 */
1319xmlNodePtr
1320xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1321 xmlNodePtr cur;
1322
1323 if (name == NULL) {
1324#ifdef DEBUG_TREE
1325 xmlGenericError(xmlGenericErrorContext,
1326 "xmlNewNode : name == NULL\n");
1327#endif
1328 return(NULL);
1329 }
1330
1331 /*
1332 * Allocate a new node and fill the fields.
1333 */
1334 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1335 if (cur == NULL) {
1336 xmlGenericError(xmlGenericErrorContext,
1337 "xmlNewNode : malloc failed\n");
1338 return(NULL);
1339 }
1340 memset(cur, 0, sizeof(xmlNode));
1341 cur->type = XML_ELEMENT_NODE;
1342
1343 cur->name = xmlStrdup(name);
1344 cur->ns = ns;
1345 return(cur);
1346}
1347
1348/**
1349 * xmlNewDocNode:
1350 * @doc: the document
1351 * @ns: namespace if any
1352 * @name: the node name
1353 * @content: the XML text content if any
1354 *
1355 * Creation of a new node element within a document. @ns and @content
1356 * are optionnal (NULL).
1357 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1358 * references, but XML special chars need to be escaped first by using
1359 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1360 * need entities support.
1361 *
1362 * Returns a pointer to the new node object.
1363 */
1364xmlNodePtr
1365xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1366 const xmlChar *name, const xmlChar *content) {
1367 xmlNodePtr cur;
1368
1369 cur = xmlNewNode(ns, name);
1370 if (cur != NULL) {
1371 cur->doc = doc;
1372 if (content != NULL) {
1373 cur->children = xmlStringGetNodeList(doc, content);
1374 UPDATE_LAST_CHILD_AND_PARENT(cur)
1375 }
1376 }
1377 return(cur);
1378}
1379
1380
1381/**
1382 * xmlNewDocRawNode:
1383 * @doc: the document
1384 * @ns: namespace if any
1385 * @name: the node name
1386 * @content: the text content if any
1387 *
1388 * Creation of a new node element within a document. @ns and @content
1389 * are optionnal (NULL).
1390 *
1391 * Returns a pointer to the new node object.
1392 */
1393xmlNodePtr
1394xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1395 const xmlChar *name, const xmlChar *content) {
1396 xmlNodePtr cur;
1397
1398 cur = xmlNewNode(ns, name);
1399 if (cur != NULL) {
1400 cur->doc = doc;
1401 if (content != NULL) {
1402 cur->children = xmlNewDocText(doc, content);
1403 UPDATE_LAST_CHILD_AND_PARENT(cur)
1404 }
1405 }
1406 return(cur);
1407}
1408
1409/**
1410 * xmlNewDocFragment:
1411 * @doc: the document owning the fragment
1412 *
1413 * Creation of a new Fragment node.
1414 * Returns a pointer to the new node object.
1415 */
1416xmlNodePtr
1417xmlNewDocFragment(xmlDocPtr doc) {
1418 xmlNodePtr cur;
1419
1420 /*
1421 * Allocate a new DocumentFragment node and fill the fields.
1422 */
1423 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1424 if (cur == NULL) {
1425 xmlGenericError(xmlGenericErrorContext,
1426 "xmlNewDocFragment : malloc failed\n");
1427 return(NULL);
1428 }
1429 memset(cur, 0, sizeof(xmlNode));
1430 cur->type = XML_DOCUMENT_FRAG_NODE;
1431
1432 cur->doc = doc;
1433 return(cur);
1434}
1435
1436/**
1437 * xmlNewText:
1438 * @content: the text content
1439 *
1440 * Creation of a new text node.
1441 * Returns a pointer to the new node object.
1442 */
1443xmlNodePtr
1444xmlNewText(const xmlChar *content) {
1445 xmlNodePtr cur;
1446
1447 /*
1448 * Allocate a new node and fill the fields.
1449 */
1450 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1451 if (cur == NULL) {
1452 xmlGenericError(xmlGenericErrorContext,
1453 "xmlNewText : malloc failed\n");
1454 return(NULL);
1455 }
1456 memset(cur, 0, sizeof(xmlNode));
1457 cur->type = XML_TEXT_NODE;
1458
1459 cur->name = xmlStringText;
1460 if (content != NULL) {
1461#ifndef XML_USE_BUFFER_CONTENT
1462 cur->content = xmlStrdup(content);
1463#else
1464 cur->content = xmlBufferCreateSize(0);
1465 xmlBufferSetAllocationScheme(cur->content,
1466 xmlGetBufferAllocationScheme());
1467 xmlBufferAdd(cur->content, content, -1);
1468#endif
1469 }
1470 return(cur);
1471}
1472
1473/**
1474 * xmlNewTextChild:
1475 * @parent: the parent node
1476 * @ns: a namespace if any
1477 * @name: the name of the child
1478 * @content: the text content of the child if any.
1479 *
1480 * Creation of a new child element, added at the end of @parent children list.
1481 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1482 * a child TEXT node will be created containing the string content.
1483 *
1484 * Returns a pointer to the new node object.
1485 */
1486xmlNodePtr
1487xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1488 const xmlChar *name, const xmlChar *content) {
1489 xmlNodePtr cur, prev;
1490
1491 if (parent == NULL) {
1492#ifdef DEBUG_TREE
1493 xmlGenericError(xmlGenericErrorContext,
1494 "xmlNewTextChild : parent == NULL\n");
1495#endif
1496 return(NULL);
1497 }
1498
1499 if (name == NULL) {
1500#ifdef DEBUG_TREE
1501 xmlGenericError(xmlGenericErrorContext,
1502 "xmlNewTextChild : name == NULL\n");
1503#endif
1504 return(NULL);
1505 }
1506
1507 /*
1508 * Allocate a new node
1509 */
1510 if (ns == NULL)
1511 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1512 else
1513 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1514 if (cur == NULL) return(NULL);
1515
1516 /*
1517 * add the new element at the end of the children list.
1518 */
1519 cur->type = XML_ELEMENT_NODE;
1520 cur->parent = parent;
1521 cur->doc = parent->doc;
1522 if (parent->children == NULL) {
1523 parent->children = cur;
1524 parent->last = cur;
1525 } else {
1526 prev = parent->last;
1527 prev->next = cur;
1528 cur->prev = prev;
1529 parent->last = cur;
1530 }
1531
1532 return(cur);
1533}
1534
1535/**
1536 * xmlNewCharRef:
1537 * @doc: the document
1538 * @name: the char ref string, starting with # or "&# ... ;"
1539 *
1540 * Creation of a new character reference node.
1541 * Returns a pointer to the new node object.
1542 */
1543xmlNodePtr
1544xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1545 xmlNodePtr cur;
1546
1547 /*
1548 * Allocate a new node and fill the fields.
1549 */
1550 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1551 if (cur == NULL) {
1552 xmlGenericError(xmlGenericErrorContext,
1553 "xmlNewText : malloc failed\n");
1554 return(NULL);
1555 }
1556 memset(cur, 0, sizeof(xmlNode));
1557 cur->type = XML_ENTITY_REF_NODE;
1558
1559 cur->doc = doc;
1560 if (name[0] == '&') {
1561 int len;
1562 name++;
1563 len = xmlStrlen(name);
1564 if (name[len - 1] == ';')
1565 cur->name = xmlStrndup(name, len - 1);
1566 else
1567 cur->name = xmlStrndup(name, len);
1568 } else
1569 cur->name = xmlStrdup(name);
1570 return(cur);
1571}
1572
1573/**
1574 * xmlNewReference:
1575 * @doc: the document
1576 * @name: the reference name, or the reference string with & and ;
1577 *
1578 * Creation of a new reference node.
1579 * Returns a pointer to the new node object.
1580 */
1581xmlNodePtr
1582xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1583 xmlNodePtr cur;
1584 xmlEntityPtr ent;
1585
1586 /*
1587 * Allocate a new node and fill the fields.
1588 */
1589 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1590 if (cur == NULL) {
1591 xmlGenericError(xmlGenericErrorContext,
1592 "xmlNewText : malloc failed\n");
1593 return(NULL);
1594 }
1595 memset(cur, 0, sizeof(xmlNode));
1596 cur->type = XML_ENTITY_REF_NODE;
1597
1598 cur->doc = doc;
1599 if (name[0] == '&') {
1600 int len;
1601 name++;
1602 len = xmlStrlen(name);
1603 if (name[len - 1] == ';')
1604 cur->name = xmlStrndup(name, len - 1);
1605 else
1606 cur->name = xmlStrndup(name, len);
1607 } else
1608 cur->name = xmlStrdup(name);
1609
1610 ent = xmlGetDocEntity(doc, cur->name);
1611 if (ent != NULL) {
1612#ifndef XML_USE_BUFFER_CONTENT
1613 cur->content = ent->content;
1614#else
1615 /*
1616 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1617 * a copy of this pointer. Let's hope we don't manipulate it
1618 * later
1619 */
1620 cur->content = xmlBufferCreateSize(0);
1621 xmlBufferSetAllocationScheme(cur->content,
1622 xmlGetBufferAllocationScheme());
1623 if (ent->content != NULL)
1624 xmlBufferAdd(cur->content, ent->content, -1);
1625#endif
1626 /*
1627 * The parent pointer in entity is a Dtd pointer and thus is NOT
1628 * updated. Not sure if this is 100% correct.
1629 * -George
1630 */
1631 cur->children = (xmlNodePtr) ent;
1632 cur->last = (xmlNodePtr) ent;
1633 }
1634 return(cur);
1635}
1636
1637/**
1638 * xmlNewDocText:
1639 * @doc: the document
1640 * @content: the text content
1641 *
1642 * Creation of a new text node within a document.
1643 * Returns a pointer to the new node object.
1644 */
1645xmlNodePtr
1646xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1647 xmlNodePtr cur;
1648
1649 cur = xmlNewText(content);
1650 if (cur != NULL) cur->doc = doc;
1651 return(cur);
1652}
1653
1654/**
1655 * xmlNewTextLen:
1656 * @content: the text content
1657 * @len: the text len.
1658 *
1659 * Creation of a new text node with an extra parameter for the content's lenght
1660 * Returns a pointer to the new node object.
1661 */
1662xmlNodePtr
1663xmlNewTextLen(const xmlChar *content, int len) {
1664 xmlNodePtr cur;
1665
1666 /*
1667 * Allocate a new node and fill the fields.
1668 */
1669 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1670 if (cur == NULL) {
1671 xmlGenericError(xmlGenericErrorContext,
1672 "xmlNewText : malloc failed\n");
1673 return(NULL);
1674 }
1675 memset(cur, 0, sizeof(xmlNode));
1676 cur->type = XML_TEXT_NODE;
1677
1678 cur->name = xmlStringText;
1679 if (content != NULL) {
1680#ifndef XML_USE_BUFFER_CONTENT
1681 cur->content = xmlStrndup(content, len);
1682#else
1683 cur->content = xmlBufferCreateSize(len);
1684 xmlBufferSetAllocationScheme(cur->content,
1685 xmlGetBufferAllocationScheme());
1686 xmlBufferAdd(cur->content, content, len);
1687#endif
1688 }
1689 return(cur);
1690}
1691
1692/**
1693 * xmlNewDocTextLen:
1694 * @doc: the document
1695 * @content: the text content
1696 * @len: the text len.
1697 *
1698 * Creation of a new text node with an extra content lenght parameter. The
1699 * text node pertain to a given document.
1700 * Returns a pointer to the new node object.
1701 */
1702xmlNodePtr
1703xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1704 xmlNodePtr cur;
1705
1706 cur = xmlNewTextLen(content, len);
1707 if (cur != NULL) cur->doc = doc;
1708 return(cur);
1709}
1710
1711/**
1712 * xmlNewComment:
1713 * @content: the comment content
1714 *
1715 * Creation of a new node containing a comment.
1716 * Returns a pointer to the new node object.
1717 */
1718xmlNodePtr
1719xmlNewComment(const xmlChar *content) {
1720 xmlNodePtr cur;
1721
1722 /*
1723 * Allocate a new node and fill the fields.
1724 */
1725 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1726 if (cur == NULL) {
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlNewComment : malloc failed\n");
1729 return(NULL);
1730 }
1731 memset(cur, 0, sizeof(xmlNode));
1732 cur->type = XML_COMMENT_NODE;
1733
1734 cur->name = xmlStringComment;
1735 if (content != NULL) {
1736#ifndef XML_USE_BUFFER_CONTENT
1737 cur->content = xmlStrdup(content);
1738#else
1739 cur->content = xmlBufferCreateSize(0);
1740 xmlBufferSetAllocationScheme(cur->content,
1741 xmlGetBufferAllocationScheme());
1742 xmlBufferAdd(cur->content, content, -1);
1743#endif
1744 }
1745 return(cur);
1746}
1747
1748/**
1749 * xmlNewCDataBlock:
1750 * @doc: the document
1751 * @content: the CData block content content
1752 * @len: the length of the block
1753 *
1754 * Creation of a new node containing a CData block.
1755 * Returns a pointer to the new node object.
1756 */
1757xmlNodePtr
1758xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1759 xmlNodePtr cur;
1760
1761 /*
1762 * Allocate a new node and fill the fields.
1763 */
1764 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1765 if (cur == NULL) {
1766 xmlGenericError(xmlGenericErrorContext,
1767 "xmlNewCDataBlock : malloc failed\n");
1768 return(NULL);
1769 }
1770 memset(cur, 0, sizeof(xmlNode));
1771 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001772 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001773
1774 if (content != NULL) {
1775#ifndef XML_USE_BUFFER_CONTENT
1776 cur->content = xmlStrndup(content, len);
1777#else
1778 cur->content = xmlBufferCreateSize(len);
1779 xmlBufferSetAllocationScheme(cur->content,
1780 xmlGetBufferAllocationScheme());
1781 xmlBufferAdd(cur->content, content, len);
1782#endif
1783 }
1784 return(cur);
1785}
1786
1787/**
1788 * xmlNewDocComment:
1789 * @doc: the document
1790 * @content: the comment content
1791 *
1792 * Creation of a new node containing a commentwithin a document.
1793 * Returns a pointer to the new node object.
1794 */
1795xmlNodePtr
1796xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1797 xmlNodePtr cur;
1798
1799 cur = xmlNewComment(content);
1800 if (cur != NULL) cur->doc = doc;
1801 return(cur);
1802}
1803
1804/**
1805 * xmlSetTreeDoc:
1806 * @tree: the top element
1807 * @doc: the document
1808 *
1809 * update all nodes under the tree to point to the right document
1810 */
1811void
1812xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001813 xmlAttrPtr prop;
1814
Owen Taylor3473f882001-02-23 17:55:21 +00001815 if (tree == NULL)
1816 return;
1817 if (tree->type == XML_ENTITY_DECL)
1818 return;
1819 if (tree->doc != doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001820 prop = tree->properties;
1821 while (prop != NULL) {
1822 prop->doc = doc;
1823 xmlSetListDoc(prop->children, doc);
1824 prop = prop->next;
1825 }
Owen Taylor3473f882001-02-23 17:55:21 +00001826 if (tree->children != NULL)
1827 xmlSetListDoc(tree->children, doc);
1828 tree->doc = doc;
1829 }
1830}
1831
1832/**
1833 * xmlSetListDoc:
1834 * @tree: the first element
1835 * @doc: the document
1836 *
1837 * update all nodes in the list to point to the right document
1838 */
1839void
1840xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1841 xmlNodePtr cur;
1842
1843 if (list == NULL)
1844 return;
1845 cur = list;
1846 while (cur != NULL) {
1847 if (cur->doc != doc)
1848 xmlSetTreeDoc(cur, doc);
1849 cur = cur->next;
1850 }
1851}
1852
1853
1854/**
1855 * xmlNewChild:
1856 * @parent: the parent node
1857 * @ns: a namespace if any
1858 * @name: the name of the child
1859 * @content: the XML content of the child if any.
1860 *
1861 * Creation of a new child element, added at the end of @parent children list.
1862 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1863 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1864 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1865 * references, but XML special chars need to be escaped first by using
1866 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1867 * support is not needed.
1868 *
1869 * Returns a pointer to the new node object.
1870 */
1871xmlNodePtr
1872xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1873 const xmlChar *name, const xmlChar *content) {
1874 xmlNodePtr cur, prev;
1875
1876 if (parent == NULL) {
1877#ifdef DEBUG_TREE
1878 xmlGenericError(xmlGenericErrorContext,
1879 "xmlNewChild : parent == NULL\n");
1880#endif
1881 return(NULL);
1882 }
1883
1884 if (name == NULL) {
1885#ifdef DEBUG_TREE
1886 xmlGenericError(xmlGenericErrorContext,
1887 "xmlNewChild : name == NULL\n");
1888#endif
1889 return(NULL);
1890 }
1891
1892 /*
1893 * Allocate a new node
1894 */
1895 if (ns == NULL)
1896 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1897 else
1898 cur = xmlNewDocNode(parent->doc, ns, name, content);
1899 if (cur == NULL) return(NULL);
1900
1901 /*
1902 * add the new element at the end of the children list.
1903 */
1904 cur->type = XML_ELEMENT_NODE;
1905 cur->parent = parent;
1906 cur->doc = parent->doc;
1907 if (parent->children == NULL) {
1908 parent->children = cur;
1909 parent->last = cur;
1910 } else {
1911 prev = parent->last;
1912 prev->next = cur;
1913 cur->prev = prev;
1914 parent->last = cur;
1915 }
1916
1917 return(cur);
1918}
1919
1920/**
1921 * xmlAddNextSibling:
1922 * @cur: the child node
1923 * @elem: the new node
1924 *
1925 * Add a new element @elem as the next siblings of @cur
1926 * If the new element was already inserted in a document it is
1927 * first unlinked from its existing context.
1928 * As a result of text merging @elem may be freed.
1929 *
1930 * Returns the new element or NULL in case of error.
1931 */
1932xmlNodePtr
1933xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1934 if (cur == NULL) {
1935#ifdef DEBUG_TREE
1936 xmlGenericError(xmlGenericErrorContext,
1937 "xmlAddNextSibling : cur == NULL\n");
1938#endif
1939 return(NULL);
1940 }
1941 if (elem == NULL) {
1942#ifdef DEBUG_TREE
1943 xmlGenericError(xmlGenericErrorContext,
1944 "xmlAddNextSibling : elem == NULL\n");
1945#endif
1946 return(NULL);
1947 }
1948
1949 xmlUnlinkNode(elem);
1950
1951 if (elem->type == XML_TEXT_NODE) {
1952 if (cur->type == XML_TEXT_NODE) {
1953#ifndef XML_USE_BUFFER_CONTENT
1954 xmlNodeAddContent(cur, elem->content);
1955#else
1956 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1957#endif
1958 xmlFreeNode(elem);
1959 return(cur);
1960 }
1961 if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
1962#ifndef XML_USE_BUFFER_CONTENT
1963 xmlChar *tmp;
1964
1965 tmp = xmlStrdup(elem->content);
1966 tmp = xmlStrcat(tmp, cur->next->content);
1967 xmlNodeSetContent(cur->next, tmp);
1968 xmlFree(tmp);
1969#else
1970 xmlBufferAddHead(cur->next->content,
1971 xmlBufferContent(elem->content),
1972 xmlBufferLength(elem->content));
1973#endif
1974 xmlFreeNode(elem);
1975 return(cur->next);
1976 }
1977 }
1978
1979 if (elem->doc != cur->doc) {
1980 xmlSetTreeDoc(elem, cur->doc);
1981 }
1982 elem->parent = cur->parent;
1983 elem->prev = cur;
1984 elem->next = cur->next;
1985 cur->next = elem;
1986 if (elem->next != NULL)
1987 elem->next->prev = elem;
1988 if ((elem->parent != NULL) && (elem->parent->last == cur))
1989 elem->parent->last = elem;
1990 return(elem);
1991}
1992
1993/**
1994 * xmlAddPrevSibling:
1995 * @cur: the child node
1996 * @elem: the new node
1997 *
1998 * Add a new element @elem as the previous siblings of @cur
1999 * merging adjacent TEXT nodes (@elem may be freed)
2000 * If the new element was already inserted in a document it is
2001 * first unlinked from its existing context.
2002 *
2003 * Returns the new element or NULL in case of error.
2004 */
2005xmlNodePtr
2006xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2007 if (cur == NULL) {
2008#ifdef DEBUG_TREE
2009 xmlGenericError(xmlGenericErrorContext,
2010 "xmlAddPrevSibling : cur == NULL\n");
2011#endif
2012 return(NULL);
2013 }
2014 if (elem == NULL) {
2015#ifdef DEBUG_TREE
2016 xmlGenericError(xmlGenericErrorContext,
2017 "xmlAddPrevSibling : elem == NULL\n");
2018#endif
2019 return(NULL);
2020 }
2021
2022 xmlUnlinkNode(elem);
2023
2024 if (elem->type == XML_TEXT_NODE) {
2025 if (cur->type == XML_TEXT_NODE) {
2026#ifndef XML_USE_BUFFER_CONTENT
2027 xmlChar *tmp;
2028
2029 tmp = xmlStrdup(elem->content);
2030 tmp = xmlStrcat(tmp, cur->content);
2031 xmlNodeSetContent(cur, tmp);
2032 xmlFree(tmp);
2033#else
2034 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2035 xmlBufferLength(elem->content));
2036#endif
2037 xmlFreeNode(elem);
2038 return(cur);
2039 }
2040 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
2041#ifndef XML_USE_BUFFER_CONTENT
2042 xmlNodeAddContent(cur->prev, elem->content);
2043#else
2044 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2045#endif
2046 xmlFreeNode(elem);
2047 return(cur->prev);
2048 }
2049 }
2050
2051 if (elem->doc != cur->doc) {
2052 xmlSetTreeDoc(elem, cur->doc);
2053 }
2054 elem->parent = cur->parent;
2055 elem->next = cur;
2056 elem->prev = cur->prev;
2057 cur->prev = elem;
2058 if (elem->prev != NULL)
2059 elem->prev->next = elem;
2060 if ((elem->parent != NULL) && (elem->parent->children == cur))
2061 elem->parent->children = elem;
2062 return(elem);
2063}
2064
2065/**
2066 * xmlAddSibling:
2067 * @cur: the child node
2068 * @elem: the new node
2069 *
2070 * Add a new element @elem to the list of siblings of @cur
2071 * merging adjacent TEXT nodes (@elem may be freed)
2072 * If the new element was already inserted in a document it is
2073 * first unlinked from its existing context.
2074 *
2075 * Returns the new element or NULL in case of error.
2076 */
2077xmlNodePtr
2078xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2079 xmlNodePtr parent;
2080
2081 if (cur == NULL) {
2082#ifdef DEBUG_TREE
2083 xmlGenericError(xmlGenericErrorContext,
2084 "xmlAddSibling : cur == NULL\n");
2085#endif
2086 return(NULL);
2087 }
2088
2089 if (elem == NULL) {
2090#ifdef DEBUG_TREE
2091 xmlGenericError(xmlGenericErrorContext,
2092 "xmlAddSibling : elem == NULL\n");
2093#endif
2094 return(NULL);
2095 }
2096
2097 /*
2098 * Constant time is we can rely on the ->parent->last to find
2099 * the last sibling.
2100 */
2101 if ((cur->parent != NULL) &&
2102 (cur->parent->children != NULL) &&
2103 (cur->parent->last != NULL) &&
2104 (cur->parent->last->next == NULL)) {
2105 cur = cur->parent->last;
2106 } else {
2107 while (cur->next != NULL) cur = cur->next;
2108 }
2109
2110 xmlUnlinkNode(elem);
2111
2112 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2113#ifndef XML_USE_BUFFER_CONTENT
2114 xmlNodeAddContent(cur, elem->content);
2115#else
2116 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2117#endif
2118 xmlFreeNode(elem);
2119 return(cur);
2120 }
2121
2122 if (elem->doc != cur->doc) {
2123 xmlSetTreeDoc(elem, cur->doc);
2124 }
2125 parent = cur->parent;
2126 elem->prev = cur;
2127 elem->next = NULL;
2128 elem->parent = parent;
2129 cur->next = elem;
2130 if (parent != NULL)
2131 parent->last = elem;
2132
2133 return(elem);
2134}
2135
2136/**
2137 * xmlAddChildList:
2138 * @parent: the parent node
2139 * @cur: the first node in the list
2140 *
2141 * Add a list of node at the end of the child list of the parent
2142 * merging adjacent TEXT nodes (@cur may be freed)
2143 *
2144 * Returns the last child or NULL in case of error.
2145 */
2146xmlNodePtr
2147xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2148 xmlNodePtr prev;
2149
2150 if (parent == NULL) {
2151#ifdef DEBUG_TREE
2152 xmlGenericError(xmlGenericErrorContext,
2153 "xmlAddChild : parent == NULL\n");
2154#endif
2155 return(NULL);
2156 }
2157
2158 if (cur == NULL) {
2159#ifdef DEBUG_TREE
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlAddChild : child == NULL\n");
2162#endif
2163 return(NULL);
2164 }
2165
2166 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2167 (cur->doc != parent->doc)) {
2168#ifdef DEBUG_TREE
2169 xmlGenericError(xmlGenericErrorContext,
2170 "Elements moved to a different document\n");
2171#endif
2172 }
2173
2174 /*
2175 * add the first element at the end of the children list.
2176 */
2177 if (parent->children == NULL) {
2178 parent->children = cur;
2179 } else {
2180 /*
2181 * If cur and parent->last both are TEXT nodes, then merge them.
2182 */
2183 if ((cur->type == XML_TEXT_NODE) &&
2184 (parent->last->type == XML_TEXT_NODE) &&
2185 (cur->name == parent->last->name)) {
2186#ifndef XML_USE_BUFFER_CONTENT
2187 xmlNodeAddContent(parent->last, cur->content);
2188#else
2189 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2190#endif
2191 /*
2192 * if it's the only child, nothing more to be done.
2193 */
2194 if (cur->next == NULL) {
2195 xmlFreeNode(cur);
2196 return(parent->last);
2197 }
2198 prev = cur;
2199 cur = cur->next;
2200 xmlFreeNode(prev);
2201 }
2202 prev = parent->last;
2203 prev->next = cur;
2204 cur->prev = prev;
2205 }
2206 while (cur->next != NULL) {
2207 cur->parent = parent;
2208 if (cur->doc != parent->doc) {
2209 xmlSetTreeDoc(cur, parent->doc);
2210 }
2211 cur = cur->next;
2212 }
2213 cur->parent = parent;
2214 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2215 parent->last = cur;
2216
2217 return(cur);
2218}
2219
2220/**
2221 * xmlAddChild:
2222 * @parent: the parent node
2223 * @cur: the child node
2224 *
2225 * Add a new child element, to @parent, at the end of the child list
2226 * merging adjacent TEXT nodes (in which case @cur is freed)
2227 * Returns the child or NULL in case of error.
2228 */
2229xmlNodePtr
2230xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2231 xmlNodePtr prev;
2232
2233 if (parent == NULL) {
2234#ifdef DEBUG_TREE
2235 xmlGenericError(xmlGenericErrorContext,
2236 "xmlAddChild : parent == NULL\n");
2237#endif
2238 return(NULL);
2239 }
2240
2241 if (cur == NULL) {
2242#ifdef DEBUG_TREE
2243 xmlGenericError(xmlGenericErrorContext,
2244 "xmlAddChild : child == NULL\n");
2245#endif
2246 return(NULL);
2247 }
2248
Owen Taylor3473f882001-02-23 17:55:21 +00002249 /*
2250 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
2251 * or with parent->content if parent->content != NULL.
2252 * cur is then freed.
2253 */
2254 if (cur->type == XML_TEXT_NODE) {
2255 if (((parent->type == XML_ELEMENT_NODE) ||
2256 (parent->type == XML_TEXT_NODE)) &&
2257 (parent->content != NULL)) {
2258#ifndef XML_USE_BUFFER_CONTENT
2259 xmlNodeAddContent(parent, cur->content);
2260#else
2261 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2262#endif
2263 xmlFreeNode(cur);
2264 return(parent);
2265 }
2266 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2267 (parent->last->name == cur->name)) {
2268#ifndef XML_USE_BUFFER_CONTENT
2269 xmlNodeAddContent(parent->last, cur->content);
2270#else
2271 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2272#endif
2273 xmlFreeNode(cur);
2274 return(parent->last);
2275 }
2276 }
2277
2278 /*
2279 * add the new element at the end of the children list.
2280 */
2281 cur->parent = parent;
2282 if (cur->doc != parent->doc) {
2283 xmlSetTreeDoc(cur, parent->doc);
2284 }
2285
2286 /*
2287 * Handle the case where parent->content != NULL, in that case it will
2288 * create a intermediate TEXT node.
2289 */
2290 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2291 (parent->content != NULL)) {
2292 xmlNodePtr text;
2293
2294#ifndef XML_USE_BUFFER_CONTENT
2295 text = xmlNewDocText(parent->doc, parent->content);
2296#else
2297 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2298#endif
2299 if (text != NULL) {
2300 text->next = parent->children;
2301 if (text->next != NULL)
2302 text->next->prev = text;
2303 parent->children = text;
2304 UPDATE_LAST_CHILD_AND_PARENT(parent)
2305#ifndef XML_USE_BUFFER_CONTENT
2306 xmlFree(parent->content);
2307#else
2308 xmlBufferFree(parent->content);
2309#endif
2310 parent->content = NULL;
2311 }
2312 }
2313 if (parent->children == NULL) {
2314 parent->children = cur;
2315 parent->last = cur;
2316 } else {
2317 prev = parent->last;
2318 prev->next = cur;
2319 cur->prev = prev;
2320 parent->last = cur;
2321 }
2322
2323 return(cur);
2324}
2325
2326/**
2327 * xmlGetLastChild:
2328 * @parent: the parent node
2329 *
2330 * Search the last child of a node.
2331 * Returns the last child or NULL if none.
2332 */
2333xmlNodePtr
2334xmlGetLastChild(xmlNodePtr parent) {
2335 if (parent == NULL) {
2336#ifdef DEBUG_TREE
2337 xmlGenericError(xmlGenericErrorContext,
2338 "xmlGetLastChild : parent == NULL\n");
2339#endif
2340 return(NULL);
2341 }
2342 return(parent->last);
2343}
2344
2345/**
2346 * xmlFreeNodeList:
2347 * @cur: the first node in the list
2348 *
2349 * Free a node and all its siblings, this is a recursive behaviour, all
2350 * the children are freed too.
2351 */
2352void
2353xmlFreeNodeList(xmlNodePtr cur) {
2354 xmlNodePtr next;
2355 if (cur == NULL) {
2356#ifdef DEBUG_TREE
2357 xmlGenericError(xmlGenericErrorContext,
2358 "xmlFreeNodeList : node == NULL\n");
2359#endif
2360 return;
2361 }
2362 while (cur != NULL) {
2363 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002364 /* unroll to speed up freeing the document */
2365 if (cur->type != XML_DTD_NODE) {
2366 if ((cur->children != NULL) &&
2367 (cur->type != XML_ENTITY_REF_NODE))
2368 xmlFreeNodeList(cur->children);
2369 if (cur->properties != NULL)
2370 xmlFreePropList(cur->properties);
2371 if (cur->type != XML_ENTITY_REF_NODE)
2372#ifndef XML_USE_BUFFER_CONTENT
2373 if (cur->content != NULL) xmlFree(cur->content);
2374#else
2375 if (cur->content != NULL) xmlBufferFree(cur->content);
2376#endif
Daniel Veillard19e96c32001-07-09 10:32:59 +00002377 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002378 /*
2379 * When a node is a text node or a comment, it uses a global static
2380 * variable for the name of the node.
2381 *
2382 * The xmlStrEqual comparisons need to be done when (happened with
2383 * XML::libXML and XML::libXSLT) the library is included twice
2384 * statically in the binary and a tree allocated by one occurent
2385 * of the lib gets freed by the other occurence, in this case
2386 * the string addresses compare are not sufficient.
2387 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002388 if ((cur->name != NULL) &&
2389 (cur->name != xmlStringText) &&
2390 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002391 (cur->name != xmlStringComment)) {
2392 if (cur->type == XML_TEXT_NODE) {
2393 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2394 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2395 xmlFree((char *) cur->name);
2396 } else if (cur->type == XML_COMMENT_NODE) {
2397 if (!xmlStrEqual(cur->name, xmlStringComment))
2398 xmlFree((char *) cur->name);
2399 } else
2400 xmlFree((char *) cur->name);
2401 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002402 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002403 xmlFree(cur);
2404 }
Owen Taylor3473f882001-02-23 17:55:21 +00002405 cur = next;
2406 }
2407}
2408
2409/**
2410 * xmlFreeNode:
2411 * @cur: the node
2412 *
2413 * Free a node, this is a recursive behaviour, all the children are freed too.
2414 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2415 */
2416void
2417xmlFreeNode(xmlNodePtr cur) {
2418 if (cur == NULL) {
2419#ifdef DEBUG_TREE
2420 xmlGenericError(xmlGenericErrorContext,
2421 "xmlFreeNode : node == NULL\n");
2422#endif
2423 return;
2424 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002425 /* use xmlFreeDtd for DTD nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002426 if (cur->type == XML_DTD_NODE)
2427 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002428 if ((cur->children != NULL) &&
2429 (cur->type != XML_ENTITY_REF_NODE))
2430 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002431 if (cur->properties != NULL)
2432 xmlFreePropList(cur->properties);
Owen Taylor3473f882001-02-23 17:55:21 +00002433 if (cur->type != XML_ENTITY_REF_NODE)
2434#ifndef XML_USE_BUFFER_CONTENT
2435 if (cur->content != NULL) xmlFree(cur->content);
2436#else
2437 if (cur->content != NULL) xmlBufferFree(cur->content);
2438#endif
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);
2759 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2760#ifndef XML_USE_BUFFER_CONTENT
2761 ret->content = xmlStrdup(node->content);
2762#else
2763 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2764 xmlBufferSetAllocationScheme(ret->content,
2765 xmlGetBufferAllocationScheme());
2766 xmlBufferAdd(ret->content,
2767 xmlBufferContent(node->content),
2768 xmlBufferLength(node->content));
2769#endif
2770 }
2771 if (parent != NULL)
2772 xmlAddChild(parent, ret);
2773
2774 if (!recursive) return(ret);
2775 if (node->nsDef != NULL)
2776 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2777
2778 if (node->ns != NULL) {
2779 xmlNsPtr ns;
2780
2781 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2782 if (ns == NULL) {
2783 /*
2784 * Humm, we are copying an element whose namespace is defined
2785 * out of the new tree scope. Search it in the original tree
2786 * and add it at the top of the new tree
2787 */
2788 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2789 if (ns != NULL) {
2790 xmlNodePtr root = ret;
2791
2792 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002793 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002794 }
2795 } else {
2796 /*
2797 * reference the existing namespace definition in our own tree.
2798 */
2799 ret->ns = ns;
2800 }
2801 }
2802 if (node->properties != NULL)
2803 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002804 if (node->type == XML_ENTITY_REF_NODE) {
2805 if ((doc == NULL) || (node->doc != doc)) {
2806 /*
2807 * The copied node will go into a separate document, so
2808 * to havoid dandling references to the ENTITY_DECL node
2809 * we cannot keep the reference. Try to find it in the
2810 * target document.
2811 */
2812 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2813 } else {
2814 ret->children = node->children;
2815 }
2816 } else if (node->children != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002817 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
2818 UPDATE_LAST_CHILD_AND_PARENT(ret)
2819 return(ret);
2820}
2821
2822static xmlNodePtr
2823xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2824 xmlNodePtr ret = NULL;
2825 xmlNodePtr p = NULL,q;
2826
2827 while (node != NULL) {
Daniel Veillardb33c2012001-04-25 12:59:04 +00002828 if( node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002829 if (doc == NULL) {
2830 node = node->next;
2831 continue;
2832 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002833 if (doc->intSubset == NULL) {
2834 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2835 q->doc = doc;
2836 q->parent = parent;
2837 doc->intSubset = (xmlDtdPtr) q;
2838 } else {
2839 q = (xmlNodePtr) doc->intSubset;
2840 }
2841 } else
2842 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002843 if (ret == NULL) {
2844 q->prev = NULL;
2845 ret = p = q;
2846 } else {
2847 p->next = q;
2848 q->prev = p;
2849 p = q;
2850 }
2851 node = node->next;
2852 }
2853 return(ret);
2854}
2855
2856/**
2857 * xmlCopyNode:
2858 * @node: the node
2859 * @recursive: if 1 do a recursive copy.
2860 *
2861 * Do a copy of the node.
2862 *
2863 * Returns: a new xmlNodePtr, or NULL in case of error.
2864 */
2865xmlNodePtr
2866xmlCopyNode(xmlNodePtr node, int recursive) {
2867 xmlNodePtr ret;
2868
2869 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2870 return(ret);
2871}
2872
2873/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002874 * xmlDocCopyNode:
2875 * @node: the node
2876 * @recursive: if 1 do a recursive copy.
2877 *
2878 * Do a copy of the node to a given document.
2879 *
2880 * Returns: a new xmlNodePtr, or NULL in case of error.
2881 */
2882xmlNodePtr
2883xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int recursive) {
2884 xmlNodePtr ret;
2885
2886 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2887 return(ret);
2888}
2889
2890/**
Owen Taylor3473f882001-02-23 17:55:21 +00002891 * xmlCopyNodeList:
2892 * @node: the first node in the list.
2893 *
2894 * Do a recursive copy of the node list.
2895 *
2896 * Returns: a new xmlNodePtr, or NULL in case of error.
2897 */
2898xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2899 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2900 return(ret);
2901}
2902
2903/**
2904 * xmlCopyElement:
2905 * @elem: the element
2906 *
2907 * Do a copy of the element definition.
2908 *
2909 * Returns: a new xmlElementPtr, or NULL in case of error.
2910xmlElementPtr
2911xmlCopyElement(xmlElementPtr elem) {
2912 xmlElementPtr ret;
2913
2914 if (elem == NULL) return(NULL);
2915 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2916 if (ret == NULL) return(NULL);
2917 if (!recursive) return(ret);
2918 if (elem->properties != NULL)
2919 ret->properties = xmlCopyPropList(elem->properties);
2920
2921 if (elem->nsDef != NULL)
2922 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
2923 if (elem->children != NULL)
2924 ret->children = xmlCopyElementList(elem->children);
2925 return(ret);
2926}
2927 */
2928
2929/**
2930 * xmlCopyDtd:
2931 * @dtd: the dtd
2932 *
2933 * Do a copy of the dtd.
2934 *
2935 * Returns: a new xmlDtdPtr, or NULL in case of error.
2936 */
2937xmlDtdPtr
2938xmlCopyDtd(xmlDtdPtr dtd) {
2939 xmlDtdPtr ret;
2940
2941 if (dtd == NULL) return(NULL);
2942 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2943 if (ret == NULL) return(NULL);
2944 if (dtd->entities != NULL)
2945 ret->entities = (void *) xmlCopyEntitiesTable(
2946 (xmlEntitiesTablePtr) dtd->entities);
2947 if (dtd->notations != NULL)
2948 ret->notations = (void *) xmlCopyNotationTable(
2949 (xmlNotationTablePtr) dtd->notations);
2950 if (dtd->elements != NULL)
2951 ret->elements = (void *) xmlCopyElementTable(
2952 (xmlElementTablePtr) dtd->elements);
2953 if (dtd->attributes != NULL)
2954 ret->attributes = (void *) xmlCopyAttributeTable(
2955 (xmlAttributeTablePtr) dtd->attributes);
2956 return(ret);
2957}
2958
2959/**
2960 * xmlCopyDoc:
2961 * @doc: the document
2962 * @recursive: if 1 do a recursive copy.
2963 *
2964 * Do a copy of the document info. If recursive, the content tree will
2965 * be copied too as well as Dtd, namespaces and entities.
2966 *
2967 * Returns: a new xmlDocPtr, or NULL in case of error.
2968 */
2969xmlDocPtr
2970xmlCopyDoc(xmlDocPtr doc, int recursive) {
2971 xmlDocPtr ret;
2972
2973 if (doc == NULL) return(NULL);
2974 ret = xmlNewDoc(doc->version);
2975 if (ret == NULL) return(NULL);
2976 if (doc->name != NULL)
2977 ret->name = xmlMemStrdup(doc->name);
2978 if (doc->encoding != NULL)
2979 ret->encoding = xmlStrdup(doc->encoding);
2980 ret->charset = doc->charset;
2981 ret->compression = doc->compression;
2982 ret->standalone = doc->standalone;
2983 if (!recursive) return(ret);
2984
Daniel Veillardb33c2012001-04-25 12:59:04 +00002985 ret->last = NULL;
2986 ret->children = NULL;
2987 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002988 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002989 ret->intSubset->doc = ret;
2990 ret->intSubset->parent = ret;
2991 }
Owen Taylor3473f882001-02-23 17:55:21 +00002992 if (doc->oldNs != NULL)
2993 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2994 if (doc->children != NULL) {
2995 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002996
2997 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2998 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002999 ret->last = NULL;
3000 tmp = ret->children;
3001 while (tmp != NULL) {
3002 if (tmp->next == NULL)
3003 ret->last = tmp;
3004 tmp = tmp->next;
3005 }
3006 }
3007 return(ret);
3008}
3009
3010/************************************************************************
3011 * *
3012 * Content access functions *
3013 * *
3014 ************************************************************************/
3015
3016/**
3017 * xmlDocGetRootElement:
3018 * @doc: the document
3019 *
3020 * Get the root element of the document (doc->children is a list
3021 * containing possibly comments, PIs, etc ...).
3022 *
3023 * Returns the xmlNodePtr for the root or NULL
3024 */
3025xmlNodePtr
3026xmlDocGetRootElement(xmlDocPtr doc) {
3027 xmlNodePtr ret;
3028
3029 if (doc == NULL) return(NULL);
3030 ret = doc->children;
3031 while (ret != NULL) {
3032 if (ret->type == XML_ELEMENT_NODE)
3033 return(ret);
3034 ret = ret->next;
3035 }
3036 return(ret);
3037}
3038
3039/**
3040 * xmlDocSetRootElement:
3041 * @doc: the document
3042 * @root: the new document root element
3043 *
3044 * Set the root element of the document (doc->children is a list
3045 * containing possibly comments, PIs, etc ...).
3046 *
3047 * Returns the old root element if any was found
3048 */
3049xmlNodePtr
3050xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3051 xmlNodePtr old = NULL;
3052
3053 if (doc == NULL) return(NULL);
3054 old = doc->children;
3055 while (old != NULL) {
3056 if (old->type == XML_ELEMENT_NODE)
3057 break;
3058 old = old->next;
3059 }
3060 if (old == NULL) {
3061 if (doc->children == NULL) {
3062 doc->children = root;
3063 doc->last = root;
3064 } else {
3065 xmlAddSibling(doc->children, root);
3066 }
3067 } else {
3068 xmlReplaceNode(old, root);
3069 }
3070 return(old);
3071}
3072
3073/**
3074 * xmlNodeSetLang:
3075 * @cur: the node being changed
3076 * @lang: the langage description
3077 *
3078 * Set the language of a node, i.e. the values of the xml:lang
3079 * attribute.
3080 */
3081void
3082xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3083 if (cur == NULL) return;
3084 switch(cur->type) {
3085 case XML_TEXT_NODE:
3086 case XML_CDATA_SECTION_NODE:
3087 case XML_COMMENT_NODE:
3088 case XML_DOCUMENT_NODE:
3089 case XML_DOCUMENT_TYPE_NODE:
3090 case XML_DOCUMENT_FRAG_NODE:
3091 case XML_NOTATION_NODE:
3092 case XML_HTML_DOCUMENT_NODE:
3093 case XML_DTD_NODE:
3094 case XML_ELEMENT_DECL:
3095 case XML_ATTRIBUTE_DECL:
3096 case XML_ENTITY_DECL:
3097 case XML_PI_NODE:
3098 case XML_ENTITY_REF_NODE:
3099 case XML_ENTITY_NODE:
3100 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003101#ifdef LIBXML_DOCB_ENABLED
3102 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003103#endif
3104 case XML_XINCLUDE_START:
3105 case XML_XINCLUDE_END:
3106 return;
3107 case XML_ELEMENT_NODE:
3108 case XML_ATTRIBUTE_NODE:
3109 break;
3110 }
3111 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3112}
3113
3114/**
3115 * xmlNodeGetLang:
3116 * @cur: the node being checked
3117 *
3118 * Searches the language of a node, i.e. the values of the xml:lang
3119 * attribute or the one carried by the nearest ancestor.
3120 *
3121 * Returns a pointer to the lang value, or NULL if not found
3122 * It's up to the caller to free the memory.
3123 */
3124xmlChar *
3125xmlNodeGetLang(xmlNodePtr cur) {
3126 xmlChar *lang;
3127
3128 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003129 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003130 if (lang != NULL)
3131 return(lang);
3132 cur = cur->parent;
3133 }
3134 return(NULL);
3135}
3136
3137
3138/**
3139 * xmlNodeSetSpacePreserve:
3140 * @cur: the node being changed
3141 * @val: the xml:space value ("0": default, 1: "preserve")
3142 *
3143 * Set (or reset) the space preserving behaviour of a node, i.e. the
3144 * value of the xml:space attribute.
3145 */
3146void
3147xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3148 if (cur == NULL) return;
3149 switch(cur->type) {
3150 case XML_TEXT_NODE:
3151 case XML_CDATA_SECTION_NODE:
3152 case XML_COMMENT_NODE:
3153 case XML_DOCUMENT_NODE:
3154 case XML_DOCUMENT_TYPE_NODE:
3155 case XML_DOCUMENT_FRAG_NODE:
3156 case XML_NOTATION_NODE:
3157 case XML_HTML_DOCUMENT_NODE:
3158 case XML_DTD_NODE:
3159 case XML_ELEMENT_DECL:
3160 case XML_ATTRIBUTE_DECL:
3161 case XML_ENTITY_DECL:
3162 case XML_PI_NODE:
3163 case XML_ENTITY_REF_NODE:
3164 case XML_ENTITY_NODE:
3165 case XML_NAMESPACE_DECL:
3166 case XML_XINCLUDE_START:
3167 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003168#ifdef LIBXML_DOCB_ENABLED
3169 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003170#endif
3171 return;
3172 case XML_ELEMENT_NODE:
3173 case XML_ATTRIBUTE_NODE:
3174 break;
3175 }
3176 switch (val) {
3177 case 0:
3178 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3179 break;
3180 case 1:
3181 xmlSetProp(cur, BAD_CAST "xml:space",
3182 BAD_CAST "preserve");
3183 break;
3184 }
3185}
3186
3187/**
3188 * xmlNodeGetSpacePreserve:
3189 * @cur: the node being checked
3190 *
3191 * Searches the space preserving behaviour of a node, i.e. the values
3192 * of the xml:space attribute or the one carried by the nearest
3193 * ancestor.
3194 *
3195 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
3196 */
3197int
3198xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3199 xmlChar *space;
3200
3201 while (cur != NULL) {
3202 space = xmlGetProp(cur, BAD_CAST "xml:space");
3203 if (space != NULL) {
3204 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3205 xmlFree(space);
3206 return(1);
3207 }
3208 if (xmlStrEqual(space, BAD_CAST "default")) {
3209 xmlFree(space);
3210 return(0);
3211 }
3212 xmlFree(space);
3213 }
3214 cur = cur->parent;
3215 }
3216 return(-1);
3217}
3218
3219/**
3220 * xmlNodeSetName:
3221 * @cur: the node being changed
3222 * @name: the new tag name
3223 *
3224 * Set (or reset) the name of a node.
3225 */
3226void
3227xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3228 if (cur == NULL) return;
3229 if (name == NULL) return;
3230 switch(cur->type) {
3231 case XML_TEXT_NODE:
3232 case XML_CDATA_SECTION_NODE:
3233 case XML_COMMENT_NODE:
3234 case XML_DOCUMENT_TYPE_NODE:
3235 case XML_DOCUMENT_FRAG_NODE:
3236 case XML_NOTATION_NODE:
3237 case XML_HTML_DOCUMENT_NODE:
3238 case XML_NAMESPACE_DECL:
3239 case XML_XINCLUDE_START:
3240 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003241#ifdef LIBXML_DOCB_ENABLED
3242 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003243#endif
3244 return;
3245 case XML_ELEMENT_NODE:
3246 case XML_ATTRIBUTE_NODE:
3247 case XML_PI_NODE:
3248 case XML_ENTITY_REF_NODE:
3249 case XML_ENTITY_NODE:
3250 case XML_DTD_NODE:
3251 case XML_DOCUMENT_NODE:
3252 case XML_ELEMENT_DECL:
3253 case XML_ATTRIBUTE_DECL:
3254 case XML_ENTITY_DECL:
3255 break;
3256 }
3257 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3258 cur->name = xmlStrdup(name);
3259}
3260
3261/**
3262 * xmlNodeSetBase:
3263 * @cur: the node being changed
3264 * @uri: the new base URI
3265 *
3266 * Set (or reset) the base URI of a node, i.e. the value of the
3267 * xml:base attribute.
3268 */
3269void
3270xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3271 if (cur == NULL) return;
3272 switch(cur->type) {
3273 case XML_TEXT_NODE:
3274 case XML_CDATA_SECTION_NODE:
3275 case XML_COMMENT_NODE:
3276 case XML_DOCUMENT_NODE:
3277 case XML_DOCUMENT_TYPE_NODE:
3278 case XML_DOCUMENT_FRAG_NODE:
3279 case XML_NOTATION_NODE:
3280 case XML_HTML_DOCUMENT_NODE:
3281 case XML_DTD_NODE:
3282 case XML_ELEMENT_DECL:
3283 case XML_ATTRIBUTE_DECL:
3284 case XML_ENTITY_DECL:
3285 case XML_PI_NODE:
3286 case XML_ENTITY_REF_NODE:
3287 case XML_ENTITY_NODE:
3288 case XML_NAMESPACE_DECL:
3289 case XML_XINCLUDE_START:
3290 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003291#ifdef LIBXML_DOCB_ENABLED
3292 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003293#endif
3294 return;
3295 case XML_ELEMENT_NODE:
3296 case XML_ATTRIBUTE_NODE:
3297 break;
3298 }
3299 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3300}
3301
3302/**
Owen Taylor3473f882001-02-23 17:55:21 +00003303 * xmlNodeGetBase:
3304 * @doc: the document the node pertains to
3305 * @cur: the node being checked
3306 *
3307 * Searches for the BASE URL. The code should work on both XML
3308 * and HTML document even if base mechanisms are completely different.
3309 * It returns the base as defined in RFC 2396 sections
3310 * 5.1.1. Base URI within Document Content
3311 * and
3312 * 5.1.2. Base URI from the Encapsulating Entity
3313 * However it does not return the document base (5.1.3), use
3314 * xmlDocumentGetBase() for this
3315 *
3316 * Returns a pointer to the base URL, or NULL if not found
3317 * It's up to the caller to free the memory.
3318 */
3319xmlChar *
3320xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003321 xmlChar *oldbase = NULL;
3322 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003323
3324 if ((cur == NULL) && (doc == NULL))
3325 return(NULL);
3326 if (doc == NULL) doc = cur->doc;
3327 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3328 cur = doc->children;
3329 while ((cur != NULL) && (cur->name != NULL)) {
3330 if (cur->type != XML_ELEMENT_NODE) {
3331 cur = cur->next;
3332 continue;
3333 }
3334 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3335 cur = cur->children;
3336 continue;
3337 }
3338 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3339 cur = cur->children;
3340 continue;
3341 }
3342 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3343 return(xmlGetProp(cur, BAD_CAST "href"));
3344 }
3345 cur = cur->next;
3346 }
3347 return(NULL);
3348 }
3349 while (cur != NULL) {
3350 if (cur->type == XML_ENTITY_DECL) {
3351 xmlEntityPtr ent = (xmlEntityPtr) cur;
3352 return(xmlStrdup(ent->URI));
3353 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003354 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003355 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003356 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003357 if (oldbase != NULL) {
3358 newbase = xmlBuildURI(oldbase, base);
3359 if (newbase != NULL) {
3360 xmlFree(oldbase);
3361 xmlFree(base);
3362 oldbase = newbase;
3363 } else {
3364 xmlFree(oldbase);
3365 xmlFree(base);
3366 return(NULL);
3367 }
3368 } else {
3369 oldbase = base;
3370 }
3371 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3372 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3373 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3374 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003375 }
3376 }
Owen Taylor3473f882001-02-23 17:55:21 +00003377 cur = cur->parent;
3378 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003379 if ((doc != NULL) && (doc->URL != NULL)) {
3380 if (oldbase == NULL)
3381 return(xmlStrdup(doc->URL));
3382 newbase = xmlBuildURI(oldbase, doc->URL);
3383 xmlFree(oldbase);
3384 return(newbase);
3385 }
3386 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003387}
3388
3389/**
3390 * xmlNodeGetContent:
3391 * @cur: the node being read
3392 *
3393 * Read the value of a node, this can be either the text carried
3394 * directly by this node if it's a TEXT node or the aggregate string
3395 * of the values carried by this node child's (TEXT and ENTITY_REF).
3396 * Entity references are substitued.
3397 * Returns a new xmlChar * or NULL if no content is available.
3398 * It's up to the caller to free the memory.
3399 */
3400xmlChar *
3401xmlNodeGetContent(xmlNodePtr cur) {
3402 if (cur == NULL) return(NULL);
3403 switch (cur->type) {
3404 case XML_DOCUMENT_FRAG_NODE:
3405 case XML_ELEMENT_NODE: {
3406 xmlNodePtr tmp = cur;
3407 xmlBufferPtr buffer;
3408 xmlChar *ret;
3409
3410 buffer = xmlBufferCreate();
3411 if (buffer == NULL)
3412 return(NULL);
3413 while (tmp != NULL) {
3414 switch (tmp->type) {
3415 case XML_ELEMENT_NODE:
Daniel Veillard2d703722001-05-30 18:32:34 +00003416 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003417 case XML_TEXT_NODE:
3418 if (tmp->content != NULL)
3419#ifndef XML_USE_BUFFER_CONTENT
3420 xmlBufferCat(buffer, tmp->content);
3421#else
3422 xmlBufferCat(buffer,
3423 xmlBufferContent(tmp->content));
3424#endif
3425 break;
3426 case XML_ENTITY_REF_NODE: {
3427 xmlEntityPtr ent;
3428
3429 ent = xmlGetDocEntity(cur->doc, tmp->name);
3430 if (ent != NULL)
3431 xmlBufferCat(buffer, ent->content);
3432 }
3433 default:
3434 break;
3435 }
3436 /*
3437 * Skip to next node
3438 */
3439 if (tmp->children != NULL) {
3440 if (tmp->children->type != XML_ENTITY_DECL) {
3441 tmp = tmp->children;
3442 continue;
3443 }
3444 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003445 if (tmp == cur)
3446 break;
3447
Owen Taylor3473f882001-02-23 17:55:21 +00003448 if (tmp->next != NULL) {
3449 tmp = tmp->next;
3450 continue;
3451 }
3452
3453 do {
3454 tmp = tmp->parent;
3455 if (tmp == NULL)
3456 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003457 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003458 tmp = NULL;
3459 break;
3460 }
3461 if (tmp->next != NULL) {
3462 tmp = tmp->next;
3463 break;
3464 }
3465 } while (tmp != NULL);
3466 }
3467 ret = buffer->content;
3468 buffer->content = NULL;
3469 xmlBufferFree(buffer);
3470 return(ret);
3471 }
3472 case XML_ATTRIBUTE_NODE: {
3473 xmlAttrPtr attr = (xmlAttrPtr) cur;
3474 if (attr->parent != NULL)
3475 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3476 else
3477 return(xmlNodeListGetString(NULL, attr->children, 1));
3478 break;
3479 }
3480 case XML_COMMENT_NODE:
3481 case XML_PI_NODE:
3482 if (cur->content != NULL)
3483#ifndef XML_USE_BUFFER_CONTENT
3484 return(xmlStrdup(cur->content));
3485#else
3486 return(xmlStrdup(xmlBufferContent(cur->content)));
3487#endif
3488 return(NULL);
3489 case XML_ENTITY_REF_NODE:
3490 /*
3491 * Locate the entity, and get it's content
3492 * @@@
3493 */
3494 return(NULL);
3495 case XML_ENTITY_NODE:
3496 case XML_DOCUMENT_NODE:
3497 case XML_HTML_DOCUMENT_NODE:
3498 case XML_DOCUMENT_TYPE_NODE:
3499 case XML_NOTATION_NODE:
3500 case XML_DTD_NODE:
3501 case XML_XINCLUDE_START:
3502 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003503#ifdef LIBXML_DOCB_ENABLED
3504 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003505#endif
3506 return(NULL);
3507 case XML_NAMESPACE_DECL:
3508 return(xmlStrdup(((xmlNsPtr)cur)->href));
3509 case XML_ELEMENT_DECL:
3510 /* TODO !!! */
3511 return(NULL);
3512 case XML_ATTRIBUTE_DECL:
3513 /* TODO !!! */
3514 return(NULL);
3515 case XML_ENTITY_DECL:
3516 /* TODO !!! */
3517 return(NULL);
3518 case XML_CDATA_SECTION_NODE:
3519 case XML_TEXT_NODE:
3520 if (cur->content != NULL)
3521#ifndef XML_USE_BUFFER_CONTENT
3522 return(xmlStrdup(cur->content));
3523#else
3524 return(xmlStrdup(xmlBufferContent(cur->content)));
3525#endif
3526 return(NULL);
3527 }
3528 return(NULL);
3529}
3530
3531/**
3532 * xmlNodeSetContent:
3533 * @cur: the node being modified
3534 * @content: the new value of the content
3535 *
3536 * Replace the content of a node.
3537 */
3538void
3539xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3540 if (cur == NULL) {
3541#ifdef DEBUG_TREE
3542 xmlGenericError(xmlGenericErrorContext,
3543 "xmlNodeSetContent : node == NULL\n");
3544#endif
3545 return;
3546 }
3547 switch (cur->type) {
3548 case XML_DOCUMENT_FRAG_NODE:
3549 case XML_ELEMENT_NODE:
3550 if (cur->content != NULL) {
3551#ifndef XML_USE_BUFFER_CONTENT
3552 xmlFree(cur->content);
3553#else
3554 xmlBufferFree(cur->content);
3555#endif
3556 cur->content = NULL;
3557 }
3558 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3559 cur->children = xmlStringGetNodeList(cur->doc, content);
3560 UPDATE_LAST_CHILD_AND_PARENT(cur)
3561 break;
3562 case XML_ATTRIBUTE_NODE:
3563 break;
3564 case XML_TEXT_NODE:
3565 case XML_CDATA_SECTION_NODE:
3566 case XML_ENTITY_REF_NODE:
3567 case XML_ENTITY_NODE:
3568 case XML_PI_NODE:
3569 case XML_COMMENT_NODE:
3570 if (cur->content != NULL) {
3571#ifndef XML_USE_BUFFER_CONTENT
3572 xmlFree(cur->content);
3573#else
3574 xmlBufferFree(cur->content);
3575#endif
3576 }
3577 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3578 cur->last = cur->children = NULL;
3579 if (content != NULL) {
3580#ifndef XML_USE_BUFFER_CONTENT
3581 cur->content = xmlStrdup(content);
3582#else
3583 cur->content = xmlBufferCreateSize(0);
3584 xmlBufferSetAllocationScheme(cur->content,
3585 xmlGetBufferAllocationScheme());
3586 xmlBufferAdd(cur->content, content, -1);
3587#endif
3588 } else
3589 cur->content = NULL;
3590 break;
3591 case XML_DOCUMENT_NODE:
3592 case XML_HTML_DOCUMENT_NODE:
3593 case XML_DOCUMENT_TYPE_NODE:
3594 case XML_XINCLUDE_START:
3595 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003596#ifdef LIBXML_DOCB_ENABLED
3597 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003598#endif
3599 break;
3600 case XML_NOTATION_NODE:
3601 break;
3602 case XML_DTD_NODE:
3603 break;
3604 case XML_NAMESPACE_DECL:
3605 break;
3606 case XML_ELEMENT_DECL:
3607 /* TODO !!! */
3608 break;
3609 case XML_ATTRIBUTE_DECL:
3610 /* TODO !!! */
3611 break;
3612 case XML_ENTITY_DECL:
3613 /* TODO !!! */
3614 break;
3615 }
3616}
3617
3618/**
3619 * xmlNodeSetContentLen:
3620 * @cur: the node being modified
3621 * @content: the new value of the content
3622 * @len: the size of @content
3623 *
3624 * Replace the content of a node.
3625 */
3626void
3627xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3628 if (cur == NULL) {
3629#ifdef DEBUG_TREE
3630 xmlGenericError(xmlGenericErrorContext,
3631 "xmlNodeSetContentLen : node == NULL\n");
3632#endif
3633 return;
3634 }
3635 switch (cur->type) {
3636 case XML_DOCUMENT_FRAG_NODE:
3637 case XML_ELEMENT_NODE:
3638 if (cur->content != NULL) {
3639#ifndef XML_USE_BUFFER_CONTENT
3640 xmlFree(cur->content);
3641#else
3642 xmlBufferFree(cur->content);
3643#endif
3644 cur->content = NULL;
3645 }
3646 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3647 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3648 UPDATE_LAST_CHILD_AND_PARENT(cur)
3649 break;
3650 case XML_ATTRIBUTE_NODE:
3651 break;
3652 case XML_TEXT_NODE:
3653 case XML_CDATA_SECTION_NODE:
3654 case XML_ENTITY_REF_NODE:
3655 case XML_ENTITY_NODE:
3656 case XML_PI_NODE:
3657 case XML_COMMENT_NODE:
3658 case XML_NOTATION_NODE:
3659 if (cur->content != NULL) {
3660#ifndef XML_USE_BUFFER_CONTENT
3661 xmlFree(cur->content);
3662#else
3663 xmlBufferFree(cur->content);
3664#endif
3665 }
3666 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3667 cur->children = cur->last = NULL;
3668 if (content != NULL) {
3669#ifndef XML_USE_BUFFER_CONTENT
3670 cur->content = xmlStrndup(content, len);
3671#else
3672 cur->content = xmlBufferCreateSize(len);
3673 xmlBufferSetAllocationScheme(cur->content,
3674 xmlGetBufferAllocationScheme());
3675 xmlBufferAdd(cur->content, content, len);
3676#endif
3677 } else
3678 cur->content = NULL;
3679 break;
3680 case XML_DOCUMENT_NODE:
3681 case XML_DTD_NODE:
3682 case XML_HTML_DOCUMENT_NODE:
3683 case XML_DOCUMENT_TYPE_NODE:
3684 case XML_NAMESPACE_DECL:
3685 case XML_XINCLUDE_START:
3686 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003687#ifdef LIBXML_DOCB_ENABLED
3688 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003689#endif
3690 break;
3691 case XML_ELEMENT_DECL:
3692 /* TODO !!! */
3693 break;
3694 case XML_ATTRIBUTE_DECL:
3695 /* TODO !!! */
3696 break;
3697 case XML_ENTITY_DECL:
3698 /* TODO !!! */
3699 break;
3700 }
3701}
3702
3703/**
3704 * xmlNodeAddContentLen:
3705 * @cur: the node being modified
3706 * @content: extra content
3707 * @len: the size of @content
3708 *
3709 * Append the extra substring to the node content.
3710 */
3711void
3712xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3713 if (cur == NULL) {
3714#ifdef DEBUG_TREE
3715 xmlGenericError(xmlGenericErrorContext,
3716 "xmlNodeAddContentLen : node == NULL\n");
3717#endif
3718 return;
3719 }
3720 if (len <= 0) return;
3721 switch (cur->type) {
3722 case XML_DOCUMENT_FRAG_NODE:
3723 case XML_ELEMENT_NODE: {
3724 xmlNodePtr last = NULL, newNode;
3725
3726 if (cur->children != NULL) {
3727 last = cur->last;
3728 } else {
3729 if (cur->content != NULL) {
3730#ifndef XML_USE_BUFFER_CONTENT
3731 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
3732#else
3733 cur->children = xmlStringGetNodeList(cur->doc,
3734 xmlBufferContent(cur->content));
3735#endif
3736 UPDATE_LAST_CHILD_AND_PARENT(cur)
3737#ifndef XML_USE_BUFFER_CONTENT
3738 xmlFree(cur->content);
3739#else
3740 xmlBufferFree(cur->content);
3741#endif
3742 cur->content = NULL;
3743 last = cur->last;
3744 }
3745 }
3746 newNode = xmlNewTextLen(content, len);
3747 if (newNode != NULL) {
3748 xmlAddChild(cur, newNode);
3749 if ((last != NULL) && (last->next == newNode)) {
3750 xmlTextMerge(last, newNode);
3751 }
3752 }
3753 break;
3754 }
3755 case XML_ATTRIBUTE_NODE:
3756 break;
3757 case XML_TEXT_NODE:
3758 case XML_CDATA_SECTION_NODE:
3759 case XML_ENTITY_REF_NODE:
3760 case XML_ENTITY_NODE:
3761 case XML_PI_NODE:
3762 case XML_COMMENT_NODE:
3763 case XML_NOTATION_NODE:
3764 if (content != NULL) {
3765#ifndef XML_USE_BUFFER_CONTENT
3766 cur->content = xmlStrncat(cur->content, content, len);
3767#else
3768 xmlBufferAdd(cur->content, content, len);
3769#endif
3770 }
3771 case XML_DOCUMENT_NODE:
3772 case XML_DTD_NODE:
3773 case XML_HTML_DOCUMENT_NODE:
3774 case XML_DOCUMENT_TYPE_NODE:
3775 case XML_NAMESPACE_DECL:
3776 case XML_XINCLUDE_START:
3777 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003778#ifdef LIBXML_DOCB_ENABLED
3779 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003780#endif
3781 break;
3782 case XML_ELEMENT_DECL:
3783 case XML_ATTRIBUTE_DECL:
3784 case XML_ENTITY_DECL:
3785 break;
3786 }
3787}
3788
3789/**
3790 * xmlNodeAddContent:
3791 * @cur: the node being modified
3792 * @content: extra content
3793 *
3794 * Append the extra substring to the node content.
3795 */
3796void
3797xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3798 int len;
3799
3800 if (cur == NULL) {
3801#ifdef DEBUG_TREE
3802 xmlGenericError(xmlGenericErrorContext,
3803 "xmlNodeAddContent : node == NULL\n");
3804#endif
3805 return;
3806 }
3807 if (content == NULL) return;
3808 len = xmlStrlen(content);
3809 xmlNodeAddContentLen(cur, content, len);
3810}
3811
3812/**
3813 * xmlTextMerge:
3814 * @first: the first text node
3815 * @second: the second text node being merged
3816 *
3817 * Merge two text nodes into one
3818 * Returns the first text node augmented
3819 */
3820xmlNodePtr
3821xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3822 if (first == NULL) return(second);
3823 if (second == NULL) return(first);
3824 if (first->type != XML_TEXT_NODE) return(first);
3825 if (second->type != XML_TEXT_NODE) return(first);
3826 if (second->name != first->name)
3827 return(first);
3828#ifndef XML_USE_BUFFER_CONTENT
3829 xmlNodeAddContent(first, second->content);
3830#else
3831 xmlNodeAddContent(first, xmlBufferContent(second->content));
3832#endif
3833 xmlUnlinkNode(second);
3834 xmlFreeNode(second);
3835 return(first);
3836}
3837
3838/**
3839 * xmlGetNsList:
3840 * @doc: the document
3841 * @node: the current node
3842 *
3843 * Search all the namespace applying to a given element.
3844 * Returns an NULL terminated array of all the xmlNsPtr found
3845 * that need to be freed by the caller or NULL if no
3846 * namespace if defined
3847 */
3848xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003849xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3850{
Owen Taylor3473f882001-02-23 17:55:21 +00003851 xmlNsPtr cur;
3852 xmlNsPtr *ret = NULL;
3853 int nbns = 0;
3854 int maxns = 10;
3855 int i;
3856
3857 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00003858 if (node->type == XML_ELEMENT_NODE) {
3859 cur = node->nsDef;
3860 while (cur != NULL) {
3861 if (ret == NULL) {
3862 ret =
3863 (xmlNsPtr *) xmlMalloc((maxns + 1) *
3864 sizeof(xmlNsPtr));
3865 if (ret == NULL) {
3866 xmlGenericError(xmlGenericErrorContext,
3867 "xmlGetNsList : out of memory!\n");
3868 return (NULL);
3869 }
3870 ret[nbns] = NULL;
3871 }
3872 for (i = 0; i < nbns; i++) {
3873 if ((cur->prefix == ret[i]->prefix) ||
3874 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
3875 break;
3876 }
3877 if (i >= nbns) {
3878 if (nbns >= maxns) {
3879 maxns *= 2;
3880 ret = (xmlNsPtr *) xmlRealloc(ret,
3881 (maxns +
3882 1) *
3883 sizeof(xmlNsPtr));
3884 if (ret == NULL) {
3885 xmlGenericError(xmlGenericErrorContext,
3886 "xmlGetNsList : realloc failed!\n");
3887 return (NULL);
3888 }
3889 }
3890 ret[nbns++] = cur;
3891 ret[nbns] = NULL;
3892 }
Owen Taylor3473f882001-02-23 17:55:21 +00003893
Daniel Veillard77044732001-06-29 21:31:07 +00003894 cur = cur->next;
3895 }
3896 }
3897 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003898 }
Daniel Veillard77044732001-06-29 21:31:07 +00003899 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003900}
3901
3902/**
3903 * xmlSearchNs:
3904 * @doc: the document
3905 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00003906 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00003907 *
3908 * Search a Ns registered under a given name space for a document.
3909 * recurse on the parents until it finds the defined namespace
3910 * or return NULL otherwise.
3911 * @nameSpace can be NULL, this is a search for the default namespace.
3912 * We don't allow to cross entities boundaries. If you don't declare
3913 * the namespace within those you will be in troubles !!! A warning
3914 * is generated to cover this case.
3915 *
3916 * Returns the namespace pointer or NULL.
3917 */
3918xmlNsPtr
3919xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
3920 xmlNsPtr cur;
3921
3922 if (node == NULL) return(NULL);
3923 if ((nameSpace != NULL) &&
3924 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
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 if ((node->type == XML_ENTITY_REF_NODE) ||
3945 (node->type == XML_ENTITY_NODE) ||
3946 (node->type == XML_ENTITY_DECL))
3947 return(NULL);
3948 if (node->type == XML_ELEMENT_NODE) {
3949 cur = node->nsDef;
3950 while (cur != NULL) {
3951 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3952 (cur->href != NULL))
3953 return(cur);
3954 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
3955 (cur->href != NULL) &&
3956 (xmlStrEqual(cur->prefix, nameSpace)))
3957 return(cur);
3958 cur = cur->next;
3959 }
3960 }
3961 node = node->parent;
3962 }
3963 return(NULL);
3964}
3965
3966/**
3967 * xmlSearchNsByHref:
3968 * @doc: the document
3969 * @node: the current node
3970 * @href: the namespace value
3971 *
3972 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3973 * the defined namespace or return NULL otherwise.
3974 * Returns the namespace pointer or NULL.
3975 */
3976xmlNsPtr
3977xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
3978 xmlNsPtr cur;
3979 xmlNodePtr orig = node;
3980
3981 if ((node == NULL) || (href == NULL)) return(NULL);
3982 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
3983 if (doc->oldNs == NULL) {
3984 /*
3985 * Allocate a new Namespace and fill the fields.
3986 */
3987 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3988 if (doc->oldNs == NULL) {
3989 xmlGenericError(xmlGenericErrorContext,
3990 "xmlSearchNsByHref : malloc failed\n");
3991 return(NULL);
3992 }
3993 memset(doc->oldNs, 0, sizeof(xmlNs));
3994 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3995
3996 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3997 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3998 }
3999 return(doc->oldNs);
4000 }
4001 while (node != NULL) {
4002 cur = node->nsDef;
4003 while (cur != NULL) {
4004 if ((cur->href != NULL) && (href != NULL) &&
4005 (xmlStrEqual(cur->href, href))) {
4006 /*
4007 * Check that the prefix is not shadowed between orig and node
4008 */
4009 xmlNodePtr check = orig;
4010 xmlNsPtr tst;
4011
4012 while (check != node) {
4013 tst = check->nsDef;
4014 while (tst != NULL) {
4015 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4016 goto shadowed;
4017 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4018 (xmlStrEqual(tst->prefix, cur->prefix)))
4019 goto shadowed;
4020 tst = tst->next;
4021 }
4022 check = check->parent;
4023 }
4024 return(cur);
4025 }
4026shadowed:
4027 cur = cur->next;
4028 }
4029 node = node->parent;
4030 }
4031 return(NULL);
4032}
4033
4034/**
4035 * xmlNewReconciliedNs
4036 * @doc: the document
4037 * @tree: a node expected to hold the new namespace
4038 * @ns: the original namespace
4039 *
4040 * This function tries to locate a namespace definition in a tree
4041 * ancestors, or create a new namespace definition node similar to
4042 * @ns trying to reuse the same prefix. However if the given prefix is
4043 * null (default namespace) or reused within the subtree defined by
4044 * @tree or on one of its ancestors then a new prefix is generated.
4045 * Returns the (new) namespace definition or NULL in case of error
4046 */
4047xmlNsPtr
4048xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4049 xmlNsPtr def;
4050 xmlChar prefix[50];
4051 int counter = 1;
4052
4053 if (tree == NULL) {
4054#ifdef DEBUG_TREE
4055 xmlGenericError(xmlGenericErrorContext,
4056 "xmlNewReconciliedNs : tree == NULL\n");
4057#endif
4058 return(NULL);
4059 }
4060 if (ns == NULL) {
4061#ifdef DEBUG_TREE
4062 xmlGenericError(xmlGenericErrorContext,
4063 "xmlNewReconciliedNs : ns == NULL\n");
4064#endif
4065 return(NULL);
4066 }
4067 /*
4068 * Search an existing namespace definition inherited.
4069 */
4070 def = xmlSearchNsByHref(doc, tree, ns->href);
4071 if (def != NULL)
4072 return(def);
4073
4074 /*
4075 * Find a close prefix which is not already in use.
4076 * Let's strip namespace prefixes longer than 20 chars !
4077 */
4078 sprintf((char *) prefix, "%.20s", ns->prefix);
4079 def = xmlSearchNs(doc, tree, prefix);
4080 while (def != NULL) {
4081 if (counter > 1000) return(NULL);
4082 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4083 def = xmlSearchNs(doc, tree, prefix);
4084 }
4085
4086 /*
4087 * Ok, now we are ready to create a new one.
4088 */
4089 def = xmlNewNs(tree, ns->href, prefix);
4090 return(def);
4091}
4092
4093/**
4094 * xmlReconciliateNs
4095 * @doc: the document
4096 * @tree: a node defining the subtree to reconciliate
4097 *
4098 * This function checks that all the namespaces declared within the given
4099 * tree are properly declared. This is needed for example after Copy or Cut
4100 * and then paste operations. The subtree may still hold pointers to
4101 * namespace declarations outside the subtree or invalid/masked. As much
4102 * as possible the function try tu reuse the existing namespaces found in
4103 * the new environment. If not possible the new namespaces are redeclared
4104 * on @tree at the top of the given subtree.
4105 * Returns the number of namespace declarations created or -1 in case of error.
4106 */
4107int
4108xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4109 xmlNsPtr *oldNs = NULL;
4110 xmlNsPtr *newNs = NULL;
4111 int sizeCache = 0;
4112 int nbCache = 0;
4113
4114 xmlNsPtr n;
4115 xmlNodePtr node = tree;
4116 xmlAttrPtr attr;
4117 int ret = 0, i;
4118
4119 while (node != NULL) {
4120 /*
4121 * Reconciliate the node namespace
4122 */
4123 if (node->ns != NULL) {
4124 /*
4125 * initialize the cache if needed
4126 */
4127 if (sizeCache == 0) {
4128 sizeCache = 10;
4129 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4130 sizeof(xmlNsPtr));
4131 if (oldNs == NULL) {
4132 xmlGenericError(xmlGenericErrorContext,
4133 "xmlReconciliateNs : memory pbm\n");
4134 return(-1);
4135 }
4136 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4137 sizeof(xmlNsPtr));
4138 if (newNs == NULL) {
4139 xmlGenericError(xmlGenericErrorContext,
4140 "xmlReconciliateNs : memory pbm\n");
4141 xmlFree(oldNs);
4142 return(-1);
4143 }
4144 }
4145 for (i = 0;i < nbCache;i++) {
4146 if (oldNs[i] == node->ns) {
4147 node->ns = newNs[i];
4148 break;
4149 }
4150 }
4151 if (i == nbCache) {
4152 /*
4153 * Ok we need to recreate a new namespace definition
4154 */
4155 n = xmlNewReconciliedNs(doc, tree, node->ns);
4156 if (n != NULL) { /* :-( what if else ??? */
4157 /*
4158 * check if we need to grow the cache buffers.
4159 */
4160 if (sizeCache <= nbCache) {
4161 sizeCache *= 2;
4162 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4163 sizeof(xmlNsPtr));
4164 if (oldNs == NULL) {
4165 xmlGenericError(xmlGenericErrorContext,
4166 "xmlReconciliateNs : memory pbm\n");
4167 xmlFree(newNs);
4168 return(-1);
4169 }
4170 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4171 sizeof(xmlNsPtr));
4172 if (newNs == NULL) {
4173 xmlGenericError(xmlGenericErrorContext,
4174 "xmlReconciliateNs : memory pbm\n");
4175 xmlFree(oldNs);
4176 return(-1);
4177 }
4178 }
4179 newNs[nbCache] = n;
4180 oldNs[nbCache++] = node->ns;
4181 node->ns = n;
4182 }
4183 }
4184 }
4185 /*
4186 * now check for namespace hold by attributes on the node.
4187 */
4188 attr = node->properties;
4189 while (attr != NULL) {
4190 if (attr->ns != NULL) {
4191 /*
4192 * initialize the cache if needed
4193 */
4194 if (sizeCache == 0) {
4195 sizeCache = 10;
4196 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4197 sizeof(xmlNsPtr));
4198 if (oldNs == NULL) {
4199 xmlGenericError(xmlGenericErrorContext,
4200 "xmlReconciliateNs : memory pbm\n");
4201 return(-1);
4202 }
4203 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4204 sizeof(xmlNsPtr));
4205 if (newNs == NULL) {
4206 xmlGenericError(xmlGenericErrorContext,
4207 "xmlReconciliateNs : memory pbm\n");
4208 xmlFree(oldNs);
4209 return(-1);
4210 }
4211 }
4212 for (i = 0;i < nbCache;i++) {
4213 if (oldNs[i] == attr->ns) {
4214 node->ns = newNs[i];
4215 break;
4216 }
4217 }
4218 if (i == nbCache) {
4219 /*
4220 * Ok we need to recreate a new namespace definition
4221 */
4222 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4223 if (n != NULL) { /* :-( what if else ??? */
4224 /*
4225 * check if we need to grow the cache buffers.
4226 */
4227 if (sizeCache <= nbCache) {
4228 sizeCache *= 2;
4229 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4230 sizeof(xmlNsPtr));
4231 if (oldNs == NULL) {
4232 xmlGenericError(xmlGenericErrorContext,
4233 "xmlReconciliateNs : memory pbm\n");
4234 xmlFree(newNs);
4235 return(-1);
4236 }
4237 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4238 sizeof(xmlNsPtr));
4239 if (newNs == NULL) {
4240 xmlGenericError(xmlGenericErrorContext,
4241 "xmlReconciliateNs : memory pbm\n");
4242 xmlFree(oldNs);
4243 return(-1);
4244 }
4245 }
4246 newNs[nbCache] = n;
4247 oldNs[nbCache++] = attr->ns;
4248 attr->ns = n;
4249 }
4250 }
4251 }
4252 attr = attr->next;
4253 }
4254
4255 /*
4256 * Browse the full subtree, deep first
4257 */
4258 if (node->children != NULL) {
4259 /* deep first */
4260 node = node->children;
4261 } else if ((node != tree) && (node->next != NULL)) {
4262 /* then siblings */
4263 node = node->next;
4264 } else if (node != tree) {
4265 /* go up to parents->next if needed */
4266 while (node != tree) {
4267 if (node->parent != NULL)
4268 node = node->parent;
4269 if ((node != tree) && (node->next != NULL)) {
4270 node = node->next;
4271 break;
4272 }
4273 if (node->parent == NULL) {
4274 node = NULL;
4275 break;
4276 }
4277 }
4278 /* exit condition */
4279 if (node == tree)
4280 node = NULL;
4281 }
4282 }
4283 return(ret);
4284}
4285
4286/**
4287 * xmlHasProp:
4288 * @node: the node
4289 * @name: the attribute name
4290 *
4291 * Search an attribute associated to a node
4292 * This function also looks in DTD attribute declaration for #FIXED or
4293 * default declaration values unless DTD use has been turned off.
4294 *
4295 * Returns the attribute or the attribute declaration or NULL if
4296 * neither was found.
4297 */
4298xmlAttrPtr
4299xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4300 xmlAttrPtr prop;
4301 xmlDocPtr doc;
4302
4303 if ((node == NULL) || (name == NULL)) return(NULL);
4304 /*
4305 * Check on the properties attached to the node
4306 */
4307 prop = node->properties;
4308 while (prop != NULL) {
4309 if (xmlStrEqual(prop->name, name)) {
4310 return(prop);
4311 }
4312 prop = prop->next;
4313 }
4314 if (!xmlCheckDTD) return(NULL);
4315
4316 /*
4317 * Check if there is a default declaration in the internal
4318 * or external subsets
4319 */
4320 doc = node->doc;
4321 if (doc != NULL) {
4322 xmlAttributePtr attrDecl;
4323 if (doc->intSubset != NULL) {
4324 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4325 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4326 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4327 if (attrDecl != NULL)
4328 return((xmlAttrPtr) attrDecl);
4329 }
4330 }
4331 return(NULL);
4332}
4333
4334/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004335 * xmlHasNsProp:
4336 * @node: the node
4337 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004338 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004339 *
4340 * Search for an attribute associated to a node
4341 * This attribute has to be anchored in the namespace specified.
4342 * This does the entity substitution.
4343 * This function looks in DTD attribute declaration for #FIXED or
4344 * default declaration values unless DTD use has been turned off.
4345 *
4346 * Returns the attribute or the attribute declaration or NULL
4347 * if neither was found.
4348 */
4349xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004350xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004351 xmlAttrPtr prop;
4352 xmlDocPtr doc;
4353 xmlNsPtr ns;
4354
4355 if (node == NULL)
4356 return(NULL);
4357
4358 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004359 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004360 return(xmlHasProp(node, name));
4361 while (prop != NULL) {
4362 /*
4363 * One need to have
4364 * - same attribute names
4365 * - and the attribute carrying that namespace
4366 * or
4367 * no namespace on the attribute and the element carrying it
4368 */
4369 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004370 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4371 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004372 }
4373 prop = prop->next;
4374 }
4375 if (!xmlCheckDTD) return(NULL);
4376
4377 /*
4378 * Check if there is a default declaration in the internal
4379 * or external subsets
4380 */
4381 doc = node->doc;
4382 if (doc != NULL) {
4383 if (doc->intSubset != NULL) {
4384 xmlAttributePtr attrDecl;
4385
4386 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4387 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4388 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4389
4390 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4391 /*
4392 * The DTD declaration only allows a prefix search
4393 */
4394 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004395 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004396 return((xmlAttrPtr) attrDecl);
4397 }
4398 }
4399 }
4400 return(NULL);
4401}
4402
4403/**
Owen Taylor3473f882001-02-23 17:55:21 +00004404 * xmlGetProp:
4405 * @node: the node
4406 * @name: the attribute name
4407 *
4408 * Search and get the value of an attribute associated to a node
4409 * This does the entity substitution.
4410 * This function looks in DTD attribute declaration for #FIXED or
4411 * default declaration values unless DTD use has been turned off.
4412 *
4413 * Returns the attribute value or NULL if not found.
4414 * It's up to the caller to free the memory.
4415 */
4416xmlChar *
4417xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4418 xmlAttrPtr prop;
4419 xmlDocPtr doc;
4420
4421 if ((node == NULL) || (name == NULL)) return(NULL);
4422 /*
4423 * Check on the properties attached to the node
4424 */
4425 prop = node->properties;
4426 while (prop != NULL) {
4427 if (xmlStrEqual(prop->name, name)) {
4428 xmlChar *ret;
4429
4430 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4431 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4432 return(ret);
4433 }
4434 prop = prop->next;
4435 }
4436 if (!xmlCheckDTD) return(NULL);
4437
4438 /*
4439 * Check if there is a default declaration in the internal
4440 * or external subsets
4441 */
4442 doc = node->doc;
4443 if (doc != NULL) {
4444 xmlAttributePtr attrDecl;
4445 if (doc->intSubset != NULL) {
4446 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4447 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4448 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4449 if (attrDecl != NULL)
4450 return(xmlStrdup(attrDecl->defaultValue));
4451 }
4452 }
4453 return(NULL);
4454}
4455
4456/**
4457 * xmlGetNsProp:
4458 * @node: the node
4459 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004460 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004461 *
4462 * Search and get the value of an attribute associated to a node
4463 * This attribute has to be anchored in the namespace specified.
4464 * This does the entity substitution.
4465 * This function looks in DTD attribute declaration for #FIXED or
4466 * default declaration values unless DTD use has been turned off.
4467 *
4468 * Returns the attribute value or NULL if not found.
4469 * It's up to the caller to free the memory.
4470 */
4471xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004472xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004473 xmlAttrPtr prop;
4474 xmlDocPtr doc;
4475 xmlNsPtr ns;
4476
4477 if (node == NULL)
4478 return(NULL);
4479
4480 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004481 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004482 return(xmlGetProp(node, name));
4483 while (prop != NULL) {
4484 /*
4485 * One need to have
4486 * - same attribute names
4487 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004488 */
4489 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004490 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004491 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004492 xmlChar *ret;
4493
4494 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4495 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4496 return(ret);
4497 }
4498 prop = prop->next;
4499 }
4500 if (!xmlCheckDTD) return(NULL);
4501
4502 /*
4503 * Check if there is a default declaration in the internal
4504 * or external subsets
4505 */
4506 doc = node->doc;
4507 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004508 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004509 xmlAttributePtr attrDecl;
4510
Owen Taylor3473f882001-02-23 17:55:21 +00004511 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4512 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4513 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4514
4515 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4516 /*
4517 * The DTD declaration only allows a prefix search
4518 */
4519 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004520 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004521 return(xmlStrdup(attrDecl->defaultValue));
4522 }
4523 }
4524 }
4525 return(NULL);
4526}
4527
4528/**
4529 * xmlSetProp:
4530 * @node: the node
4531 * @name: the attribute name
4532 * @value: the attribute value
4533 *
4534 * Set (or reset) an attribute carried by a node.
4535 * Returns the attribute pointer.
4536 */
4537xmlAttrPtr
4538xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
4539 xmlAttrPtr prop = node->properties;
4540 xmlDocPtr doc = NULL;
4541
4542 if ((node == NULL) || (name == NULL))
4543 return(NULL);
4544 doc = node->doc;
4545 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004546 if ((xmlStrEqual(prop->name, name)) &&
4547 (prop->ns == NULL)){
Owen Taylor3473f882001-02-23 17:55:21 +00004548 if (prop->children != NULL)
4549 xmlFreeNodeList(prop->children);
4550 prop->children = NULL;
4551 prop->last = NULL;
4552 if (value != NULL) {
4553 xmlChar *buffer;
4554 xmlNodePtr tmp;
4555
4556 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4557 prop->children = xmlStringGetNodeList(node->doc, buffer);
4558 prop->last = NULL;
4559 prop->doc = doc;
4560 tmp = prop->children;
4561 while (tmp != NULL) {
4562 tmp->parent = (xmlNodePtr) prop;
4563 tmp->doc = doc;
4564 if (tmp->next == NULL)
4565 prop->last = tmp;
4566 tmp = tmp->next;
4567 }
4568 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004569 }
Owen Taylor3473f882001-02-23 17:55:21 +00004570 return(prop);
4571 }
4572 prop = prop->next;
4573 }
4574 prop = xmlNewProp(node, name, value);
4575 return(prop);
4576}
4577
4578/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004579 * xmlUnsetProp:
4580 * @node: the node
4581 * @name: the attribute name
4582 *
4583 * Remove an attribute carried by a node.
4584 * Returns 0 if successful, -1 if not found
4585 */
4586int
4587xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4588 xmlAttrPtr prop = node->properties, prev = NULL;;
4589
4590 if ((node == NULL) || (name == NULL))
4591 return(-1);
4592 while (prop != NULL) {
4593 if ((xmlStrEqual(prop->name, name)) &&
4594 (prop->ns == NULL)) {
4595 if (prev == NULL)
4596 node->properties = prop->next;
4597 else
4598 prev->next = prop->next;
4599 xmlFreeProp(prop);
4600 return(0);
4601 }
4602 prev = prop;
4603 prop = prop->next;
4604 }
4605 return(-1);
4606}
4607
4608/**
Owen Taylor3473f882001-02-23 17:55:21 +00004609 * xmlSetNsProp:
4610 * @node: the node
4611 * @ns: the namespace definition
4612 * @name: the attribute name
4613 * @value: the attribute value
4614 *
4615 * Set (or reset) an attribute carried by a node.
4616 * The ns structure must be in scope, this is not checked.
4617 *
4618 * Returns the attribute pointer.
4619 */
4620xmlAttrPtr
4621xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4622 const xmlChar *value) {
4623 xmlAttrPtr prop;
4624
4625 if ((node == NULL) || (name == NULL))
4626 return(NULL);
4627
4628 if (ns == NULL)
4629 return(xmlSetProp(node, name, value));
4630 if (ns->href == NULL)
4631 return(NULL);
4632 prop = node->properties;
4633
4634 while (prop != NULL) {
4635 /*
4636 * One need to have
4637 * - same attribute names
4638 * - and the attribute carrying that namespace
4639 * or
4640 * no namespace on the attribute and the element carrying it
4641 */
4642 if ((xmlStrEqual(prop->name, name)) &&
4643 (((prop->ns == NULL) && (node->ns != NULL) &&
4644 (xmlStrEqual(node->ns->href, ns->href))) ||
4645 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4646 if (prop->children != NULL)
4647 xmlFreeNodeList(prop->children);
4648 prop->children = NULL;
4649 prop->last = NULL;
4650 prop->ns = ns;
4651 if (value != NULL) {
4652 xmlChar *buffer;
4653 xmlNodePtr tmp;
4654
4655 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4656 prop->children = xmlStringGetNodeList(node->doc, buffer);
4657 prop->last = NULL;
4658 tmp = prop->children;
4659 while (tmp != NULL) {
4660 tmp->parent = (xmlNodePtr) prop;
4661 if (tmp->next == NULL)
4662 prop->last = tmp;
4663 tmp = tmp->next;
4664 }
4665 xmlFree(buffer);
4666 }
4667 return(prop);
4668 }
4669 prop = prop->next;
4670 }
4671 prop = xmlNewNsProp(node, ns, name, value);
4672 return(prop);
4673}
4674
4675/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004676 * xmlUnsetNsProp:
4677 * @node: the node
4678 * @ns: the namespace definition
4679 * @name: the attribute name
4680 *
4681 * Remove an attribute carried by a node.
4682 * Returns 0 if successful, -1 if not found
4683 */
4684int
4685xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4686 xmlAttrPtr prop = node->properties, prev = NULL;;
4687
4688 if ((node == NULL) || (name == NULL))
4689 return(-1);
4690 if (ns == NULL)
4691 return(xmlUnsetProp(node, name));
4692 if (ns->href == NULL)
4693 return(-1);
4694 while (prop != NULL) {
4695 if ((xmlStrEqual(prop->name, name)) &&
4696 (((prop->ns == NULL) && (node->ns != NULL) &&
4697 (xmlStrEqual(node->ns->href, ns->href))) ||
4698 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4699 if (prev == NULL)
4700 node->properties = prop->next;
4701 else
4702 prev->next = prop->next;
4703 xmlFreeProp(prop);
4704 return(0);
4705 }
4706 prev = prop;
4707 prop = prop->next;
4708 }
4709 return(-1);
4710}
4711
4712/**
Owen Taylor3473f882001-02-23 17:55:21 +00004713 * xmlNodeIsText:
4714 * @node: the node
4715 *
4716 * Is this node a Text node ?
4717 * Returns 1 yes, 0 no
4718 */
4719int
4720xmlNodeIsText(xmlNodePtr node) {
4721 if (node == NULL) return(0);
4722
4723 if (node->type == XML_TEXT_NODE) return(1);
4724 return(0);
4725}
4726
4727/**
4728 * xmlIsBlankNode:
4729 * @node: the node
4730 *
4731 * Checks whether this node is an empty or whitespace only
4732 * (and possibly ignorable) text-node.
4733 *
4734 * Returns 1 yes, 0 no
4735 */
4736int
4737xmlIsBlankNode(xmlNodePtr node) {
4738 const xmlChar *cur;
4739 if (node == NULL) return(0);
4740
4741 if (node->type != XML_TEXT_NODE) return(0);
4742 if (node->content == NULL) return(1);
4743#ifndef XML_USE_BUFFER_CONTENT
4744 cur = node->content;
4745#else
4746 cur = xmlBufferContent(node->content);
4747#endif
4748 while (*cur != 0) {
4749 if (!IS_BLANK(*cur)) return(0);
4750 cur++;
4751 }
4752
4753 return(1);
4754}
4755
4756/**
4757 * xmlTextConcat:
4758 * @node: the node
4759 * @content: the content
4760 * @len: @content lenght
4761 *
4762 * Concat the given string at the end of the existing node content
4763 */
4764
4765void
4766xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4767 if (node == NULL) return;
4768
4769 if ((node->type != XML_TEXT_NODE) &&
4770 (node->type != XML_CDATA_SECTION_NODE)) {
4771#ifdef DEBUG_TREE
4772 xmlGenericError(xmlGenericErrorContext,
4773 "xmlTextConcat: node is not text nor cdata\n");
4774#endif
4775 return;
4776 }
4777#ifndef XML_USE_BUFFER_CONTENT
4778 node->content = xmlStrncat(node->content, content, len);
4779#else
4780 xmlBufferAdd(node->content, content, len);
4781#endif
4782}
4783
4784/************************************************************************
4785 * *
4786 * Output : to a FILE or in memory *
4787 * *
4788 ************************************************************************/
4789
4790#define BASE_BUFFER_SIZE 4000
4791
Daniel Veillarde356c282001-03-10 12:32:04 +00004792int xmlDefaultBufferSize = BASE_BUFFER_SIZE;
4793
Owen Taylor3473f882001-02-23 17:55:21 +00004794/**
4795 * xmlBufferCreate:
4796 *
4797 * routine to create an XML buffer.
4798 * returns the new structure.
4799 */
4800xmlBufferPtr
4801xmlBufferCreate(void) {
4802 xmlBufferPtr ret;
4803
4804 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4805 if (ret == NULL) {
4806 xmlGenericError(xmlGenericErrorContext,
4807 "xmlBufferCreate : out of memory!\n");
4808 return(NULL);
4809 }
4810 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004811 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004812 ret->alloc = xmlBufferAllocScheme;
4813 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4814 if (ret->content == NULL) {
4815 xmlGenericError(xmlGenericErrorContext,
4816 "xmlBufferCreate : out of memory!\n");
4817 xmlFree(ret);
4818 return(NULL);
4819 }
4820 ret->content[0] = 0;
4821 return(ret);
4822}
4823
4824/**
4825 * xmlBufferCreateSize:
4826 * @size: initial size of buffer
4827 *
4828 * routine to create an XML buffer.
4829 * returns the new structure.
4830 */
4831xmlBufferPtr
4832xmlBufferCreateSize(size_t size) {
4833 xmlBufferPtr ret;
4834
4835 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4836 if (ret == NULL) {
4837 xmlGenericError(xmlGenericErrorContext,
4838 "xmlBufferCreate : out of memory!\n");
4839 return(NULL);
4840 }
4841 ret->use = 0;
4842 ret->alloc = xmlBufferAllocScheme;
4843 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4844 if (ret->size){
4845 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4846 if (ret->content == NULL) {
4847 xmlGenericError(xmlGenericErrorContext,
4848 "xmlBufferCreate : out of memory!\n");
4849 xmlFree(ret);
4850 return(NULL);
4851 }
4852 ret->content[0] = 0;
4853 } else
4854 ret->content = NULL;
4855 return(ret);
4856}
4857
4858/**
4859 * xmlBufferSetAllocationScheme:
4860 * @buf: the buffer to free
4861 * @scheme: allocation scheme to use
4862 *
4863 * Sets the allocation scheme for this buffer
4864 */
4865void
4866xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4867 xmlBufferAllocationScheme scheme) {
4868 if (buf == NULL) {
4869#ifdef DEBUG_BUFFER
4870 xmlGenericError(xmlGenericErrorContext,
4871 "xmlBufferSetAllocationScheme: buf == NULL\n");
4872#endif
4873 return;
4874 }
4875
4876 buf->alloc = scheme;
4877}
4878
4879/**
4880 * xmlBufferFree:
4881 * @buf: the buffer to free
4882 *
4883 * Frees an XML buffer.
4884 */
4885void
4886xmlBufferFree(xmlBufferPtr buf) {
4887 if (buf == NULL) {
4888#ifdef DEBUG_BUFFER
4889 xmlGenericError(xmlGenericErrorContext,
4890 "xmlBufferFree: buf == NULL\n");
4891#endif
4892 return;
4893 }
4894 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004895 xmlFree(buf->content);
4896 }
Owen Taylor3473f882001-02-23 17:55:21 +00004897 xmlFree(buf);
4898}
4899
4900/**
4901 * xmlBufferEmpty:
4902 * @buf: the buffer
4903 *
4904 * empty a buffer.
4905 */
4906void
4907xmlBufferEmpty(xmlBufferPtr buf) {
4908 if (buf->content == NULL) return;
4909 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004910 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004911}
4912
4913/**
4914 * xmlBufferShrink:
4915 * @buf: the buffer to dump
4916 * @len: the number of xmlChar to remove
4917 *
4918 * Remove the beginning of an XML buffer.
4919 *
4920 * Returns the number of xmlChar removed, or -1 in case of failure.
4921 */
4922int
4923xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
4924 if (len == 0) return(0);
4925 if (len > buf->use) return(-1);
4926
4927 buf->use -= len;
4928 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
4929
4930 buf->content[buf->use] = 0;
4931 return(len);
4932}
4933
4934/**
4935 * xmlBufferGrow:
4936 * @buf: the buffer
4937 * @len: the minimum free size to allocate
4938 *
4939 * Grow the available space of an XML buffer.
4940 *
4941 * Returns the new available space or -1 in case of error
4942 */
4943int
4944xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
4945 int size;
4946 xmlChar *newbuf;
4947
4948 if (len + buf->use < buf->size) return(0);
4949
4950 size = buf->use + len + 100;
4951
4952 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
4953 if (newbuf == NULL) return(-1);
4954 buf->content = newbuf;
4955 buf->size = size;
4956 return(buf->size - buf->use);
4957}
4958
4959/**
4960 * xmlBufferDump:
4961 * @file: the file output
4962 * @buf: the buffer to dump
4963 *
4964 * Dumps an XML buffer to a FILE *.
4965 * Returns the number of xmlChar written
4966 */
4967int
4968xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4969 int ret;
4970
4971 if (buf == NULL) {
4972#ifdef DEBUG_BUFFER
4973 xmlGenericError(xmlGenericErrorContext,
4974 "xmlBufferDump: buf == NULL\n");
4975#endif
4976 return(0);
4977 }
4978 if (buf->content == NULL) {
4979#ifdef DEBUG_BUFFER
4980 xmlGenericError(xmlGenericErrorContext,
4981 "xmlBufferDump: buf->content == NULL\n");
4982#endif
4983 return(0);
4984 }
4985 if (file == NULL) file = stdout;
4986 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
4987 return(ret);
4988}
4989
4990/**
4991 * xmlBufferContent:
4992 * @buf: the buffer
4993 *
4994 * Returns the internal content
4995 */
4996
4997const xmlChar*
4998xmlBufferContent(const xmlBufferPtr buf)
4999{
5000 if(!buf)
5001 return NULL;
5002
5003 return buf->content;
5004}
5005
5006/**
5007 * xmlBufferLength:
5008 * @buf: the buffer
5009 *
5010 * Returns the length of data in the internal content
5011 */
5012
5013int
5014xmlBufferLength(const xmlBufferPtr buf)
5015{
5016 if(!buf)
5017 return 0;
5018
5019 return buf->use;
5020}
5021
5022/**
5023 * xmlBufferResize:
5024 * @buf: the buffer to resize
5025 * @size: the desired size
5026 *
5027 * Resize a buffer to accomodate minimum size of @size.
5028 *
5029 * Returns 0 in case of problems, 1 otherwise
5030 */
5031int
5032xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5033{
5034 unsigned int newSize;
5035 xmlChar* rebuf = NULL;
5036
5037 /*take care of empty case*/
5038 newSize = (buf->size ? buf->size*2 : size);
5039
5040 /* Don't resize if we don't have to */
5041 if (size < buf->size)
5042 return 1;
5043
5044 /* figure out new size */
5045 switch (buf->alloc){
5046 case XML_BUFFER_ALLOC_DOUBLEIT:
5047 while (size > newSize) newSize *= 2;
5048 break;
5049 case XML_BUFFER_ALLOC_EXACT:
5050 newSize = size+10;
5051 break;
5052 default:
5053 newSize = size+10;
5054 break;
5055 }
5056
5057 if (buf->content == NULL)
5058 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5059 else
5060 rebuf = (xmlChar *) xmlRealloc(buf->content,
5061 newSize * sizeof(xmlChar));
5062 if (rebuf == NULL) {
5063 xmlGenericError(xmlGenericErrorContext,
5064 "xmlBufferAdd : out of memory!\n");
5065 return 0;
5066 }
5067 buf->content = rebuf;
5068 buf->size = newSize;
5069
5070 return 1;
5071}
5072
5073/**
5074 * xmlBufferAdd:
5075 * @buf: the buffer to dump
5076 * @str: the xmlChar string
5077 * @len: the number of xmlChar to add
5078 *
5079 * Add a string range to an XML buffer. if len == -1, the lenght of
5080 * str is recomputed.
5081 */
5082void
5083xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5084 unsigned int needSize;
5085
5086 if (str == NULL) {
5087#ifdef DEBUG_BUFFER
5088 xmlGenericError(xmlGenericErrorContext,
5089 "xmlBufferAdd: str == NULL\n");
5090#endif
5091 return;
5092 }
5093 if (len < -1) {
5094#ifdef DEBUG_BUFFER
5095 xmlGenericError(xmlGenericErrorContext,
5096 "xmlBufferAdd: len < 0\n");
5097#endif
5098 return;
5099 }
5100 if (len == 0) return;
5101
5102 if (len < 0)
5103 len = xmlStrlen(str);
5104
5105 if (len <= 0) return;
5106
5107 needSize = buf->use + len + 2;
5108 if (needSize > buf->size){
5109 if (!xmlBufferResize(buf, needSize)){
5110 xmlGenericError(xmlGenericErrorContext,
5111 "xmlBufferAdd : out of memory!\n");
5112 return;
5113 }
5114 }
5115
5116 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5117 buf->use += len;
5118 buf->content[buf->use] = 0;
5119}
5120
5121/**
5122 * xmlBufferAddHead:
5123 * @buf: the buffer
5124 * @str: the xmlChar string
5125 * @len: the number of xmlChar to add
5126 *
5127 * Add a string range to the beginning of an XML buffer.
5128 * if len == -1, the lenght of @str is recomputed.
5129 */
5130void
5131xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5132 unsigned int needSize;
5133
5134 if (str == NULL) {
5135#ifdef DEBUG_BUFFER
5136 xmlGenericError(xmlGenericErrorContext,
5137 "xmlBufferAdd: str == NULL\n");
5138#endif
5139 return;
5140 }
5141 if (len < -1) {
5142#ifdef DEBUG_BUFFER
5143 xmlGenericError(xmlGenericErrorContext,
5144 "xmlBufferAdd: len < 0\n");
5145#endif
5146 return;
5147 }
5148 if (len == 0) return;
5149
5150 if (len < 0)
5151 len = xmlStrlen(str);
5152
5153 if (len <= 0) return;
5154
5155 needSize = buf->use + len + 2;
5156 if (needSize > buf->size){
5157 if (!xmlBufferResize(buf, needSize)){
5158 xmlGenericError(xmlGenericErrorContext,
5159 "xmlBufferAddHead : out of memory!\n");
5160 return;
5161 }
5162 }
5163
5164 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5165 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5166 buf->use += len;
5167 buf->content[buf->use] = 0;
5168}
5169
5170/**
5171 * xmlBufferCat:
5172 * @buf: the buffer to dump
5173 * @str: the xmlChar string
5174 *
5175 * Append a zero terminated string to an XML buffer.
5176 */
5177void
5178xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5179 if (str != NULL)
5180 xmlBufferAdd(buf, str, -1);
5181}
5182
5183/**
5184 * xmlBufferCCat:
5185 * @buf: the buffer to dump
5186 * @str: the C char string
5187 *
5188 * Append a zero terminated C string to an XML buffer.
5189 */
5190void
5191xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5192 const char *cur;
5193
5194 if (str == NULL) {
5195#ifdef DEBUG_BUFFER
5196 xmlGenericError(xmlGenericErrorContext,
5197 "xmlBufferAdd: str == NULL\n");
5198#endif
5199 return;
5200 }
5201 for (cur = str;*cur != 0;cur++) {
5202 if (buf->use + 10 >= buf->size) {
5203 if (!xmlBufferResize(buf, buf->use+10)){
5204 xmlGenericError(xmlGenericErrorContext,
5205 "xmlBufferCCat : out of memory!\n");
5206 return;
5207 }
5208 }
5209 buf->content[buf->use++] = *cur;
5210 }
5211 buf->content[buf->use] = 0;
5212}
5213
5214/**
5215 * xmlBufferWriteCHAR:
5216 * @buf: the XML buffer
5217 * @string: the string to add
5218 *
5219 * routine which manages and grows an output buffer. This one adds
5220 * xmlChars at the end of the buffer.
5221 */
5222void
5223#ifdef VMS
5224xmlBufferWriteXmlCHAR
5225#else
5226xmlBufferWriteCHAR
5227#endif
5228(xmlBufferPtr buf, const xmlChar *string) {
5229 xmlBufferCat(buf, string);
5230}
5231
5232/**
5233 * xmlBufferWriteChar:
5234 * @buf: the XML buffer output
5235 * @string: the string to add
5236 *
5237 * routine which manage and grows an output buffer. This one add
5238 * C chars at the end of the array.
5239 */
5240void
5241xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5242 xmlBufferCCat(buf, string);
5243}
5244
5245
5246/**
5247 * xmlBufferWriteQuotedString:
5248 * @buf: the XML buffer output
5249 * @string: the string to add
5250 *
5251 * routine which manage and grows an output buffer. This one writes
5252 * a quoted or double quoted xmlChar string, checking first if it holds
5253 * quote or double-quotes internally
5254 */
5255void
5256xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5257 if (xmlStrchr(string, '"')) {
5258 if (xmlStrchr(string, '\'')) {
5259#ifdef DEBUG_BUFFER
5260 xmlGenericError(xmlGenericErrorContext,
5261 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5262#endif
5263 }
5264 xmlBufferCCat(buf, "'");
5265 xmlBufferCat(buf, string);
5266 xmlBufferCCat(buf, "'");
5267 } else {
5268 xmlBufferCCat(buf, "\"");
5269 xmlBufferCat(buf, string);
5270 xmlBufferCCat(buf, "\"");
5271 }
5272}
5273
5274
5275/************************************************************************
5276 * *
5277 * Dumping XML tree content to a simple buffer *
5278 * *
5279 ************************************************************************/
5280
5281void
5282xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5283 int format);
5284static void
5285xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5286 int format);
5287void
5288htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5289
5290/**
5291 * xmlNsDump:
5292 * @buf: the XML buffer output
5293 * @cur: a namespace
5294 *
5295 * Dump a local Namespace definition.
5296 * Should be called in the context of attributes dumps.
5297 */
5298static void
5299xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5300 if (cur == NULL) {
5301#ifdef DEBUG_TREE
5302 xmlGenericError(xmlGenericErrorContext,
5303 "xmlNsDump : Ns == NULL\n");
5304#endif
5305 return;
5306 }
5307 if (cur->type == XML_LOCAL_NAMESPACE) {
5308 /* Within the context of an element attributes */
5309 if (cur->prefix != NULL) {
5310 xmlBufferWriteChar(buf, " xmlns:");
5311 xmlBufferWriteCHAR(buf, cur->prefix);
5312 } else
5313 xmlBufferWriteChar(buf, " xmlns");
5314 xmlBufferWriteChar(buf, "=");
5315 xmlBufferWriteQuotedString(buf, cur->href);
5316 }
5317}
5318
5319/**
5320 * xmlNsListDump:
5321 * @buf: the XML buffer output
5322 * @cur: the first namespace
5323 *
5324 * Dump a list of local Namespace definitions.
5325 * Should be called in the context of attributes dumps.
5326 */
5327static void
5328xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5329 while (cur != NULL) {
5330 xmlNsDump(buf, cur);
5331 cur = cur->next;
5332 }
5333}
5334
5335/**
5336 * xmlDtdDump:
5337 * @buf: the XML buffer output
5338 * @doc: the document
5339 *
5340 * Dump the XML document DTD, if any.
5341 */
5342static void
5343xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5344 if (dtd == NULL) {
5345#ifdef DEBUG_TREE
5346 xmlGenericError(xmlGenericErrorContext,
5347 "xmlDtdDump : no internal subset\n");
5348#endif
5349 return;
5350 }
5351 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5352 xmlBufferWriteCHAR(buf, dtd->name);
5353 if (dtd->ExternalID != NULL) {
5354 xmlBufferWriteChar(buf, " PUBLIC ");
5355 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5356 xmlBufferWriteChar(buf, " ");
5357 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5358 } else if (dtd->SystemID != NULL) {
5359 xmlBufferWriteChar(buf, " SYSTEM ");
5360 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5361 }
5362 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5363 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5364 xmlBufferWriteChar(buf, ">");
5365 return;
5366 }
5367 xmlBufferWriteChar(buf, " [\n");
5368 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5369#if 0
5370 if (dtd->entities != NULL)
5371 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5372 if (dtd->notations != NULL)
5373 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5374 if (dtd->elements != NULL)
5375 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5376 if (dtd->attributes != NULL)
5377 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5378#endif
5379 xmlBufferWriteChar(buf, "]>");
5380}
5381
5382/**
5383 * xmlAttrDump:
5384 * @buf: the XML buffer output
5385 * @doc: the document
5386 * @cur: the attribute pointer
5387 *
5388 * Dump an XML attribute
5389 */
5390static void
5391xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5392 xmlChar *value;
5393
5394 if (cur == NULL) {
5395#ifdef DEBUG_TREE
5396 xmlGenericError(xmlGenericErrorContext,
5397 "xmlAttrDump : property == NULL\n");
5398#endif
5399 return;
5400 }
5401 xmlBufferWriteChar(buf, " ");
5402 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5403 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5404 xmlBufferWriteChar(buf, ":");
5405 }
5406 xmlBufferWriteCHAR(buf, cur->name);
5407 value = xmlNodeListGetString(doc, cur->children, 0);
5408 if (value != NULL) {
5409 xmlBufferWriteChar(buf, "=");
5410 xmlBufferWriteQuotedString(buf, value);
5411 xmlFree(value);
5412 } else {
5413 xmlBufferWriteChar(buf, "=\"\"");
5414 }
5415}
5416
5417/**
5418 * xmlAttrListDump:
5419 * @buf: the XML buffer output
5420 * @doc: the document
5421 * @cur: the first attribute pointer
5422 *
5423 * Dump a list of XML attributes
5424 */
5425static void
5426xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5427 if (cur == NULL) {
5428#ifdef DEBUG_TREE
5429 xmlGenericError(xmlGenericErrorContext,
5430 "xmlAttrListDump : property == NULL\n");
5431#endif
5432 return;
5433 }
5434 while (cur != NULL) {
5435 xmlAttrDump(buf, doc, cur);
5436 cur = cur->next;
5437 }
5438}
5439
5440
5441
5442/**
5443 * xmlNodeListDump:
5444 * @buf: the XML buffer output
5445 * @doc: the document
5446 * @cur: the first node
5447 * @level: the imbrication level for indenting
5448 * @format: is formatting allowed
5449 *
5450 * Dump an XML node list, recursive behaviour,children are printed too.
5451 */
5452static void
5453xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5454 int format) {
5455 int i;
5456
5457 if (cur == NULL) {
5458#ifdef DEBUG_TREE
5459 xmlGenericError(xmlGenericErrorContext,
5460 "xmlNodeListDump : node == NULL\n");
5461#endif
5462 return;
5463 }
5464 while (cur != NULL) {
5465 if ((format) && (xmlIndentTreeOutput) &&
5466 (cur->type == XML_ELEMENT_NODE))
5467 for (i = 0;i < level;i++)
5468 xmlBufferWriteChar(buf, " ");
5469 xmlNodeDump(buf, doc, cur, level, format);
5470 if (format) {
5471 xmlBufferWriteChar(buf, "\n");
5472 }
5473 cur = cur->next;
5474 }
5475}
5476
5477/**
5478 * xmlNodeDump:
5479 * @buf: the XML buffer output
5480 * @doc: the document
5481 * @cur: the current node
5482 * @level: the imbrication level for indenting
5483 * @format: is formatting allowed
5484 *
5485 * Dump an XML node, recursive behaviour,children are printed too.
5486 */
5487void
5488xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5489 int format) {
5490 int i;
5491 xmlNodePtr tmp;
5492
5493 if (cur == NULL) {
5494#ifdef DEBUG_TREE
5495 xmlGenericError(xmlGenericErrorContext,
5496 "xmlNodeDump : node == NULL\n");
5497#endif
5498 return;
5499 }
5500 if (cur->type == XML_XINCLUDE_START)
5501 return;
5502 if (cur->type == XML_XINCLUDE_END)
5503 return;
5504 if (cur->type == XML_DTD_NODE) {
5505 xmlDtdDump(buf, (xmlDtdPtr) cur);
5506 return;
5507 }
5508 if (cur->type == XML_ELEMENT_DECL) {
5509 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5510 return;
5511 }
5512 if (cur->type == XML_ATTRIBUTE_DECL) {
5513 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5514 return;
5515 }
5516 if (cur->type == XML_ENTITY_DECL) {
5517 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5518 return;
5519 }
5520 if (cur->type == XML_TEXT_NODE) {
5521 if (cur->content != NULL) {
5522 if ((cur->name == xmlStringText) ||
5523 (cur->name != xmlStringTextNoenc)) {
5524 xmlChar *buffer;
5525
5526#ifndef XML_USE_BUFFER_CONTENT
5527 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5528#else
5529 buffer = xmlEncodeEntitiesReentrant(doc,
5530 xmlBufferContent(cur->content));
5531#endif
5532 if (buffer != NULL) {
5533 xmlBufferWriteCHAR(buf, buffer);
5534 xmlFree(buffer);
5535 }
5536 } else {
5537 /*
5538 * Disable escaping, needed for XSLT
5539 */
5540#ifndef XML_USE_BUFFER_CONTENT
5541 xmlBufferWriteCHAR(buf, cur->content);
5542#else
5543 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5544#endif
5545 }
5546 }
5547 return;
5548 }
5549 if (cur->type == XML_PI_NODE) {
5550 if (cur->content != NULL) {
5551 xmlBufferWriteChar(buf, "<?");
5552 xmlBufferWriteCHAR(buf, cur->name);
5553 if (cur->content != NULL) {
5554 xmlBufferWriteChar(buf, " ");
5555#ifndef XML_USE_BUFFER_CONTENT
5556 xmlBufferWriteCHAR(buf, cur->content);
5557#else
5558 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5559#endif
5560 }
5561 xmlBufferWriteChar(buf, "?>");
5562 } else {
5563 xmlBufferWriteChar(buf, "<?");
5564 xmlBufferWriteCHAR(buf, cur->name);
5565 xmlBufferWriteChar(buf, "?>");
5566 }
5567 return;
5568 }
5569 if (cur->type == XML_COMMENT_NODE) {
5570 if (cur->content != NULL) {
5571 xmlBufferWriteChar(buf, "<!--");
5572#ifndef XML_USE_BUFFER_CONTENT
5573 xmlBufferWriteCHAR(buf, cur->content);
5574#else
5575 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5576#endif
5577 xmlBufferWriteChar(buf, "-->");
5578 }
5579 return;
5580 }
5581 if (cur->type == XML_ENTITY_REF_NODE) {
5582 xmlBufferWriteChar(buf, "&");
5583 xmlBufferWriteCHAR(buf, cur->name);
5584 xmlBufferWriteChar(buf, ";");
5585 return;
5586 }
5587 if (cur->type == XML_CDATA_SECTION_NODE) {
5588 xmlBufferWriteChar(buf, "<![CDATA[");
5589 if (cur->content != NULL)
5590#ifndef XML_USE_BUFFER_CONTENT
5591 xmlBufferWriteCHAR(buf, cur->content);
5592#else
5593 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5594#endif
5595 xmlBufferWriteChar(buf, "]]>");
5596 return;
5597 }
5598
5599 if (format == 1) {
5600 tmp = cur->children;
5601 while (tmp != NULL) {
5602 if ((tmp->type == XML_TEXT_NODE) ||
5603 (tmp->type == XML_ENTITY_REF_NODE)) {
5604 format = 0;
5605 break;
5606 }
5607 tmp = tmp->next;
5608 }
5609 }
5610 xmlBufferWriteChar(buf, "<");
5611 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5612 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5613 xmlBufferWriteChar(buf, ":");
5614 }
5615
5616 xmlBufferWriteCHAR(buf, cur->name);
5617 if (cur->nsDef)
5618 xmlNsListDump(buf, cur->nsDef);
5619 if (cur->properties != NULL)
5620 xmlAttrListDump(buf, doc, cur->properties);
5621
5622 if ((cur->content == NULL) && (cur->children == NULL) &&
5623 (!xmlSaveNoEmptyTags)) {
5624 xmlBufferWriteChar(buf, "/>");
5625 return;
5626 }
5627 xmlBufferWriteChar(buf, ">");
5628 if (cur->content != NULL) {
5629 xmlChar *buffer;
5630
5631#ifndef XML_USE_BUFFER_CONTENT
5632 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5633#else
5634 buffer = xmlEncodeEntitiesReentrant(doc,
5635 xmlBufferContent(cur->content));
5636#endif
5637 if (buffer != NULL) {
5638 xmlBufferWriteCHAR(buf, buffer);
5639 xmlFree(buffer);
5640 }
5641 }
5642 if (cur->children != NULL) {
5643 if (format) xmlBufferWriteChar(buf, "\n");
5644 xmlNodeListDump(buf, doc, cur->children,
5645 (level >= 0?level+1:-1), format);
5646 if ((xmlIndentTreeOutput) && (format))
5647 for (i = 0;i < level;i++)
5648 xmlBufferWriteChar(buf, " ");
5649 }
5650 xmlBufferWriteChar(buf, "</");
5651 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5652 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5653 xmlBufferWriteChar(buf, ":");
5654 }
5655
5656 xmlBufferWriteCHAR(buf, cur->name);
5657 xmlBufferWriteChar(buf, ">");
5658}
5659
5660/**
5661 * xmlElemDump:
5662 * @f: the FILE * for the output
5663 * @doc: the document
5664 * @cur: the current node
5665 *
5666 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5667 */
5668void
5669xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5670 xmlBufferPtr buf;
5671
5672 if (cur == NULL) {
5673#ifdef DEBUG_TREE
5674 xmlGenericError(xmlGenericErrorContext,
5675 "xmlElemDump : cur == NULL\n");
5676#endif
5677 return;
5678 }
Owen Taylor3473f882001-02-23 17:55:21 +00005679#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005680 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005681 xmlGenericError(xmlGenericErrorContext,
5682 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005683 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005684#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005685 buf = xmlBufferCreate();
5686 if (buf == NULL) return;
5687 if ((doc != NULL) &&
5688 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5689#ifdef LIBXML_HTML_ENABLED
5690 htmlNodeDump(buf, doc, cur);
5691#else
5692 xmlGenericError(xmlGenericErrorContext,
5693 "HTML support not compiled in\n");
5694#endif /* LIBXML_HTML_ENABLED */
5695 } else
5696 xmlNodeDump(buf, doc, cur, 0, 1);
5697 xmlBufferDump(f, buf);
5698 xmlBufferFree(buf);
5699}
5700
5701/************************************************************************
5702 * *
5703 * Dumping XML tree content to an I/O output buffer *
5704 * *
5705 ************************************************************************/
5706
5707void
5708xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5709 int level, int format, const char *encoding);
5710static void
5711xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5712 int level, int format, const char *encoding);
5713/**
5714 * xmlNsDumpOutput:
5715 * @buf: the XML buffer output
5716 * @cur: a namespace
5717 *
5718 * Dump a local Namespace definition.
5719 * Should be called in the context of attributes dumps.
5720 */
5721static void
5722xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5723 if (cur == NULL) {
5724#ifdef DEBUG_TREE
5725 xmlGenericError(xmlGenericErrorContext,
5726 "xmlNsDump : Ns == NULL\n");
5727#endif
5728 return;
5729 }
5730 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5731 /* Within the context of an element attributes */
5732 if (cur->prefix != NULL) {
5733 xmlOutputBufferWriteString(buf, " xmlns:");
5734 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5735 } else
5736 xmlOutputBufferWriteString(buf, " xmlns");
5737 xmlOutputBufferWriteString(buf, "=");
5738 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5739 }
5740}
5741
5742/**
5743 * xmlNsListDumpOutput:
5744 * @buf: the XML buffer output
5745 * @cur: the first namespace
5746 *
5747 * Dump a list of local Namespace definitions.
5748 * Should be called in the context of attributes dumps.
5749 */
5750static void
5751xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5752 while (cur != NULL) {
5753 xmlNsDumpOutput(buf, cur);
5754 cur = cur->next;
5755 }
5756}
5757
5758/**
5759 * xmlDtdDumpOutput:
5760 * @buf: the XML buffer output
5761 * @doc: the document
5762 * @encoding: an optional encoding string
5763 *
5764 * Dump the XML document DTD, if any.
5765 */
5766static void
5767xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5768 if (dtd == NULL) {
5769#ifdef DEBUG_TREE
5770 xmlGenericError(xmlGenericErrorContext,
5771 "xmlDtdDump : no internal subset\n");
5772#endif
5773 return;
5774 }
5775 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5776 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5777 if (dtd->ExternalID != NULL) {
5778 xmlOutputBufferWriteString(buf, " PUBLIC ");
5779 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5780 xmlOutputBufferWriteString(buf, " ");
5781 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5782 } else if (dtd->SystemID != NULL) {
5783 xmlOutputBufferWriteString(buf, " SYSTEM ");
5784 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5785 }
5786 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5787 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5788 xmlOutputBufferWriteString(buf, ">");
5789 return;
5790 }
5791 xmlOutputBufferWriteString(buf, " [\n");
5792 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5793 xmlOutputBufferWriteString(buf, "]>");
5794}
5795
5796/**
5797 * xmlAttrDumpOutput:
5798 * @buf: the XML buffer output
5799 * @doc: the document
5800 * @cur: the attribute pointer
5801 * @encoding: an optional encoding string
5802 *
5803 * Dump an XML attribute
5804 */
5805static void
5806xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005807 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005808 xmlChar *value;
5809
5810 if (cur == NULL) {
5811#ifdef DEBUG_TREE
5812 xmlGenericError(xmlGenericErrorContext,
5813 "xmlAttrDump : property == NULL\n");
5814#endif
5815 return;
5816 }
5817 xmlOutputBufferWriteString(buf, " ");
5818 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5819 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5820 xmlOutputBufferWriteString(buf, ":");
5821 }
5822 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5823 value = xmlNodeListGetString(doc, cur->children, 0);
5824 if (value) {
5825 xmlOutputBufferWriteString(buf, "=");
5826 xmlBufferWriteQuotedString(buf->buffer, value);
5827 xmlFree(value);
5828 } else {
5829 xmlOutputBufferWriteString(buf, "=\"\"");
5830 }
5831}
5832
5833/**
5834 * xmlAttrListDumpOutput:
5835 * @buf: the XML buffer output
5836 * @doc: the document
5837 * @cur: the first attribute pointer
5838 * @encoding: an optional encoding string
5839 *
5840 * Dump a list of XML attributes
5841 */
5842static void
5843xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5844 xmlAttrPtr cur, const char *encoding) {
5845 if (cur == NULL) {
5846#ifdef DEBUG_TREE
5847 xmlGenericError(xmlGenericErrorContext,
5848 "xmlAttrListDump : property == NULL\n");
5849#endif
5850 return;
5851 }
5852 while (cur != NULL) {
5853 xmlAttrDumpOutput(buf, doc, cur, encoding);
5854 cur = cur->next;
5855 }
5856}
5857
5858
5859
5860/**
5861 * xmlNodeListDumpOutput:
5862 * @buf: the XML buffer output
5863 * @doc: the document
5864 * @cur: the first node
5865 * @level: the imbrication level for indenting
5866 * @format: is formatting allowed
5867 * @encoding: an optional encoding string
5868 *
5869 * Dump an XML node list, recursive behaviour,children are printed too.
5870 */
5871static void
5872xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5873 xmlNodePtr cur, int level, int format, const char *encoding) {
5874 int i;
5875
5876 if (cur == NULL) {
5877#ifdef DEBUG_TREE
5878 xmlGenericError(xmlGenericErrorContext,
5879 "xmlNodeListDump : node == NULL\n");
5880#endif
5881 return;
5882 }
5883 while (cur != NULL) {
5884 if ((format) && (xmlIndentTreeOutput) &&
5885 (cur->type == XML_ELEMENT_NODE))
5886 for (i = 0;i < level;i++)
5887 xmlOutputBufferWriteString(buf, " ");
5888 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5889 if (format) {
5890 xmlOutputBufferWriteString(buf, "\n");
5891 }
5892 cur = cur->next;
5893 }
5894}
5895
5896/**
5897 * xmlNodeDumpOutput:
5898 * @buf: the XML buffer output
5899 * @doc: the document
5900 * @cur: the current node
5901 * @level: the imbrication level for indenting
5902 * @format: is formatting allowed
5903 * @encoding: an optional encoding string
5904 *
5905 * Dump an XML node, recursive behaviour,children are printed too.
5906 */
5907void
5908xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5909 int level, int format, const char *encoding) {
5910 int i;
5911 xmlNodePtr tmp;
5912
5913 if (cur == NULL) {
5914#ifdef DEBUG_TREE
5915 xmlGenericError(xmlGenericErrorContext,
5916 "xmlNodeDump : node == NULL\n");
5917#endif
5918 return;
5919 }
5920 if (cur->type == XML_XINCLUDE_START)
5921 return;
5922 if (cur->type == XML_XINCLUDE_END)
5923 return;
5924 if (cur->type == XML_DTD_NODE) {
5925 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5926 return;
5927 }
5928 if (cur->type == XML_ELEMENT_DECL) {
5929 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5930 return;
5931 }
5932 if (cur->type == XML_ATTRIBUTE_DECL) {
5933 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5934 return;
5935 }
5936 if (cur->type == XML_ENTITY_DECL) {
5937 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5938 return;
5939 }
5940 if (cur->type == XML_TEXT_NODE) {
5941 if (cur->content != NULL) {
5942 if ((cur->name == xmlStringText) ||
5943 (cur->name != xmlStringTextNoenc)) {
5944 xmlChar *buffer;
5945
5946#ifndef XML_USE_BUFFER_CONTENT
5947 if (encoding == NULL)
5948 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5949 else
5950 buffer = xmlEncodeSpecialChars(doc, cur->content);
5951#else
5952 if (encoding == NULL)
5953 buffer = xmlEncodeEntitiesReentrant(doc,
5954 xmlBufferContent(cur->content));
5955 else
5956 buffer = xmlEncodeSpecialChars(doc,
5957 xmlBufferContent(cur->content));
5958#endif
5959 if (buffer != NULL) {
5960 xmlOutputBufferWriteString(buf, (const char *)buffer);
5961 xmlFree(buffer);
5962 }
5963 } else {
5964 /*
5965 * Disable escaping, needed for XSLT
5966 */
5967#ifndef XML_USE_BUFFER_CONTENT
5968 xmlOutputBufferWriteString(buf, (const char *) cur->content);
5969#else
5970 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5971#endif
5972 }
5973 }
5974
5975 return;
5976 }
5977 if (cur->type == XML_PI_NODE) {
5978 if (cur->content != NULL) {
5979 xmlOutputBufferWriteString(buf, "<?");
5980 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5981 if (cur->content != NULL) {
5982 xmlOutputBufferWriteString(buf, " ");
5983#ifndef XML_USE_BUFFER_CONTENT
5984 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5985#else
5986 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5987#endif
5988 }
5989 xmlOutputBufferWriteString(buf, "?>");
5990 } else {
5991 xmlOutputBufferWriteString(buf, "<?");
5992 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5993 xmlOutputBufferWriteString(buf, "?>");
5994 }
5995 return;
5996 }
5997 if (cur->type == XML_COMMENT_NODE) {
5998 if (cur->content != NULL) {
5999 xmlOutputBufferWriteString(buf, "<!--");
6000#ifndef XML_USE_BUFFER_CONTENT
6001 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6002#else
6003 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6004#endif
6005 xmlOutputBufferWriteString(buf, "-->");
6006 }
6007 return;
6008 }
6009 if (cur->type == XML_ENTITY_REF_NODE) {
6010 xmlOutputBufferWriteString(buf, "&");
6011 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6012 xmlOutputBufferWriteString(buf, ";");
6013 return;
6014 }
6015 if (cur->type == XML_CDATA_SECTION_NODE) {
6016 xmlOutputBufferWriteString(buf, "<![CDATA[");
6017 if (cur->content != NULL)
6018#ifndef XML_USE_BUFFER_CONTENT
6019 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6020#else
6021 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6022#endif
6023 xmlOutputBufferWriteString(buf, "]]>");
6024 return;
6025 }
6026
6027 if (format == 1) {
6028 tmp = cur->children;
6029 while (tmp != NULL) {
6030 if ((tmp->type == XML_TEXT_NODE) ||
6031 (tmp->type == XML_ENTITY_REF_NODE)) {
6032 format = 0;
6033 break;
6034 }
6035 tmp = tmp->next;
6036 }
6037 }
6038 xmlOutputBufferWriteString(buf, "<");
6039 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6040 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6041 xmlOutputBufferWriteString(buf, ":");
6042 }
6043
6044 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6045 if (cur->nsDef)
6046 xmlNsListDumpOutput(buf, cur->nsDef);
6047 if (cur->properties != NULL)
6048 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6049
6050 if ((cur->content == NULL) && (cur->children == NULL) &&
6051 (!xmlSaveNoEmptyTags)) {
6052 xmlOutputBufferWriteString(buf, "/>");
6053 return;
6054 }
6055 xmlOutputBufferWriteString(buf, ">");
6056 if (cur->content != NULL) {
6057 xmlChar *buffer;
6058
6059#ifndef XML_USE_BUFFER_CONTENT
6060 if (encoding == NULL)
6061 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6062 else
6063 buffer = xmlEncodeSpecialChars(doc, cur->content);
6064#else
6065 if (encoding == NULL)
6066 buffer = xmlEncodeEntitiesReentrant(doc,
6067 xmlBufferContent(cur->content));
6068 else
6069 buffer = xmlEncodeSpecialChars(doc,
6070 xmlBufferContent(cur->content));
6071#endif
6072 if (buffer != NULL) {
6073 xmlOutputBufferWriteString(buf, (const char *)buffer);
6074 xmlFree(buffer);
6075 }
6076 }
6077 if (cur->children != NULL) {
6078 if (format) xmlOutputBufferWriteString(buf, "\n");
6079 xmlNodeListDumpOutput(buf, doc, cur->children,
6080 (level >= 0?level+1:-1), format, encoding);
6081 if ((xmlIndentTreeOutput) && (format))
6082 for (i = 0;i < level;i++)
6083 xmlOutputBufferWriteString(buf, " ");
6084 }
6085 xmlOutputBufferWriteString(buf, "</");
6086 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6087 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6088 xmlOutputBufferWriteString(buf, ":");
6089 }
6090
6091 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6092 xmlOutputBufferWriteString(buf, ">");
6093}
6094
6095/**
6096 * xmlDocContentDumpOutput:
6097 * @buf: the XML buffer output
6098 * @cur: the document
6099 * @encoding: an optional encoding string
6100 * @format: should formatting spaces been added
6101 *
6102 * Dump an XML document.
6103 */
6104static void
6105xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6106 const char *encoding, int format) {
6107 xmlOutputBufferWriteString(buf, "<?xml version=");
6108 if (cur->version != NULL)
6109 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6110 else
6111 xmlOutputBufferWriteString(buf, "\"1.0\"");
6112 if (encoding == NULL) {
6113 if (cur->encoding != NULL)
6114 encoding = (const char *) cur->encoding;
6115 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6116 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6117 }
6118 if (encoding != NULL) {
6119 xmlOutputBufferWriteString(buf, " encoding=");
6120 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6121 }
6122 switch (cur->standalone) {
6123 case 0:
6124 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6125 break;
6126 case 1:
6127 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6128 break;
6129 }
6130 xmlOutputBufferWriteString(buf, "?>\n");
6131 if (cur->children != NULL) {
6132 xmlNodePtr child = cur->children;
6133
6134 while (child != NULL) {
6135 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6136 xmlOutputBufferWriteString(buf, "\n");
6137 child = child->next;
6138 }
6139 }
6140}
6141
6142/************************************************************************
6143 * *
6144 * Saving functions front-ends *
6145 * *
6146 ************************************************************************/
6147
6148/**
6149 * xmlDocDumpMemoryEnc:
6150 * @out_doc: Document to generate XML text from
6151 * @doc_txt_ptr: Memory pointer for allocated XML text
6152 * @doc_txt_len: Length of the generated XML text
6153 * @txt_encoding: Character encoding to use when generating XML text
6154 * @format: should formatting spaces been added
6155 *
6156 * Dump the current DOM tree into memory using the character encoding specified
6157 * by the caller. Note it is up to the caller of this function to free the
6158 * allocated memory.
6159 */
6160
6161void
6162xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006163 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006164 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006165 int dummy = 0;
6166
6167 xmlCharEncoding doc_charset;
6168 xmlOutputBufferPtr out_buff = NULL;
6169 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6170
6171 if (doc_txt_len == NULL) {
6172 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6173 }
6174
6175 if (doc_txt_ptr == NULL) {
6176 *doc_txt_len = 0;
6177 xmlGenericError(xmlGenericErrorContext,
6178 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6179 return;
6180 }
6181
6182 *doc_txt_ptr = NULL;
6183 *doc_txt_len = 0;
6184
6185 if (out_doc == NULL) {
6186 /* No document, no output */
6187 xmlGenericError(xmlGenericErrorContext,
6188 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6189 return;
6190 }
6191
6192 /*
6193 * Validate the encoding value, if provided.
6194 * This logic is copied from xmlSaveFileEnc.
6195 */
6196
6197 if (txt_encoding == NULL)
6198 txt_encoding = (const char *) out_doc->encoding;
6199 if (txt_encoding != NULL) {
6200 doc_charset = xmlParseCharEncoding(txt_encoding);
6201
6202 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6203 xmlGenericError(xmlGenericErrorContext,
6204 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6205 return;
6206
6207 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6208 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6209 if ( conv_hdlr == NULL ) {
6210 xmlGenericError(xmlGenericErrorContext,
6211 "%s: %s %s '%s'\n",
6212 "xmlDocDumpFormatMemoryEnc",
6213 "Failed to identify encoding handler for",
6214 "character set",
6215 txt_encoding);
6216 return;
6217 }
6218 }
6219 }
6220
6221 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6222 xmlGenericError(xmlGenericErrorContext,
6223 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6224 return;
6225 }
6226
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006227 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006228 xmlOutputBufferFlush(out_buff);
6229 if (out_buff->conv != NULL) {
6230 *doc_txt_len = out_buff->conv->use;
6231 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6232 } else {
6233 *doc_txt_len = out_buff->buffer->use;
6234 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6235 }
6236 (void)xmlOutputBufferClose(out_buff);
6237
6238 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6239 *doc_txt_len = 0;
6240 xmlGenericError(xmlGenericErrorContext,
6241 "xmlDocDumpFormatMemoryEnc: %s\n",
6242 "Failed to allocate memory for document text representation.");
6243 }
6244
6245 return;
6246}
6247
6248/**
6249 * xmlDocDumpMemory:
6250 * @cur: the document
6251 * @mem: OUT: the memory pointer
6252 * @size: OUT: the memory lenght
6253 *
6254 * Dump an XML document in memory and return the xmlChar * and it's size.
6255 * It's up to the caller to free the memory.
6256 */
6257void
6258xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6259 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6260}
6261
6262/**
6263 * xmlDocDumpFormatMemory:
6264 * @cur: the document
6265 * @mem: OUT: the memory pointer
6266 * @size: OUT: the memory lenght
6267 * @format: should formatting spaces been added
6268 *
6269 *
6270 * Dump an XML document in memory and return the xmlChar * and it's size.
6271 * It's up to the caller to free the memory.
6272 */
6273void
6274xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6275 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6276}
6277
6278/**
6279 * xmlDocDumpMemoryEnc:
6280 * @out_doc: Document to generate XML text from
6281 * @doc_txt_ptr: Memory pointer for allocated XML text
6282 * @doc_txt_len: Length of the generated XML text
6283 * @txt_encoding: Character encoding to use when generating XML text
6284 *
6285 * Dump the current DOM tree into memory using the character encoding specified
6286 * by the caller. Note it is up to the caller of this function to free the
6287 * allocated memory.
6288 */
6289
6290void
6291xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6292 int * doc_txt_len, const char * txt_encoding) {
6293 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006294 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006295}
6296
6297/**
6298 * xmlGetDocCompressMode:
6299 * @doc: the document
6300 *
6301 * get the compression ratio for a document, ZLIB based
6302 * Returns 0 (uncompressed) to 9 (max compression)
6303 */
6304int
6305xmlGetDocCompressMode (xmlDocPtr doc) {
6306 if (doc == NULL) return(-1);
6307 return(doc->compression);
6308}
6309
6310/**
6311 * xmlSetDocCompressMode:
6312 * @doc: the document
6313 * @mode: the compression ratio
6314 *
6315 * set the compression ratio for a document, ZLIB based
6316 * Correct values: 0 (uncompressed) to 9 (max compression)
6317 */
6318void
6319xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6320 if (doc == NULL) return;
6321 if (mode < 0) doc->compression = 0;
6322 else if (mode > 9) doc->compression = 9;
6323 else doc->compression = mode;
6324}
6325
6326/**
6327 * xmlGetCompressMode:
6328 *
6329 * get the default compression mode used, ZLIB based.
6330 * Returns 0 (uncompressed) to 9 (max compression)
6331 */
6332int
6333 xmlGetCompressMode(void) {
6334 return(xmlCompressMode);
6335}
6336
6337/**
6338 * xmlSetCompressMode:
6339 * @mode: the compression ratio
6340 *
6341 * set the default compression mode used, ZLIB based
6342 * Correct values: 0 (uncompressed) to 9 (max compression)
6343 */
6344void
6345xmlSetCompressMode(int mode) {
6346 if (mode < 0) xmlCompressMode = 0;
6347 else if (mode > 9) xmlCompressMode = 9;
6348 else xmlCompressMode = mode;
6349}
6350
6351/**
6352 * xmlDocDump:
6353 * @f: the FILE*
6354 * @cur: the document
6355 *
6356 * Dump an XML document to an open FILE.
6357 *
6358 * returns: the number of byte written or -1 in case of failure.
6359 */
6360int
6361xmlDocDump(FILE *f, xmlDocPtr cur) {
6362 xmlOutputBufferPtr buf;
6363 const char * encoding;
6364 xmlCharEncodingHandlerPtr handler = NULL;
6365 int ret;
6366
6367 if (cur == NULL) {
6368#ifdef DEBUG_TREE
6369 xmlGenericError(xmlGenericErrorContext,
6370 "xmlDocDump : document == NULL\n");
6371#endif
6372 return(-1);
6373 }
6374 encoding = (const char *) cur->encoding;
6375
6376 if (encoding != NULL) {
6377 xmlCharEncoding enc;
6378
6379 enc = xmlParseCharEncoding(encoding);
6380
6381 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6382 xmlGenericError(xmlGenericErrorContext,
6383 "xmlDocDump: document not in UTF8\n");
6384 return(-1);
6385 }
6386 if (enc != XML_CHAR_ENCODING_UTF8) {
6387 handler = xmlFindCharEncodingHandler(encoding);
6388 if (handler == NULL) {
6389 xmlFree((char *) cur->encoding);
6390 cur->encoding = NULL;
6391 }
6392 }
6393 }
6394 buf = xmlOutputBufferCreateFile(f, handler);
6395 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006396 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006397
6398 ret = xmlOutputBufferClose(buf);
6399 return(ret);
6400}
6401
6402/**
6403 * xmlSaveFileTo:
6404 * @buf: an output I/O buffer
6405 * @cur: the document
6406 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6407 *
6408 * Dump an XML document to an I/O buffer.
6409 *
6410 * returns: the number of byte written or -1 in case of failure.
6411 */
6412int
6413xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
6414 int ret;
6415
6416 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006417 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006418 ret = xmlOutputBufferClose(buf);
6419 return(ret);
6420}
6421
6422/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006423 * xmlSaveFormatFileTo:
6424 * @buf: an output I/O buffer
6425 * @cur: the document
6426 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6427 * @format: should formatting spaces been added
6428 *
6429 * Dump an XML document to an I/O buffer.
6430 *
6431 * returns: the number of byte written or -1 in case of failure.
6432 */
6433int
6434xmlSaveFormatFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding, int format) {
6435 int ret;
6436
6437 if (buf == NULL) return(0);
6438 xmlDocContentDumpOutput(buf, cur, encoding, format);
6439 ret = xmlOutputBufferClose(buf);
6440 return(ret);
6441}
6442
6443/**
Owen Taylor3473f882001-02-23 17:55:21 +00006444 * xmlSaveFileEnc:
6445 * @filename: the filename (or URL)
6446 * @cur: the document
6447 * @encoding: the name of an encoding (or NULL)
6448 *
6449 * Dump an XML document, converting it to the given encoding
6450 *
6451 * returns: the number of byte written or -1 in case of failure.
6452 */
6453int
6454xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6455 xmlOutputBufferPtr buf;
6456 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006457 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006458 int ret;
6459
6460 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006461
6462 enc = xmlParseCharEncoding(encoding);
6463 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6464 xmlGenericError(xmlGenericErrorContext,
6465 "xmlSaveFileEnc: document not in UTF8\n");
6466 return(-1);
6467 }
6468 if (enc != XML_CHAR_ENCODING_UTF8) {
6469 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006470 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006471 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006472 }
6473 }
6474
6475 /*
6476 * save the content to a temp buffer.
6477 */
6478 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
6479 if (buf == NULL) return(-1);
6480
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006481 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006482
6483 ret = xmlOutputBufferClose(buf);
6484 return(ret);
6485}
6486
6487/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006488 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006489 * @filename: the filename (or URL)
6490 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006491 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006492 *
6493 * Dump an XML document to a file. Will use compression if
6494 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillard67fee942001-04-26 18:59:03 +00006495 * used. If format is set then the document will be indented on output.
6496 *
Owen Taylor3473f882001-02-23 17:55:21 +00006497 * returns: the number of byte written or -1 in case of failure.
6498 */
6499int
Daniel Veillard67fee942001-04-26 18:59:03 +00006500xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006501 xmlOutputBufferPtr buf;
6502 const char *encoding;
6503 xmlCharEncodingHandlerPtr handler = NULL;
6504 int ret;
6505
6506 if (cur == NULL)
6507 return(-1);
6508 encoding = (const char *) cur->encoding;
6509
6510 /*
6511 * save the content to a temp buffer.
6512 */
6513#ifdef HAVE_ZLIB_H
6514 if (cur->compression < 0) cur->compression = xmlCompressMode;
6515#endif
6516 if (encoding != NULL) {
6517 xmlCharEncoding enc;
6518
6519 enc = xmlParseCharEncoding(encoding);
6520
6521 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6522 xmlGenericError(xmlGenericErrorContext,
6523 "xmlSaveFile: document not in UTF8\n");
6524 return(-1);
6525 }
6526 if (enc != XML_CHAR_ENCODING_UTF8) {
6527 handler = xmlFindCharEncodingHandler(encoding);
6528 if (handler == NULL) {
6529 xmlFree((char *) cur->encoding);
6530 cur->encoding = NULL;
6531 }
6532 }
6533 }
6534
6535 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
6536 if (buf == NULL) return(-1);
6537
Daniel Veillard67fee942001-04-26 18:59:03 +00006538 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006539
6540 ret = xmlOutputBufferClose(buf);
6541 return(ret);
6542}
6543
Daniel Veillard67fee942001-04-26 18:59:03 +00006544/**
6545 * xmlSaveFile:
6546 * @filename: the filename (or URL)
6547 * @cur: the document
6548 *
6549 * Dump an XML document to a file. Will use compression if
6550 * compiled in and enabled. If @filename is "-" the stdout file is
6551 * used.
6552 * returns: the number of byte written or -1 in case of failure.
6553 */
6554int
6555xmlSaveFile(const char *filename, xmlDocPtr cur) {
6556 return(xmlSaveFormatFile(filename, cur, 0));
6557}
6558