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