blob: 5027fcfad5ade39793c67f34225278e052589792 [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
2372 if ((cur->name != NULL) &&
2373 (cur->name != xmlStringText) &&
2374 (cur->name != xmlStringTextNoenc) &&
2375 (cur->name != xmlStringComment))
2376 xmlFree((char *) cur->name);
2377 /* TODO : derecursivate this function */
2378 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
2379 xmlFree(cur);
2380 }
Owen Taylor3473f882001-02-23 17:55:21 +00002381 cur = next;
2382 }
2383}
2384
2385/**
2386 * xmlFreeNode:
2387 * @cur: the node
2388 *
2389 * Free a node, this is a recursive behaviour, all the children are freed too.
2390 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2391 */
2392void
2393xmlFreeNode(xmlNodePtr cur) {
2394 if (cur == NULL) {
2395#ifdef DEBUG_TREE
2396 xmlGenericError(xmlGenericErrorContext,
2397 "xmlFreeNode : node == NULL\n");
2398#endif
2399 return;
2400 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002401 /* use xmlFreeDtd for DTD nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002402 if (cur->type == XML_DTD_NODE)
2403 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002404 if ((cur->children != NULL) &&
2405 (cur->type != XML_ENTITY_REF_NODE))
2406 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002407 if (cur->properties != NULL)
2408 xmlFreePropList(cur->properties);
Owen Taylor3473f882001-02-23 17:55:21 +00002409 if (cur->type != XML_ENTITY_REF_NODE)
2410#ifndef XML_USE_BUFFER_CONTENT
2411 if (cur->content != NULL) xmlFree(cur->content);
2412#else
2413 if (cur->content != NULL) xmlBufferFree(cur->content);
2414#endif
2415 if ((cur->name != NULL) &&
2416 (cur->name != xmlStringText) &&
2417 (cur->name != xmlStringTextNoenc) &&
2418 (cur->name != xmlStringComment))
2419 xmlFree((char *) cur->name);
2420 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002421 xmlFree(cur);
2422}
2423
2424/**
2425 * xmlUnlinkNode:
2426 * @cur: the node
2427 *
2428 * Unlink a node from it's current context, the node is not freed
2429 */
2430void
2431xmlUnlinkNode(xmlNodePtr cur) {
2432 if (cur == NULL) {
2433#ifdef DEBUG_TREE
2434 xmlGenericError(xmlGenericErrorContext,
2435 "xmlUnlinkNode : node == NULL\n");
2436#endif
2437 return;
2438 }
2439 if ((cur->parent != NULL) && (cur->parent->children == cur))
2440 cur->parent->children = cur->next;
2441 if ((cur->parent != NULL) && (cur->parent->last == cur))
2442 cur->parent->last = cur->prev;
2443 if (cur->next != NULL)
2444 cur->next->prev = cur->prev;
2445 if (cur->prev != NULL)
2446 cur->prev->next = cur->next;
2447 cur->next = cur->prev = NULL;
2448 cur->parent = NULL;
2449}
2450
2451/**
2452 * xmlReplaceNode:
2453 * @old: the old node
2454 * @cur: the node
2455 *
2456 * Unlink the old node from it's current context, prune the new one
2457 * at the same place. If cur was already inserted in a document it is
2458 * first unlinked from its existing context.
2459 *
2460 * Returns the old node
2461 */
2462xmlNodePtr
2463xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2464 if (old == NULL) {
2465#ifdef DEBUG_TREE
2466 xmlGenericError(xmlGenericErrorContext,
2467 "xmlReplaceNode : old == NULL\n");
2468#endif
2469 return(NULL);
2470 }
2471 if (cur == NULL) {
2472 xmlUnlinkNode(old);
2473 return(old);
2474 }
2475 if (cur == old) {
2476 return(old);
2477 }
2478 xmlUnlinkNode(cur);
2479 cur->doc = old->doc;
2480 cur->parent = old->parent;
2481 cur->next = old->next;
2482 if (cur->next != NULL)
2483 cur->next->prev = cur;
2484 cur->prev = old->prev;
2485 if (cur->prev != NULL)
2486 cur->prev->next = cur;
2487 if (cur->parent != NULL) {
2488 if (cur->parent->children == old)
2489 cur->parent->children = cur;
2490 if (cur->parent->last == old)
2491 cur->parent->last = cur;
2492 }
2493 old->next = old->prev = NULL;
2494 old->parent = NULL;
2495 return(old);
2496}
2497
2498/************************************************************************
2499 * *
2500 * Copy operations *
2501 * *
2502 ************************************************************************/
2503
2504/**
2505 * xmlCopyNamespace:
2506 * @cur: the namespace
2507 *
2508 * Do a copy of the namespace.
2509 *
2510 * Returns: a new xmlNsPtr, or NULL in case of error.
2511 */
2512xmlNsPtr
2513xmlCopyNamespace(xmlNsPtr cur) {
2514 xmlNsPtr ret;
2515
2516 if (cur == NULL) return(NULL);
2517 switch (cur->type) {
2518 case XML_LOCAL_NAMESPACE:
2519 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2520 break;
2521 default:
2522#ifdef DEBUG_TREE
2523 xmlGenericError(xmlGenericErrorContext,
2524 "xmlCopyNamespace: invalid type %d\n", cur->type);
2525#endif
2526 return(NULL);
2527 }
2528 return(ret);
2529}
2530
2531/**
2532 * xmlCopyNamespaceList:
2533 * @cur: the first namespace
2534 *
2535 * Do a copy of an namespace list.
2536 *
2537 * Returns: a new xmlNsPtr, or NULL in case of error.
2538 */
2539xmlNsPtr
2540xmlCopyNamespaceList(xmlNsPtr cur) {
2541 xmlNsPtr ret = NULL;
2542 xmlNsPtr p = NULL,q;
2543
2544 while (cur != NULL) {
2545 q = xmlCopyNamespace(cur);
2546 if (p == NULL) {
2547 ret = p = q;
2548 } else {
2549 p->next = q;
2550 p = q;
2551 }
2552 cur = cur->next;
2553 }
2554 return(ret);
2555}
2556
2557static xmlNodePtr
2558xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2559/**
2560 * xmlCopyProp:
2561 * @target: the element where the attribute will be grafted
2562 * @cur: the attribute
2563 *
2564 * Do a copy of the attribute.
2565 *
2566 * Returns: a new xmlAttrPtr, or NULL in case of error.
2567 */
2568xmlAttrPtr
2569xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2570 xmlAttrPtr ret;
2571
2572 if (cur == NULL) return(NULL);
2573 if (target != NULL)
2574 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2575 else if (cur->parent != NULL)
2576 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2577 else if (cur->children != NULL)
2578 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2579 else
2580 ret = xmlNewDocProp(NULL, cur->name, NULL);
2581 if (ret == NULL) return(NULL);
2582 ret->parent = target;
2583
2584 if ((cur->ns != NULL) && (target != NULL)) {
2585 xmlNsPtr ns;
2586
2587 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2588 ret->ns = ns;
2589 } else
2590 ret->ns = NULL;
2591
2592 if (cur->children != NULL) {
2593 xmlNodePtr tmp;
2594
2595 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2596 ret->last = NULL;
2597 tmp = ret->children;
2598 while (tmp != NULL) {
2599 /* tmp->parent = (xmlNodePtr)ret; */
2600 if (tmp->next == NULL)
2601 ret->last = tmp;
2602 tmp = tmp->next;
2603 }
2604 }
2605 return(ret);
2606}
2607
2608/**
2609 * xmlCopyPropList:
2610 * @target: the element where the attributes will be grafted
2611 * @cur: the first attribute
2612 *
2613 * Do a copy of an attribute list.
2614 *
2615 * Returns: a new xmlAttrPtr, or NULL in case of error.
2616 */
2617xmlAttrPtr
2618xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2619 xmlAttrPtr ret = NULL;
2620 xmlAttrPtr p = NULL,q;
2621
2622 while (cur != NULL) {
2623 q = xmlCopyProp(target, cur);
2624 if (p == NULL) {
2625 ret = p = q;
2626 } else {
2627 p->next = q;
2628 q->prev = p;
2629 p = q;
2630 }
2631 cur = cur->next;
2632 }
2633 return(ret);
2634}
2635
2636/*
2637 * NOTE abeut the CopyNode operations !
2638 *
2639 * They are splitted into external and internal parts for one
2640 * tricky reason: namespaces. Doing a direct copy of a node
2641 * say RPM:Copyright without changing the namespace pointer to
2642 * something else can produce stale links. One way to do it is
2643 * to keep a reference counter but this doesn't work as soon
2644 * as one move the element or the subtree out of the scope of
2645 * the existing namespace. The actual solution seems to add
2646 * a copy of the namespace at the top of the copied tree if
2647 * not available in the subtree.
2648 * Hence two functions, the public front-end call the inner ones
2649 */
2650
2651static xmlNodePtr
2652xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2653
2654static xmlNodePtr
2655xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2656 int recursive) {
2657 xmlNodePtr ret;
2658
2659 if (node == NULL) return(NULL);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002660
Owen Taylor3473f882001-02-23 17:55:21 +00002661 /*
2662 * Allocate a new node and fill the fields.
2663 */
2664 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2665 if (ret == NULL) {
2666 xmlGenericError(xmlGenericErrorContext,
2667 "xmlStaticCopyNode : malloc failed\n");
2668 return(NULL);
2669 }
2670 memset(ret, 0, sizeof(xmlNode));
2671 ret->type = node->type;
2672
2673 ret->doc = doc;
2674 ret->parent = parent;
2675 if (node->name == xmlStringText)
2676 ret->name = xmlStringText;
2677 else if (node->name == xmlStringTextNoenc)
2678 ret->name = xmlStringTextNoenc;
2679 else if (node->name == xmlStringComment)
2680 ret->name = xmlStringComment;
2681 else if (node->name != NULL)
2682 ret->name = xmlStrdup(node->name);
2683 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2684#ifndef XML_USE_BUFFER_CONTENT
2685 ret->content = xmlStrdup(node->content);
2686#else
2687 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2688 xmlBufferSetAllocationScheme(ret->content,
2689 xmlGetBufferAllocationScheme());
2690 xmlBufferAdd(ret->content,
2691 xmlBufferContent(node->content),
2692 xmlBufferLength(node->content));
2693#endif
2694 }
2695 if (parent != NULL)
2696 xmlAddChild(parent, ret);
2697
2698 if (!recursive) return(ret);
2699 if (node->nsDef != NULL)
2700 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2701
2702 if (node->ns != NULL) {
2703 xmlNsPtr ns;
2704
2705 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2706 if (ns == NULL) {
2707 /*
2708 * Humm, we are copying an element whose namespace is defined
2709 * out of the new tree scope. Search it in the original tree
2710 * and add it at the top of the new tree
2711 */
2712 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2713 if (ns != NULL) {
2714 xmlNodePtr root = ret;
2715
2716 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002717 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002718 }
2719 } else {
2720 /*
2721 * reference the existing namespace definition in our own tree.
2722 */
2723 ret->ns = ns;
2724 }
2725 }
2726 if (node->properties != NULL)
2727 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002728 if (node->type == XML_ENTITY_REF_NODE) {
2729 if ((doc == NULL) || (node->doc != doc)) {
2730 /*
2731 * The copied node will go into a separate document, so
2732 * to havoid dandling references to the ENTITY_DECL node
2733 * we cannot keep the reference. Try to find it in the
2734 * target document.
2735 */
2736 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2737 } else {
2738 ret->children = node->children;
2739 }
2740 } else if (node->children != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002741 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
2742 UPDATE_LAST_CHILD_AND_PARENT(ret)
2743 return(ret);
2744}
2745
2746static xmlNodePtr
2747xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2748 xmlNodePtr ret = NULL;
2749 xmlNodePtr p = NULL,q;
2750
2751 while (node != NULL) {
Daniel Veillardb33c2012001-04-25 12:59:04 +00002752 if( node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002753 if (doc == NULL) {
2754 node = node->next;
2755 continue;
2756 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002757 if (doc->intSubset == NULL) {
2758 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2759 q->doc = doc;
2760 q->parent = parent;
2761 doc->intSubset = (xmlDtdPtr) q;
2762 } else {
2763 q = (xmlNodePtr) doc->intSubset;
2764 }
2765 } else
2766 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002767 if (ret == NULL) {
2768 q->prev = NULL;
2769 ret = p = q;
2770 } else {
2771 p->next = q;
2772 q->prev = p;
2773 p = q;
2774 }
2775 node = node->next;
2776 }
2777 return(ret);
2778}
2779
2780/**
2781 * xmlCopyNode:
2782 * @node: the node
2783 * @recursive: if 1 do a recursive copy.
2784 *
2785 * Do a copy of the node.
2786 *
2787 * Returns: a new xmlNodePtr, or NULL in case of error.
2788 */
2789xmlNodePtr
2790xmlCopyNode(xmlNodePtr node, int recursive) {
2791 xmlNodePtr ret;
2792
2793 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2794 return(ret);
2795}
2796
2797/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002798 * xmlDocCopyNode:
2799 * @node: the node
2800 * @recursive: if 1 do a recursive copy.
2801 *
2802 * Do a copy of the node to a given document.
2803 *
2804 * Returns: a new xmlNodePtr, or NULL in case of error.
2805 */
2806xmlNodePtr
2807xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int recursive) {
2808 xmlNodePtr ret;
2809
2810 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2811 return(ret);
2812}
2813
2814/**
Owen Taylor3473f882001-02-23 17:55:21 +00002815 * xmlCopyNodeList:
2816 * @node: the first node in the list.
2817 *
2818 * Do a recursive copy of the node list.
2819 *
2820 * Returns: a new xmlNodePtr, or NULL in case of error.
2821 */
2822xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2823 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2824 return(ret);
2825}
2826
2827/**
2828 * xmlCopyElement:
2829 * @elem: the element
2830 *
2831 * Do a copy of the element definition.
2832 *
2833 * Returns: a new xmlElementPtr, or NULL in case of error.
2834xmlElementPtr
2835xmlCopyElement(xmlElementPtr elem) {
2836 xmlElementPtr ret;
2837
2838 if (elem == NULL) return(NULL);
2839 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2840 if (ret == NULL) return(NULL);
2841 if (!recursive) return(ret);
2842 if (elem->properties != NULL)
2843 ret->properties = xmlCopyPropList(elem->properties);
2844
2845 if (elem->nsDef != NULL)
2846 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
2847 if (elem->children != NULL)
2848 ret->children = xmlCopyElementList(elem->children);
2849 return(ret);
2850}
2851 */
2852
2853/**
2854 * xmlCopyDtd:
2855 * @dtd: the dtd
2856 *
2857 * Do a copy of the dtd.
2858 *
2859 * Returns: a new xmlDtdPtr, or NULL in case of error.
2860 */
2861xmlDtdPtr
2862xmlCopyDtd(xmlDtdPtr dtd) {
2863 xmlDtdPtr ret;
2864
2865 if (dtd == NULL) return(NULL);
2866 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2867 if (ret == NULL) return(NULL);
2868 if (dtd->entities != NULL)
2869 ret->entities = (void *) xmlCopyEntitiesTable(
2870 (xmlEntitiesTablePtr) dtd->entities);
2871 if (dtd->notations != NULL)
2872 ret->notations = (void *) xmlCopyNotationTable(
2873 (xmlNotationTablePtr) dtd->notations);
2874 if (dtd->elements != NULL)
2875 ret->elements = (void *) xmlCopyElementTable(
2876 (xmlElementTablePtr) dtd->elements);
2877 if (dtd->attributes != NULL)
2878 ret->attributes = (void *) xmlCopyAttributeTable(
2879 (xmlAttributeTablePtr) dtd->attributes);
2880 return(ret);
2881}
2882
2883/**
2884 * xmlCopyDoc:
2885 * @doc: the document
2886 * @recursive: if 1 do a recursive copy.
2887 *
2888 * Do a copy of the document info. If recursive, the content tree will
2889 * be copied too as well as Dtd, namespaces and entities.
2890 *
2891 * Returns: a new xmlDocPtr, or NULL in case of error.
2892 */
2893xmlDocPtr
2894xmlCopyDoc(xmlDocPtr doc, int recursive) {
2895 xmlDocPtr ret;
2896
2897 if (doc == NULL) return(NULL);
2898 ret = xmlNewDoc(doc->version);
2899 if (ret == NULL) return(NULL);
2900 if (doc->name != NULL)
2901 ret->name = xmlMemStrdup(doc->name);
2902 if (doc->encoding != NULL)
2903 ret->encoding = xmlStrdup(doc->encoding);
2904 ret->charset = doc->charset;
2905 ret->compression = doc->compression;
2906 ret->standalone = doc->standalone;
2907 if (!recursive) return(ret);
2908
Daniel Veillardb33c2012001-04-25 12:59:04 +00002909 ret->last = NULL;
2910 ret->children = NULL;
2911 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002912 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002913 ret->intSubset->doc = ret;
2914 ret->intSubset->parent = ret;
2915 }
Owen Taylor3473f882001-02-23 17:55:21 +00002916 if (doc->oldNs != NULL)
2917 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2918 if (doc->children != NULL) {
2919 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002920
2921 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2922 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002923 ret->last = NULL;
2924 tmp = ret->children;
2925 while (tmp != NULL) {
2926 if (tmp->next == NULL)
2927 ret->last = tmp;
2928 tmp = tmp->next;
2929 }
2930 }
2931 return(ret);
2932}
2933
2934/************************************************************************
2935 * *
2936 * Content access functions *
2937 * *
2938 ************************************************************************/
2939
2940/**
2941 * xmlDocGetRootElement:
2942 * @doc: the document
2943 *
2944 * Get the root element of the document (doc->children is a list
2945 * containing possibly comments, PIs, etc ...).
2946 *
2947 * Returns the xmlNodePtr for the root or NULL
2948 */
2949xmlNodePtr
2950xmlDocGetRootElement(xmlDocPtr doc) {
2951 xmlNodePtr ret;
2952
2953 if (doc == NULL) return(NULL);
2954 ret = doc->children;
2955 while (ret != NULL) {
2956 if (ret->type == XML_ELEMENT_NODE)
2957 return(ret);
2958 ret = ret->next;
2959 }
2960 return(ret);
2961}
2962
2963/**
2964 * xmlDocSetRootElement:
2965 * @doc: the document
2966 * @root: the new document root element
2967 *
2968 * Set the root element of the document (doc->children is a list
2969 * containing possibly comments, PIs, etc ...).
2970 *
2971 * Returns the old root element if any was found
2972 */
2973xmlNodePtr
2974xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2975 xmlNodePtr old = NULL;
2976
2977 if (doc == NULL) return(NULL);
2978 old = doc->children;
2979 while (old != NULL) {
2980 if (old->type == XML_ELEMENT_NODE)
2981 break;
2982 old = old->next;
2983 }
2984 if (old == NULL) {
2985 if (doc->children == NULL) {
2986 doc->children = root;
2987 doc->last = root;
2988 } else {
2989 xmlAddSibling(doc->children, root);
2990 }
2991 } else {
2992 xmlReplaceNode(old, root);
2993 }
2994 return(old);
2995}
2996
2997/**
2998 * xmlNodeSetLang:
2999 * @cur: the node being changed
3000 * @lang: the langage description
3001 *
3002 * Set the language of a node, i.e. the values of the xml:lang
3003 * attribute.
3004 */
3005void
3006xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3007 if (cur == NULL) return;
3008 switch(cur->type) {
3009 case XML_TEXT_NODE:
3010 case XML_CDATA_SECTION_NODE:
3011 case XML_COMMENT_NODE:
3012 case XML_DOCUMENT_NODE:
3013 case XML_DOCUMENT_TYPE_NODE:
3014 case XML_DOCUMENT_FRAG_NODE:
3015 case XML_NOTATION_NODE:
3016 case XML_HTML_DOCUMENT_NODE:
3017 case XML_DTD_NODE:
3018 case XML_ELEMENT_DECL:
3019 case XML_ATTRIBUTE_DECL:
3020 case XML_ENTITY_DECL:
3021 case XML_PI_NODE:
3022 case XML_ENTITY_REF_NODE:
3023 case XML_ENTITY_NODE:
3024 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003025#ifdef LIBXML_DOCB_ENABLED
3026 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003027#endif
3028 case XML_XINCLUDE_START:
3029 case XML_XINCLUDE_END:
3030 return;
3031 case XML_ELEMENT_NODE:
3032 case XML_ATTRIBUTE_NODE:
3033 break;
3034 }
3035 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3036}
3037
3038/**
3039 * xmlNodeGetLang:
3040 * @cur: the node being checked
3041 *
3042 * Searches the language of a node, i.e. the values of the xml:lang
3043 * attribute or the one carried by the nearest ancestor.
3044 *
3045 * Returns a pointer to the lang value, or NULL if not found
3046 * It's up to the caller to free the memory.
3047 */
3048xmlChar *
3049xmlNodeGetLang(xmlNodePtr cur) {
3050 xmlChar *lang;
3051
3052 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003053 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003054 if (lang != NULL)
3055 return(lang);
3056 cur = cur->parent;
3057 }
3058 return(NULL);
3059}
3060
3061
3062/**
3063 * xmlNodeSetSpacePreserve:
3064 * @cur: the node being changed
3065 * @val: the xml:space value ("0": default, 1: "preserve")
3066 *
3067 * Set (or reset) the space preserving behaviour of a node, i.e. the
3068 * value of the xml:space attribute.
3069 */
3070void
3071xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3072 if (cur == NULL) return;
3073 switch(cur->type) {
3074 case XML_TEXT_NODE:
3075 case XML_CDATA_SECTION_NODE:
3076 case XML_COMMENT_NODE:
3077 case XML_DOCUMENT_NODE:
3078 case XML_DOCUMENT_TYPE_NODE:
3079 case XML_DOCUMENT_FRAG_NODE:
3080 case XML_NOTATION_NODE:
3081 case XML_HTML_DOCUMENT_NODE:
3082 case XML_DTD_NODE:
3083 case XML_ELEMENT_DECL:
3084 case XML_ATTRIBUTE_DECL:
3085 case XML_ENTITY_DECL:
3086 case XML_PI_NODE:
3087 case XML_ENTITY_REF_NODE:
3088 case XML_ENTITY_NODE:
3089 case XML_NAMESPACE_DECL:
3090 case XML_XINCLUDE_START:
3091 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003092#ifdef LIBXML_DOCB_ENABLED
3093 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003094#endif
3095 return;
3096 case XML_ELEMENT_NODE:
3097 case XML_ATTRIBUTE_NODE:
3098 break;
3099 }
3100 switch (val) {
3101 case 0:
3102 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3103 break;
3104 case 1:
3105 xmlSetProp(cur, BAD_CAST "xml:space",
3106 BAD_CAST "preserve");
3107 break;
3108 }
3109}
3110
3111/**
3112 * xmlNodeGetSpacePreserve:
3113 * @cur: the node being checked
3114 *
3115 * Searches the space preserving behaviour of a node, i.e. the values
3116 * of the xml:space attribute or the one carried by the nearest
3117 * ancestor.
3118 *
3119 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
3120 */
3121int
3122xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3123 xmlChar *space;
3124
3125 while (cur != NULL) {
3126 space = xmlGetProp(cur, BAD_CAST "xml:space");
3127 if (space != NULL) {
3128 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3129 xmlFree(space);
3130 return(1);
3131 }
3132 if (xmlStrEqual(space, BAD_CAST "default")) {
3133 xmlFree(space);
3134 return(0);
3135 }
3136 xmlFree(space);
3137 }
3138 cur = cur->parent;
3139 }
3140 return(-1);
3141}
3142
3143/**
3144 * xmlNodeSetName:
3145 * @cur: the node being changed
3146 * @name: the new tag name
3147 *
3148 * Set (or reset) the name of a node.
3149 */
3150void
3151xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3152 if (cur == NULL) return;
3153 if (name == NULL) return;
3154 switch(cur->type) {
3155 case XML_TEXT_NODE:
3156 case XML_CDATA_SECTION_NODE:
3157 case XML_COMMENT_NODE:
3158 case XML_DOCUMENT_TYPE_NODE:
3159 case XML_DOCUMENT_FRAG_NODE:
3160 case XML_NOTATION_NODE:
3161 case XML_HTML_DOCUMENT_NODE:
3162 case XML_NAMESPACE_DECL:
3163 case XML_XINCLUDE_START:
3164 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003165#ifdef LIBXML_DOCB_ENABLED
3166 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003167#endif
3168 return;
3169 case XML_ELEMENT_NODE:
3170 case XML_ATTRIBUTE_NODE:
3171 case XML_PI_NODE:
3172 case XML_ENTITY_REF_NODE:
3173 case XML_ENTITY_NODE:
3174 case XML_DTD_NODE:
3175 case XML_DOCUMENT_NODE:
3176 case XML_ELEMENT_DECL:
3177 case XML_ATTRIBUTE_DECL:
3178 case XML_ENTITY_DECL:
3179 break;
3180 }
3181 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3182 cur->name = xmlStrdup(name);
3183}
3184
3185/**
3186 * xmlNodeSetBase:
3187 * @cur: the node being changed
3188 * @uri: the new base URI
3189 *
3190 * Set (or reset) the base URI of a node, i.e. the value of the
3191 * xml:base attribute.
3192 */
3193void
3194xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3195 if (cur == NULL) return;
3196 switch(cur->type) {
3197 case XML_TEXT_NODE:
3198 case XML_CDATA_SECTION_NODE:
3199 case XML_COMMENT_NODE:
3200 case XML_DOCUMENT_NODE:
3201 case XML_DOCUMENT_TYPE_NODE:
3202 case XML_DOCUMENT_FRAG_NODE:
3203 case XML_NOTATION_NODE:
3204 case XML_HTML_DOCUMENT_NODE:
3205 case XML_DTD_NODE:
3206 case XML_ELEMENT_DECL:
3207 case XML_ATTRIBUTE_DECL:
3208 case XML_ENTITY_DECL:
3209 case XML_PI_NODE:
3210 case XML_ENTITY_REF_NODE:
3211 case XML_ENTITY_NODE:
3212 case XML_NAMESPACE_DECL:
3213 case XML_XINCLUDE_START:
3214 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003215#ifdef LIBXML_DOCB_ENABLED
3216 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003217#endif
3218 return;
3219 case XML_ELEMENT_NODE:
3220 case XML_ATTRIBUTE_NODE:
3221 break;
3222 }
3223 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3224}
3225
3226/**
Owen Taylor3473f882001-02-23 17:55:21 +00003227 * xmlNodeGetBase:
3228 * @doc: the document the node pertains to
3229 * @cur: the node being checked
3230 *
3231 * Searches for the BASE URL. The code should work on both XML
3232 * and HTML document even if base mechanisms are completely different.
3233 * It returns the base as defined in RFC 2396 sections
3234 * 5.1.1. Base URI within Document Content
3235 * and
3236 * 5.1.2. Base URI from the Encapsulating Entity
3237 * However it does not return the document base (5.1.3), use
3238 * xmlDocumentGetBase() for this
3239 *
3240 * Returns a pointer to the base URL, or NULL if not found
3241 * It's up to the caller to free the memory.
3242 */
3243xmlChar *
3244xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
3245 xmlChar *base;
3246
3247 if ((cur == NULL) && (doc == NULL))
3248 return(NULL);
3249 if (doc == NULL) doc = cur->doc;
3250 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3251 cur = doc->children;
3252 while ((cur != NULL) && (cur->name != NULL)) {
3253 if (cur->type != XML_ELEMENT_NODE) {
3254 cur = cur->next;
3255 continue;
3256 }
3257 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3258 cur = cur->children;
3259 continue;
3260 }
3261 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3262 cur = cur->children;
3263 continue;
3264 }
3265 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3266 return(xmlGetProp(cur, BAD_CAST "href"));
3267 }
3268 cur = cur->next;
3269 }
3270 return(NULL);
3271 }
3272 while (cur != NULL) {
3273 if (cur->type == XML_ENTITY_DECL) {
3274 xmlEntityPtr ent = (xmlEntityPtr) cur;
3275 return(xmlStrdup(ent->URI));
3276 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003277 if (cur->type == XML_ELEMENT_NODE) {
3278 base = xmlGetProp(cur, BAD_CAST "xml:base");
3279 if (base != NULL) {
3280 /* TODO : apply cascade in the base resolution ! */
3281 return(base);
3282 }
3283 }
Owen Taylor3473f882001-02-23 17:55:21 +00003284 cur = cur->parent;
3285 }
3286 if ((doc != NULL) && (doc->URL != NULL))
3287 return(xmlStrdup(doc->URL));
3288 return(NULL);
3289}
3290
3291/**
3292 * xmlNodeGetContent:
3293 * @cur: the node being read
3294 *
3295 * Read the value of a node, this can be either the text carried
3296 * directly by this node if it's a TEXT node or the aggregate string
3297 * of the values carried by this node child's (TEXT and ENTITY_REF).
3298 * Entity references are substitued.
3299 * Returns a new xmlChar * or NULL if no content is available.
3300 * It's up to the caller to free the memory.
3301 */
3302xmlChar *
3303xmlNodeGetContent(xmlNodePtr cur) {
3304 if (cur == NULL) return(NULL);
3305 switch (cur->type) {
3306 case XML_DOCUMENT_FRAG_NODE:
3307 case XML_ELEMENT_NODE: {
3308 xmlNodePtr tmp = cur;
3309 xmlBufferPtr buffer;
3310 xmlChar *ret;
3311
3312 buffer = xmlBufferCreate();
3313 if (buffer == NULL)
3314 return(NULL);
3315 while (tmp != NULL) {
3316 switch (tmp->type) {
3317 case XML_ELEMENT_NODE:
Daniel Veillard2d703722001-05-30 18:32:34 +00003318 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003319 case XML_TEXT_NODE:
3320 if (tmp->content != NULL)
3321#ifndef XML_USE_BUFFER_CONTENT
3322 xmlBufferCat(buffer, tmp->content);
3323#else
3324 xmlBufferCat(buffer,
3325 xmlBufferContent(tmp->content));
3326#endif
3327 break;
3328 case XML_ENTITY_REF_NODE: {
3329 xmlEntityPtr ent;
3330
3331 ent = xmlGetDocEntity(cur->doc, tmp->name);
3332 if (ent != NULL)
3333 xmlBufferCat(buffer, ent->content);
3334 }
3335 default:
3336 break;
3337 }
3338 /*
3339 * Skip to next node
3340 */
3341 if (tmp->children != NULL) {
3342 if (tmp->children->type != XML_ENTITY_DECL) {
3343 tmp = tmp->children;
3344 continue;
3345 }
3346 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003347 if (tmp == cur)
3348 break;
3349
Owen Taylor3473f882001-02-23 17:55:21 +00003350 if (tmp->next != NULL) {
3351 tmp = tmp->next;
3352 continue;
3353 }
3354
3355 do {
3356 tmp = tmp->parent;
3357 if (tmp == NULL)
3358 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003359 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003360 tmp = NULL;
3361 break;
3362 }
3363 if (tmp->next != NULL) {
3364 tmp = tmp->next;
3365 break;
3366 }
3367 } while (tmp != NULL);
3368 }
3369 ret = buffer->content;
3370 buffer->content = NULL;
3371 xmlBufferFree(buffer);
3372 return(ret);
3373 }
3374 case XML_ATTRIBUTE_NODE: {
3375 xmlAttrPtr attr = (xmlAttrPtr) cur;
3376 if (attr->parent != NULL)
3377 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3378 else
3379 return(xmlNodeListGetString(NULL, attr->children, 1));
3380 break;
3381 }
3382 case XML_COMMENT_NODE:
3383 case XML_PI_NODE:
3384 if (cur->content != NULL)
3385#ifndef XML_USE_BUFFER_CONTENT
3386 return(xmlStrdup(cur->content));
3387#else
3388 return(xmlStrdup(xmlBufferContent(cur->content)));
3389#endif
3390 return(NULL);
3391 case XML_ENTITY_REF_NODE:
3392 /*
3393 * Locate the entity, and get it's content
3394 * @@@
3395 */
3396 return(NULL);
3397 case XML_ENTITY_NODE:
3398 case XML_DOCUMENT_NODE:
3399 case XML_HTML_DOCUMENT_NODE:
3400 case XML_DOCUMENT_TYPE_NODE:
3401 case XML_NOTATION_NODE:
3402 case XML_DTD_NODE:
3403 case XML_XINCLUDE_START:
3404 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003405#ifdef LIBXML_DOCB_ENABLED
3406 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003407#endif
3408 return(NULL);
3409 case XML_NAMESPACE_DECL:
3410 return(xmlStrdup(((xmlNsPtr)cur)->href));
3411 case XML_ELEMENT_DECL:
3412 /* TODO !!! */
3413 return(NULL);
3414 case XML_ATTRIBUTE_DECL:
3415 /* TODO !!! */
3416 return(NULL);
3417 case XML_ENTITY_DECL:
3418 /* TODO !!! */
3419 return(NULL);
3420 case XML_CDATA_SECTION_NODE:
3421 case XML_TEXT_NODE:
3422 if (cur->content != NULL)
3423#ifndef XML_USE_BUFFER_CONTENT
3424 return(xmlStrdup(cur->content));
3425#else
3426 return(xmlStrdup(xmlBufferContent(cur->content)));
3427#endif
3428 return(NULL);
3429 }
3430 return(NULL);
3431}
3432
3433/**
3434 * xmlNodeSetContent:
3435 * @cur: the node being modified
3436 * @content: the new value of the content
3437 *
3438 * Replace the content of a node.
3439 */
3440void
3441xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3442 if (cur == NULL) {
3443#ifdef DEBUG_TREE
3444 xmlGenericError(xmlGenericErrorContext,
3445 "xmlNodeSetContent : node == NULL\n");
3446#endif
3447 return;
3448 }
3449 switch (cur->type) {
3450 case XML_DOCUMENT_FRAG_NODE:
3451 case XML_ELEMENT_NODE:
3452 if (cur->content != NULL) {
3453#ifndef XML_USE_BUFFER_CONTENT
3454 xmlFree(cur->content);
3455#else
3456 xmlBufferFree(cur->content);
3457#endif
3458 cur->content = NULL;
3459 }
3460 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3461 cur->children = xmlStringGetNodeList(cur->doc, content);
3462 UPDATE_LAST_CHILD_AND_PARENT(cur)
3463 break;
3464 case XML_ATTRIBUTE_NODE:
3465 break;
3466 case XML_TEXT_NODE:
3467 case XML_CDATA_SECTION_NODE:
3468 case XML_ENTITY_REF_NODE:
3469 case XML_ENTITY_NODE:
3470 case XML_PI_NODE:
3471 case XML_COMMENT_NODE:
3472 if (cur->content != NULL) {
3473#ifndef XML_USE_BUFFER_CONTENT
3474 xmlFree(cur->content);
3475#else
3476 xmlBufferFree(cur->content);
3477#endif
3478 }
3479 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3480 cur->last = cur->children = NULL;
3481 if (content != NULL) {
3482#ifndef XML_USE_BUFFER_CONTENT
3483 cur->content = xmlStrdup(content);
3484#else
3485 cur->content = xmlBufferCreateSize(0);
3486 xmlBufferSetAllocationScheme(cur->content,
3487 xmlGetBufferAllocationScheme());
3488 xmlBufferAdd(cur->content, content, -1);
3489#endif
3490 } else
3491 cur->content = NULL;
3492 break;
3493 case XML_DOCUMENT_NODE:
3494 case XML_HTML_DOCUMENT_NODE:
3495 case XML_DOCUMENT_TYPE_NODE:
3496 case XML_XINCLUDE_START:
3497 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003498#ifdef LIBXML_DOCB_ENABLED
3499 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003500#endif
3501 break;
3502 case XML_NOTATION_NODE:
3503 break;
3504 case XML_DTD_NODE:
3505 break;
3506 case XML_NAMESPACE_DECL:
3507 break;
3508 case XML_ELEMENT_DECL:
3509 /* TODO !!! */
3510 break;
3511 case XML_ATTRIBUTE_DECL:
3512 /* TODO !!! */
3513 break;
3514 case XML_ENTITY_DECL:
3515 /* TODO !!! */
3516 break;
3517 }
3518}
3519
3520/**
3521 * xmlNodeSetContentLen:
3522 * @cur: the node being modified
3523 * @content: the new value of the content
3524 * @len: the size of @content
3525 *
3526 * Replace the content of a node.
3527 */
3528void
3529xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3530 if (cur == NULL) {
3531#ifdef DEBUG_TREE
3532 xmlGenericError(xmlGenericErrorContext,
3533 "xmlNodeSetContentLen : node == NULL\n");
3534#endif
3535 return;
3536 }
3537 switch (cur->type) {
3538 case XML_DOCUMENT_FRAG_NODE:
3539 case XML_ELEMENT_NODE:
3540 if (cur->content != NULL) {
3541#ifndef XML_USE_BUFFER_CONTENT
3542 xmlFree(cur->content);
3543#else
3544 xmlBufferFree(cur->content);
3545#endif
3546 cur->content = NULL;
3547 }
3548 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3549 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3550 UPDATE_LAST_CHILD_AND_PARENT(cur)
3551 break;
3552 case XML_ATTRIBUTE_NODE:
3553 break;
3554 case XML_TEXT_NODE:
3555 case XML_CDATA_SECTION_NODE:
3556 case XML_ENTITY_REF_NODE:
3557 case XML_ENTITY_NODE:
3558 case XML_PI_NODE:
3559 case XML_COMMENT_NODE:
3560 case XML_NOTATION_NODE:
3561 if (cur->content != NULL) {
3562#ifndef XML_USE_BUFFER_CONTENT
3563 xmlFree(cur->content);
3564#else
3565 xmlBufferFree(cur->content);
3566#endif
3567 }
3568 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3569 cur->children = cur->last = NULL;
3570 if (content != NULL) {
3571#ifndef XML_USE_BUFFER_CONTENT
3572 cur->content = xmlStrndup(content, len);
3573#else
3574 cur->content = xmlBufferCreateSize(len);
3575 xmlBufferSetAllocationScheme(cur->content,
3576 xmlGetBufferAllocationScheme());
3577 xmlBufferAdd(cur->content, content, len);
3578#endif
3579 } else
3580 cur->content = NULL;
3581 break;
3582 case XML_DOCUMENT_NODE:
3583 case XML_DTD_NODE:
3584 case XML_HTML_DOCUMENT_NODE:
3585 case XML_DOCUMENT_TYPE_NODE:
3586 case XML_NAMESPACE_DECL:
3587 case XML_XINCLUDE_START:
3588 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003589#ifdef LIBXML_DOCB_ENABLED
3590 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003591#endif
3592 break;
3593 case XML_ELEMENT_DECL:
3594 /* TODO !!! */
3595 break;
3596 case XML_ATTRIBUTE_DECL:
3597 /* TODO !!! */
3598 break;
3599 case XML_ENTITY_DECL:
3600 /* TODO !!! */
3601 break;
3602 }
3603}
3604
3605/**
3606 * xmlNodeAddContentLen:
3607 * @cur: the node being modified
3608 * @content: extra content
3609 * @len: the size of @content
3610 *
3611 * Append the extra substring to the node content.
3612 */
3613void
3614xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3615 if (cur == NULL) {
3616#ifdef DEBUG_TREE
3617 xmlGenericError(xmlGenericErrorContext,
3618 "xmlNodeAddContentLen : node == NULL\n");
3619#endif
3620 return;
3621 }
3622 if (len <= 0) return;
3623 switch (cur->type) {
3624 case XML_DOCUMENT_FRAG_NODE:
3625 case XML_ELEMENT_NODE: {
3626 xmlNodePtr last = NULL, newNode;
3627
3628 if (cur->children != NULL) {
3629 last = cur->last;
3630 } else {
3631 if (cur->content != NULL) {
3632#ifndef XML_USE_BUFFER_CONTENT
3633 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
3634#else
3635 cur->children = xmlStringGetNodeList(cur->doc,
3636 xmlBufferContent(cur->content));
3637#endif
3638 UPDATE_LAST_CHILD_AND_PARENT(cur)
3639#ifndef XML_USE_BUFFER_CONTENT
3640 xmlFree(cur->content);
3641#else
3642 xmlBufferFree(cur->content);
3643#endif
3644 cur->content = NULL;
3645 last = cur->last;
3646 }
3647 }
3648 newNode = xmlNewTextLen(content, len);
3649 if (newNode != NULL) {
3650 xmlAddChild(cur, newNode);
3651 if ((last != NULL) && (last->next == newNode)) {
3652 xmlTextMerge(last, newNode);
3653 }
3654 }
3655 break;
3656 }
3657 case XML_ATTRIBUTE_NODE:
3658 break;
3659 case XML_TEXT_NODE:
3660 case XML_CDATA_SECTION_NODE:
3661 case XML_ENTITY_REF_NODE:
3662 case XML_ENTITY_NODE:
3663 case XML_PI_NODE:
3664 case XML_COMMENT_NODE:
3665 case XML_NOTATION_NODE:
3666 if (content != NULL) {
3667#ifndef XML_USE_BUFFER_CONTENT
3668 cur->content = xmlStrncat(cur->content, content, len);
3669#else
3670 xmlBufferAdd(cur->content, content, len);
3671#endif
3672 }
3673 case XML_DOCUMENT_NODE:
3674 case XML_DTD_NODE:
3675 case XML_HTML_DOCUMENT_NODE:
3676 case XML_DOCUMENT_TYPE_NODE:
3677 case XML_NAMESPACE_DECL:
3678 case XML_XINCLUDE_START:
3679 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003680#ifdef LIBXML_DOCB_ENABLED
3681 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003682#endif
3683 break;
3684 case XML_ELEMENT_DECL:
3685 case XML_ATTRIBUTE_DECL:
3686 case XML_ENTITY_DECL:
3687 break;
3688 }
3689}
3690
3691/**
3692 * xmlNodeAddContent:
3693 * @cur: the node being modified
3694 * @content: extra content
3695 *
3696 * Append the extra substring to the node content.
3697 */
3698void
3699xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3700 int len;
3701
3702 if (cur == NULL) {
3703#ifdef DEBUG_TREE
3704 xmlGenericError(xmlGenericErrorContext,
3705 "xmlNodeAddContent : node == NULL\n");
3706#endif
3707 return;
3708 }
3709 if (content == NULL) return;
3710 len = xmlStrlen(content);
3711 xmlNodeAddContentLen(cur, content, len);
3712}
3713
3714/**
3715 * xmlTextMerge:
3716 * @first: the first text node
3717 * @second: the second text node being merged
3718 *
3719 * Merge two text nodes into one
3720 * Returns the first text node augmented
3721 */
3722xmlNodePtr
3723xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3724 if (first == NULL) return(second);
3725 if (second == NULL) return(first);
3726 if (first->type != XML_TEXT_NODE) return(first);
3727 if (second->type != XML_TEXT_NODE) return(first);
3728 if (second->name != first->name)
3729 return(first);
3730#ifndef XML_USE_BUFFER_CONTENT
3731 xmlNodeAddContent(first, second->content);
3732#else
3733 xmlNodeAddContent(first, xmlBufferContent(second->content));
3734#endif
3735 xmlUnlinkNode(second);
3736 xmlFreeNode(second);
3737 return(first);
3738}
3739
3740/**
3741 * xmlGetNsList:
3742 * @doc: the document
3743 * @node: the current node
3744 *
3745 * Search all the namespace applying to a given element.
3746 * Returns an NULL terminated array of all the xmlNsPtr found
3747 * that need to be freed by the caller or NULL if no
3748 * namespace if defined
3749 */
3750xmlNsPtr *
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003751xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003752 xmlNsPtr cur;
3753 xmlNsPtr *ret = NULL;
3754 int nbns = 0;
3755 int maxns = 10;
3756 int i;
3757
3758 while (node != NULL) {
3759 cur = node->nsDef;
3760 while (cur != NULL) {
3761 if (ret == NULL) {
3762 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
3763 if (ret == NULL) {
3764 xmlGenericError(xmlGenericErrorContext,
3765 "xmlGetNsList : out of memory!\n");
3766 return(NULL);
3767 }
3768 ret[nbns] = NULL;
3769 }
3770 for (i = 0;i < nbns;i++) {
3771 if ((cur->prefix == ret[i]->prefix) ||
3772 (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
3773 }
3774 if (i >= nbns) {
3775 if (nbns >= maxns) {
3776 maxns *= 2;
3777 ret = (xmlNsPtr *) xmlRealloc(ret,
3778 (maxns + 1) * sizeof(xmlNsPtr));
3779 if (ret == NULL) {
3780 xmlGenericError(xmlGenericErrorContext,
3781 "xmlGetNsList : realloc failed!\n");
3782 return(NULL);
3783 }
3784 }
3785 ret[nbns++] = cur;
3786 ret[nbns] = NULL;
3787 }
3788
3789 cur = cur->next;
3790 }
3791 node = node->parent;
3792 }
3793 return(ret);
3794}
3795
3796/**
3797 * xmlSearchNs:
3798 * @doc: the document
3799 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00003800 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00003801 *
3802 * Search a Ns registered under a given name space for a document.
3803 * recurse on the parents until it finds the defined namespace
3804 * or return NULL otherwise.
3805 * @nameSpace can be NULL, this is a search for the default namespace.
3806 * We don't allow to cross entities boundaries. If you don't declare
3807 * the namespace within those you will be in troubles !!! A warning
3808 * is generated to cover this case.
3809 *
3810 * Returns the namespace pointer or NULL.
3811 */
3812xmlNsPtr
3813xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
3814 xmlNsPtr cur;
3815
3816 if (node == NULL) return(NULL);
3817 if ((nameSpace != NULL) &&
3818 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
3819 if (doc->oldNs == NULL) {
3820 /*
3821 * Allocate a new Namespace and fill the fields.
3822 */
3823 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3824 if (doc->oldNs == NULL) {
3825 xmlGenericError(xmlGenericErrorContext,
3826 "xmlSearchNsByHref : malloc failed\n");
3827 return(NULL);
3828 }
3829 memset(doc->oldNs, 0, sizeof(xmlNs));
3830 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3831
3832 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3833 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3834 }
3835 return(doc->oldNs);
3836 }
3837 while (node != NULL) {
3838 if ((node->type == XML_ENTITY_REF_NODE) ||
3839 (node->type == XML_ENTITY_NODE) ||
3840 (node->type == XML_ENTITY_DECL))
3841 return(NULL);
3842 if (node->type == XML_ELEMENT_NODE) {
3843 cur = node->nsDef;
3844 while (cur != NULL) {
3845 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3846 (cur->href != NULL))
3847 return(cur);
3848 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
3849 (cur->href != NULL) &&
3850 (xmlStrEqual(cur->prefix, nameSpace)))
3851 return(cur);
3852 cur = cur->next;
3853 }
3854 }
3855 node = node->parent;
3856 }
3857 return(NULL);
3858}
3859
3860/**
3861 * xmlSearchNsByHref:
3862 * @doc: the document
3863 * @node: the current node
3864 * @href: the namespace value
3865 *
3866 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3867 * the defined namespace or return NULL otherwise.
3868 * Returns the namespace pointer or NULL.
3869 */
3870xmlNsPtr
3871xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
3872 xmlNsPtr cur;
3873 xmlNodePtr orig = node;
3874
3875 if ((node == NULL) || (href == NULL)) return(NULL);
3876 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
3877 if (doc->oldNs == NULL) {
3878 /*
3879 * Allocate a new Namespace and fill the fields.
3880 */
3881 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3882 if (doc->oldNs == NULL) {
3883 xmlGenericError(xmlGenericErrorContext,
3884 "xmlSearchNsByHref : malloc failed\n");
3885 return(NULL);
3886 }
3887 memset(doc->oldNs, 0, sizeof(xmlNs));
3888 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3889
3890 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3891 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3892 }
3893 return(doc->oldNs);
3894 }
3895 while (node != NULL) {
3896 cur = node->nsDef;
3897 while (cur != NULL) {
3898 if ((cur->href != NULL) && (href != NULL) &&
3899 (xmlStrEqual(cur->href, href))) {
3900 /*
3901 * Check that the prefix is not shadowed between orig and node
3902 */
3903 xmlNodePtr check = orig;
3904 xmlNsPtr tst;
3905
3906 while (check != node) {
3907 tst = check->nsDef;
3908 while (tst != NULL) {
3909 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3910 goto shadowed;
3911 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
3912 (xmlStrEqual(tst->prefix, cur->prefix)))
3913 goto shadowed;
3914 tst = tst->next;
3915 }
3916 check = check->parent;
3917 }
3918 return(cur);
3919 }
3920shadowed:
3921 cur = cur->next;
3922 }
3923 node = node->parent;
3924 }
3925 return(NULL);
3926}
3927
3928/**
3929 * xmlNewReconciliedNs
3930 * @doc: the document
3931 * @tree: a node expected to hold the new namespace
3932 * @ns: the original namespace
3933 *
3934 * This function tries to locate a namespace definition in a tree
3935 * ancestors, or create a new namespace definition node similar to
3936 * @ns trying to reuse the same prefix. However if the given prefix is
3937 * null (default namespace) or reused within the subtree defined by
3938 * @tree or on one of its ancestors then a new prefix is generated.
3939 * Returns the (new) namespace definition or NULL in case of error
3940 */
3941xmlNsPtr
3942xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3943 xmlNsPtr def;
3944 xmlChar prefix[50];
3945 int counter = 1;
3946
3947 if (tree == NULL) {
3948#ifdef DEBUG_TREE
3949 xmlGenericError(xmlGenericErrorContext,
3950 "xmlNewReconciliedNs : tree == NULL\n");
3951#endif
3952 return(NULL);
3953 }
3954 if (ns == NULL) {
3955#ifdef DEBUG_TREE
3956 xmlGenericError(xmlGenericErrorContext,
3957 "xmlNewReconciliedNs : ns == NULL\n");
3958#endif
3959 return(NULL);
3960 }
3961 /*
3962 * Search an existing namespace definition inherited.
3963 */
3964 def = xmlSearchNsByHref(doc, tree, ns->href);
3965 if (def != NULL)
3966 return(def);
3967
3968 /*
3969 * Find a close prefix which is not already in use.
3970 * Let's strip namespace prefixes longer than 20 chars !
3971 */
3972 sprintf((char *) prefix, "%.20s", ns->prefix);
3973 def = xmlSearchNs(doc, tree, prefix);
3974 while (def != NULL) {
3975 if (counter > 1000) return(NULL);
3976 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3977 def = xmlSearchNs(doc, tree, prefix);
3978 }
3979
3980 /*
3981 * Ok, now we are ready to create a new one.
3982 */
3983 def = xmlNewNs(tree, ns->href, prefix);
3984 return(def);
3985}
3986
3987/**
3988 * xmlReconciliateNs
3989 * @doc: the document
3990 * @tree: a node defining the subtree to reconciliate
3991 *
3992 * This function checks that all the namespaces declared within the given
3993 * tree are properly declared. This is needed for example after Copy or Cut
3994 * and then paste operations. The subtree may still hold pointers to
3995 * namespace declarations outside the subtree or invalid/masked. As much
3996 * as possible the function try tu reuse the existing namespaces found in
3997 * the new environment. If not possible the new namespaces are redeclared
3998 * on @tree at the top of the given subtree.
3999 * Returns the number of namespace declarations created or -1 in case of error.
4000 */
4001int
4002xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4003 xmlNsPtr *oldNs = NULL;
4004 xmlNsPtr *newNs = NULL;
4005 int sizeCache = 0;
4006 int nbCache = 0;
4007
4008 xmlNsPtr n;
4009 xmlNodePtr node = tree;
4010 xmlAttrPtr attr;
4011 int ret = 0, i;
4012
4013 while (node != NULL) {
4014 /*
4015 * Reconciliate the node namespace
4016 */
4017 if (node->ns != NULL) {
4018 /*
4019 * initialize the cache if needed
4020 */
4021 if (sizeCache == 0) {
4022 sizeCache = 10;
4023 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4024 sizeof(xmlNsPtr));
4025 if (oldNs == NULL) {
4026 xmlGenericError(xmlGenericErrorContext,
4027 "xmlReconciliateNs : memory pbm\n");
4028 return(-1);
4029 }
4030 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4031 sizeof(xmlNsPtr));
4032 if (newNs == NULL) {
4033 xmlGenericError(xmlGenericErrorContext,
4034 "xmlReconciliateNs : memory pbm\n");
4035 xmlFree(oldNs);
4036 return(-1);
4037 }
4038 }
4039 for (i = 0;i < nbCache;i++) {
4040 if (oldNs[i] == node->ns) {
4041 node->ns = newNs[i];
4042 break;
4043 }
4044 }
4045 if (i == nbCache) {
4046 /*
4047 * Ok we need to recreate a new namespace definition
4048 */
4049 n = xmlNewReconciliedNs(doc, tree, node->ns);
4050 if (n != NULL) { /* :-( what if else ??? */
4051 /*
4052 * check if we need to grow the cache buffers.
4053 */
4054 if (sizeCache <= nbCache) {
4055 sizeCache *= 2;
4056 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4057 sizeof(xmlNsPtr));
4058 if (oldNs == NULL) {
4059 xmlGenericError(xmlGenericErrorContext,
4060 "xmlReconciliateNs : memory pbm\n");
4061 xmlFree(newNs);
4062 return(-1);
4063 }
4064 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4065 sizeof(xmlNsPtr));
4066 if (newNs == NULL) {
4067 xmlGenericError(xmlGenericErrorContext,
4068 "xmlReconciliateNs : memory pbm\n");
4069 xmlFree(oldNs);
4070 return(-1);
4071 }
4072 }
4073 newNs[nbCache] = n;
4074 oldNs[nbCache++] = node->ns;
4075 node->ns = n;
4076 }
4077 }
4078 }
4079 /*
4080 * now check for namespace hold by attributes on the node.
4081 */
4082 attr = node->properties;
4083 while (attr != NULL) {
4084 if (attr->ns != NULL) {
4085 /*
4086 * initialize the cache if needed
4087 */
4088 if (sizeCache == 0) {
4089 sizeCache = 10;
4090 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4091 sizeof(xmlNsPtr));
4092 if (oldNs == NULL) {
4093 xmlGenericError(xmlGenericErrorContext,
4094 "xmlReconciliateNs : memory pbm\n");
4095 return(-1);
4096 }
4097 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4098 sizeof(xmlNsPtr));
4099 if (newNs == NULL) {
4100 xmlGenericError(xmlGenericErrorContext,
4101 "xmlReconciliateNs : memory pbm\n");
4102 xmlFree(oldNs);
4103 return(-1);
4104 }
4105 }
4106 for (i = 0;i < nbCache;i++) {
4107 if (oldNs[i] == attr->ns) {
4108 node->ns = newNs[i];
4109 break;
4110 }
4111 }
4112 if (i == nbCache) {
4113 /*
4114 * Ok we need to recreate a new namespace definition
4115 */
4116 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4117 if (n != NULL) { /* :-( what if else ??? */
4118 /*
4119 * check if we need to grow the cache buffers.
4120 */
4121 if (sizeCache <= nbCache) {
4122 sizeCache *= 2;
4123 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4124 sizeof(xmlNsPtr));
4125 if (oldNs == NULL) {
4126 xmlGenericError(xmlGenericErrorContext,
4127 "xmlReconciliateNs : memory pbm\n");
4128 xmlFree(newNs);
4129 return(-1);
4130 }
4131 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4132 sizeof(xmlNsPtr));
4133 if (newNs == NULL) {
4134 xmlGenericError(xmlGenericErrorContext,
4135 "xmlReconciliateNs : memory pbm\n");
4136 xmlFree(oldNs);
4137 return(-1);
4138 }
4139 }
4140 newNs[nbCache] = n;
4141 oldNs[nbCache++] = attr->ns;
4142 attr->ns = n;
4143 }
4144 }
4145 }
4146 attr = attr->next;
4147 }
4148
4149 /*
4150 * Browse the full subtree, deep first
4151 */
4152 if (node->children != NULL) {
4153 /* deep first */
4154 node = node->children;
4155 } else if ((node != tree) && (node->next != NULL)) {
4156 /* then siblings */
4157 node = node->next;
4158 } else if (node != tree) {
4159 /* go up to parents->next if needed */
4160 while (node != tree) {
4161 if (node->parent != NULL)
4162 node = node->parent;
4163 if ((node != tree) && (node->next != NULL)) {
4164 node = node->next;
4165 break;
4166 }
4167 if (node->parent == NULL) {
4168 node = NULL;
4169 break;
4170 }
4171 }
4172 /* exit condition */
4173 if (node == tree)
4174 node = NULL;
4175 }
4176 }
4177 return(ret);
4178}
4179
4180/**
4181 * xmlHasProp:
4182 * @node: the node
4183 * @name: the attribute name
4184 *
4185 * Search an attribute associated to a node
4186 * This function also looks in DTD attribute declaration for #FIXED or
4187 * default declaration values unless DTD use has been turned off.
4188 *
4189 * Returns the attribute or the attribute declaration or NULL if
4190 * neither was found.
4191 */
4192xmlAttrPtr
4193xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4194 xmlAttrPtr prop;
4195 xmlDocPtr doc;
4196
4197 if ((node == NULL) || (name == NULL)) return(NULL);
4198 /*
4199 * Check on the properties attached to the node
4200 */
4201 prop = node->properties;
4202 while (prop != NULL) {
4203 if (xmlStrEqual(prop->name, name)) {
4204 return(prop);
4205 }
4206 prop = prop->next;
4207 }
4208 if (!xmlCheckDTD) return(NULL);
4209
4210 /*
4211 * Check if there is a default declaration in the internal
4212 * or external subsets
4213 */
4214 doc = node->doc;
4215 if (doc != NULL) {
4216 xmlAttributePtr attrDecl;
4217 if (doc->intSubset != NULL) {
4218 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4219 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4220 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4221 if (attrDecl != NULL)
4222 return((xmlAttrPtr) attrDecl);
4223 }
4224 }
4225 return(NULL);
4226}
4227
4228/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004229 * xmlHasNsProp:
4230 * @node: the node
4231 * @name: the attribute name
4232 * @namespace: the URI of the namespace
4233 *
4234 * Search for an attribute associated to a node
4235 * This attribute has to be anchored in the namespace specified.
4236 * This does the entity substitution.
4237 * This function looks in DTD attribute declaration for #FIXED or
4238 * default declaration values unless DTD use has been turned off.
4239 *
4240 * Returns the attribute or the attribute declaration or NULL
4241 * if neither was found.
4242 */
4243xmlAttrPtr
4244xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
4245 xmlAttrPtr prop;
4246 xmlDocPtr doc;
4247 xmlNsPtr ns;
4248
4249 if (node == NULL)
4250 return(NULL);
4251
4252 prop = node->properties;
4253 if (namespace == NULL)
4254 return(xmlHasProp(node, name));
4255 while (prop != NULL) {
4256 /*
4257 * One need to have
4258 * - same attribute names
4259 * - and the attribute carrying that namespace
4260 * or
4261 * no namespace on the attribute and the element carrying it
4262 */
4263 if ((xmlStrEqual(prop->name, name)) &&
4264 (((prop->ns == NULL) && (node->ns != NULL) &&
4265 (xmlStrEqual(node->ns->href, namespace))) ||
4266 ((prop->ns != NULL) &&
4267 (xmlStrEqual(prop->ns->href, namespace))))) {
4268 return(prop);
4269 }
4270 prop = prop->next;
4271 }
4272 if (!xmlCheckDTD) return(NULL);
4273
4274 /*
4275 * Check if there is a default declaration in the internal
4276 * or external subsets
4277 */
4278 doc = node->doc;
4279 if (doc != NULL) {
4280 if (doc->intSubset != NULL) {
4281 xmlAttributePtr attrDecl;
4282
4283 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4284 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4285 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4286
4287 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4288 /*
4289 * The DTD declaration only allows a prefix search
4290 */
4291 ns = xmlSearchNs(doc, node, attrDecl->prefix);
4292 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
4293 return((xmlAttrPtr) attrDecl);
4294 }
4295 }
4296 }
4297 return(NULL);
4298}
4299
4300/**
Owen Taylor3473f882001-02-23 17:55:21 +00004301 * xmlGetProp:
4302 * @node: the node
4303 * @name: the attribute name
4304 *
4305 * Search and get the value of an attribute associated to a node
4306 * This does the entity substitution.
4307 * This function looks in DTD attribute declaration for #FIXED or
4308 * default declaration values unless DTD use has been turned off.
4309 *
4310 * Returns the attribute value or NULL if not found.
4311 * It's up to the caller to free the memory.
4312 */
4313xmlChar *
4314xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4315 xmlAttrPtr prop;
4316 xmlDocPtr doc;
4317
4318 if ((node == NULL) || (name == NULL)) return(NULL);
4319 /*
4320 * Check on the properties attached to the node
4321 */
4322 prop = node->properties;
4323 while (prop != NULL) {
4324 if (xmlStrEqual(prop->name, name)) {
4325 xmlChar *ret;
4326
4327 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4328 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4329 return(ret);
4330 }
4331 prop = prop->next;
4332 }
4333 if (!xmlCheckDTD) return(NULL);
4334
4335 /*
4336 * Check if there is a default declaration in the internal
4337 * or external subsets
4338 */
4339 doc = node->doc;
4340 if (doc != NULL) {
4341 xmlAttributePtr attrDecl;
4342 if (doc->intSubset != NULL) {
4343 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4344 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4345 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4346 if (attrDecl != NULL)
4347 return(xmlStrdup(attrDecl->defaultValue));
4348 }
4349 }
4350 return(NULL);
4351}
4352
4353/**
4354 * xmlGetNsProp:
4355 * @node: the node
4356 * @name: the attribute name
4357 * @namespace: the URI of the namespace
4358 *
4359 * Search and get the value of an attribute associated to a node
4360 * This attribute has to be anchored in the namespace specified.
4361 * This does the entity substitution.
4362 * This function looks in DTD attribute declaration for #FIXED or
4363 * default declaration values unless DTD use has been turned off.
4364 *
4365 * Returns the attribute value or NULL if not found.
4366 * It's up to the caller to free the memory.
4367 */
4368xmlChar *
4369xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
4370 xmlAttrPtr prop;
4371 xmlDocPtr doc;
4372 xmlNsPtr ns;
4373
4374 if (node == NULL)
4375 return(NULL);
4376
4377 prop = node->properties;
4378 if (namespace == NULL)
4379 return(xmlGetProp(node, name));
4380 while (prop != NULL) {
4381 /*
4382 * One need to have
4383 * - same attribute names
4384 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004385 */
4386 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004387 ((prop->ns != NULL) &&
4388 (xmlStrEqual(prop->ns->href, namespace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004389 xmlChar *ret;
4390
4391 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4392 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4393 return(ret);
4394 }
4395 prop = prop->next;
4396 }
4397 if (!xmlCheckDTD) return(NULL);
4398
4399 /*
4400 * Check if there is a default declaration in the internal
4401 * or external subsets
4402 */
4403 doc = node->doc;
4404 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004405 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004406 xmlAttributePtr attrDecl;
4407
Owen Taylor3473f882001-02-23 17:55:21 +00004408 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4409 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4410 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4411
4412 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4413 /*
4414 * The DTD declaration only allows a prefix search
4415 */
4416 ns = xmlSearchNs(doc, node, attrDecl->prefix);
4417 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
4418 return(xmlStrdup(attrDecl->defaultValue));
4419 }
4420 }
4421 }
4422 return(NULL);
4423}
4424
4425/**
4426 * xmlSetProp:
4427 * @node: the node
4428 * @name: the attribute name
4429 * @value: the attribute value
4430 *
4431 * Set (or reset) an attribute carried by a node.
4432 * Returns the attribute pointer.
4433 */
4434xmlAttrPtr
4435xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
4436 xmlAttrPtr prop = node->properties;
4437 xmlDocPtr doc = NULL;
4438
4439 if ((node == NULL) || (name == NULL))
4440 return(NULL);
4441 doc = node->doc;
4442 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004443 if ((xmlStrEqual(prop->name, name)) &&
4444 (prop->ns == NULL)){
Owen Taylor3473f882001-02-23 17:55:21 +00004445 if (prop->children != NULL)
4446 xmlFreeNodeList(prop->children);
4447 prop->children = NULL;
4448 prop->last = NULL;
4449 if (value != NULL) {
4450 xmlChar *buffer;
4451 xmlNodePtr tmp;
4452
4453 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4454 prop->children = xmlStringGetNodeList(node->doc, buffer);
4455 prop->last = NULL;
4456 prop->doc = doc;
4457 tmp = prop->children;
4458 while (tmp != NULL) {
4459 tmp->parent = (xmlNodePtr) prop;
4460 tmp->doc = doc;
4461 if (tmp->next == NULL)
4462 prop->last = tmp;
4463 tmp = tmp->next;
4464 }
4465 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004466 }
Owen Taylor3473f882001-02-23 17:55:21 +00004467 return(prop);
4468 }
4469 prop = prop->next;
4470 }
4471 prop = xmlNewProp(node, name, value);
4472 return(prop);
4473}
4474
4475/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004476 * xmlUnsetProp:
4477 * @node: the node
4478 * @name: the attribute name
4479 *
4480 * Remove an attribute carried by a node.
4481 * Returns 0 if successful, -1 if not found
4482 */
4483int
4484xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4485 xmlAttrPtr prop = node->properties, prev = NULL;;
4486
4487 if ((node == NULL) || (name == NULL))
4488 return(-1);
4489 while (prop != NULL) {
4490 if ((xmlStrEqual(prop->name, name)) &&
4491 (prop->ns == NULL)) {
4492 if (prev == NULL)
4493 node->properties = prop->next;
4494 else
4495 prev->next = prop->next;
4496 xmlFreeProp(prop);
4497 return(0);
4498 }
4499 prev = prop;
4500 prop = prop->next;
4501 }
4502 return(-1);
4503}
4504
4505/**
Owen Taylor3473f882001-02-23 17:55:21 +00004506 * xmlSetNsProp:
4507 * @node: the node
4508 * @ns: the namespace definition
4509 * @name: the attribute name
4510 * @value: the attribute value
4511 *
4512 * Set (or reset) an attribute carried by a node.
4513 * The ns structure must be in scope, this is not checked.
4514 *
4515 * Returns the attribute pointer.
4516 */
4517xmlAttrPtr
4518xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4519 const xmlChar *value) {
4520 xmlAttrPtr prop;
4521
4522 if ((node == NULL) || (name == NULL))
4523 return(NULL);
4524
4525 if (ns == NULL)
4526 return(xmlSetProp(node, name, value));
4527 if (ns->href == NULL)
4528 return(NULL);
4529 prop = node->properties;
4530
4531 while (prop != NULL) {
4532 /*
4533 * One need to have
4534 * - same attribute names
4535 * - and the attribute carrying that namespace
4536 * or
4537 * no namespace on the attribute and the element carrying it
4538 */
4539 if ((xmlStrEqual(prop->name, name)) &&
4540 (((prop->ns == NULL) && (node->ns != NULL) &&
4541 (xmlStrEqual(node->ns->href, ns->href))) ||
4542 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4543 if (prop->children != NULL)
4544 xmlFreeNodeList(prop->children);
4545 prop->children = NULL;
4546 prop->last = NULL;
4547 prop->ns = ns;
4548 if (value != NULL) {
4549 xmlChar *buffer;
4550 xmlNodePtr tmp;
4551
4552 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4553 prop->children = xmlStringGetNodeList(node->doc, buffer);
4554 prop->last = NULL;
4555 tmp = prop->children;
4556 while (tmp != NULL) {
4557 tmp->parent = (xmlNodePtr) prop;
4558 if (tmp->next == NULL)
4559 prop->last = tmp;
4560 tmp = tmp->next;
4561 }
4562 xmlFree(buffer);
4563 }
4564 return(prop);
4565 }
4566 prop = prop->next;
4567 }
4568 prop = xmlNewNsProp(node, ns, name, value);
4569 return(prop);
4570}
4571
4572/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004573 * xmlUnsetNsProp:
4574 * @node: the node
4575 * @ns: the namespace definition
4576 * @name: the attribute name
4577 *
4578 * Remove an attribute carried by a node.
4579 * Returns 0 if successful, -1 if not found
4580 */
4581int
4582xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4583 xmlAttrPtr prop = node->properties, prev = NULL;;
4584
4585 if ((node == NULL) || (name == NULL))
4586 return(-1);
4587 if (ns == NULL)
4588 return(xmlUnsetProp(node, name));
4589 if (ns->href == NULL)
4590 return(-1);
4591 while (prop != NULL) {
4592 if ((xmlStrEqual(prop->name, name)) &&
4593 (((prop->ns == NULL) && (node->ns != NULL) &&
4594 (xmlStrEqual(node->ns->href, ns->href))) ||
4595 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4596 if (prev == NULL)
4597 node->properties = prop->next;
4598 else
4599 prev->next = prop->next;
4600 xmlFreeProp(prop);
4601 return(0);
4602 }
4603 prev = prop;
4604 prop = prop->next;
4605 }
4606 return(-1);
4607}
4608
4609/**
Owen Taylor3473f882001-02-23 17:55:21 +00004610 * xmlNodeIsText:
4611 * @node: the node
4612 *
4613 * Is this node a Text node ?
4614 * Returns 1 yes, 0 no
4615 */
4616int
4617xmlNodeIsText(xmlNodePtr node) {
4618 if (node == NULL) return(0);
4619
4620 if (node->type == XML_TEXT_NODE) return(1);
4621 return(0);
4622}
4623
4624/**
4625 * xmlIsBlankNode:
4626 * @node: the node
4627 *
4628 * Checks whether this node is an empty or whitespace only
4629 * (and possibly ignorable) text-node.
4630 *
4631 * Returns 1 yes, 0 no
4632 */
4633int
4634xmlIsBlankNode(xmlNodePtr node) {
4635 const xmlChar *cur;
4636 if (node == NULL) return(0);
4637
4638 if (node->type != XML_TEXT_NODE) return(0);
4639 if (node->content == NULL) return(1);
4640#ifndef XML_USE_BUFFER_CONTENT
4641 cur = node->content;
4642#else
4643 cur = xmlBufferContent(node->content);
4644#endif
4645 while (*cur != 0) {
4646 if (!IS_BLANK(*cur)) return(0);
4647 cur++;
4648 }
4649
4650 return(1);
4651}
4652
4653/**
4654 * xmlTextConcat:
4655 * @node: the node
4656 * @content: the content
4657 * @len: @content lenght
4658 *
4659 * Concat the given string at the end of the existing node content
4660 */
4661
4662void
4663xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4664 if (node == NULL) return;
4665
4666 if ((node->type != XML_TEXT_NODE) &&
4667 (node->type != XML_CDATA_SECTION_NODE)) {
4668#ifdef DEBUG_TREE
4669 xmlGenericError(xmlGenericErrorContext,
4670 "xmlTextConcat: node is not text nor cdata\n");
4671#endif
4672 return;
4673 }
4674#ifndef XML_USE_BUFFER_CONTENT
4675 node->content = xmlStrncat(node->content, content, len);
4676#else
4677 xmlBufferAdd(node->content, content, len);
4678#endif
4679}
4680
4681/************************************************************************
4682 * *
4683 * Output : to a FILE or in memory *
4684 * *
4685 ************************************************************************/
4686
4687#define BASE_BUFFER_SIZE 4000
4688
Daniel Veillarde356c282001-03-10 12:32:04 +00004689int xmlDefaultBufferSize = BASE_BUFFER_SIZE;
4690
Owen Taylor3473f882001-02-23 17:55:21 +00004691/**
4692 * xmlBufferCreate:
4693 *
4694 * routine to create an XML buffer.
4695 * returns the new structure.
4696 */
4697xmlBufferPtr
4698xmlBufferCreate(void) {
4699 xmlBufferPtr ret;
4700
4701 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4702 if (ret == NULL) {
4703 xmlGenericError(xmlGenericErrorContext,
4704 "xmlBufferCreate : out of memory!\n");
4705 return(NULL);
4706 }
4707 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004708 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004709 ret->alloc = xmlBufferAllocScheme;
4710 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4711 if (ret->content == NULL) {
4712 xmlGenericError(xmlGenericErrorContext,
4713 "xmlBufferCreate : out of memory!\n");
4714 xmlFree(ret);
4715 return(NULL);
4716 }
4717 ret->content[0] = 0;
4718 return(ret);
4719}
4720
4721/**
4722 * xmlBufferCreateSize:
4723 * @size: initial size of buffer
4724 *
4725 * routine to create an XML buffer.
4726 * returns the new structure.
4727 */
4728xmlBufferPtr
4729xmlBufferCreateSize(size_t size) {
4730 xmlBufferPtr ret;
4731
4732 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4733 if (ret == NULL) {
4734 xmlGenericError(xmlGenericErrorContext,
4735 "xmlBufferCreate : out of memory!\n");
4736 return(NULL);
4737 }
4738 ret->use = 0;
4739 ret->alloc = xmlBufferAllocScheme;
4740 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4741 if (ret->size){
4742 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4743 if (ret->content == NULL) {
4744 xmlGenericError(xmlGenericErrorContext,
4745 "xmlBufferCreate : out of memory!\n");
4746 xmlFree(ret);
4747 return(NULL);
4748 }
4749 ret->content[0] = 0;
4750 } else
4751 ret->content = NULL;
4752 return(ret);
4753}
4754
4755/**
4756 * xmlBufferSetAllocationScheme:
4757 * @buf: the buffer to free
4758 * @scheme: allocation scheme to use
4759 *
4760 * Sets the allocation scheme for this buffer
4761 */
4762void
4763xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4764 xmlBufferAllocationScheme scheme) {
4765 if (buf == NULL) {
4766#ifdef DEBUG_BUFFER
4767 xmlGenericError(xmlGenericErrorContext,
4768 "xmlBufferSetAllocationScheme: buf == NULL\n");
4769#endif
4770 return;
4771 }
4772
4773 buf->alloc = scheme;
4774}
4775
4776/**
4777 * xmlBufferFree:
4778 * @buf: the buffer to free
4779 *
4780 * Frees an XML buffer.
4781 */
4782void
4783xmlBufferFree(xmlBufferPtr buf) {
4784 if (buf == NULL) {
4785#ifdef DEBUG_BUFFER
4786 xmlGenericError(xmlGenericErrorContext,
4787 "xmlBufferFree: buf == NULL\n");
4788#endif
4789 return;
4790 }
4791 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004792 xmlFree(buf->content);
4793 }
Owen Taylor3473f882001-02-23 17:55:21 +00004794 xmlFree(buf);
4795}
4796
4797/**
4798 * xmlBufferEmpty:
4799 * @buf: the buffer
4800 *
4801 * empty a buffer.
4802 */
4803void
4804xmlBufferEmpty(xmlBufferPtr buf) {
4805 if (buf->content == NULL) return;
4806 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004807 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004808}
4809
4810/**
4811 * xmlBufferShrink:
4812 * @buf: the buffer to dump
4813 * @len: the number of xmlChar to remove
4814 *
4815 * Remove the beginning of an XML buffer.
4816 *
4817 * Returns the number of xmlChar removed, or -1 in case of failure.
4818 */
4819int
4820xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
4821 if (len == 0) return(0);
4822 if (len > buf->use) return(-1);
4823
4824 buf->use -= len;
4825 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
4826
4827 buf->content[buf->use] = 0;
4828 return(len);
4829}
4830
4831/**
4832 * xmlBufferGrow:
4833 * @buf: the buffer
4834 * @len: the minimum free size to allocate
4835 *
4836 * Grow the available space of an XML buffer.
4837 *
4838 * Returns the new available space or -1 in case of error
4839 */
4840int
4841xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
4842 int size;
4843 xmlChar *newbuf;
4844
4845 if (len + buf->use < buf->size) return(0);
4846
4847 size = buf->use + len + 100;
4848
4849 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
4850 if (newbuf == NULL) return(-1);
4851 buf->content = newbuf;
4852 buf->size = size;
4853 return(buf->size - buf->use);
4854}
4855
4856/**
4857 * xmlBufferDump:
4858 * @file: the file output
4859 * @buf: the buffer to dump
4860 *
4861 * Dumps an XML buffer to a FILE *.
4862 * Returns the number of xmlChar written
4863 */
4864int
4865xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4866 int ret;
4867
4868 if (buf == NULL) {
4869#ifdef DEBUG_BUFFER
4870 xmlGenericError(xmlGenericErrorContext,
4871 "xmlBufferDump: buf == NULL\n");
4872#endif
4873 return(0);
4874 }
4875 if (buf->content == NULL) {
4876#ifdef DEBUG_BUFFER
4877 xmlGenericError(xmlGenericErrorContext,
4878 "xmlBufferDump: buf->content == NULL\n");
4879#endif
4880 return(0);
4881 }
4882 if (file == NULL) file = stdout;
4883 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
4884 return(ret);
4885}
4886
4887/**
4888 * xmlBufferContent:
4889 * @buf: the buffer
4890 *
4891 * Returns the internal content
4892 */
4893
4894const xmlChar*
4895xmlBufferContent(const xmlBufferPtr buf)
4896{
4897 if(!buf)
4898 return NULL;
4899
4900 return buf->content;
4901}
4902
4903/**
4904 * xmlBufferLength:
4905 * @buf: the buffer
4906 *
4907 * Returns the length of data in the internal content
4908 */
4909
4910int
4911xmlBufferLength(const xmlBufferPtr buf)
4912{
4913 if(!buf)
4914 return 0;
4915
4916 return buf->use;
4917}
4918
4919/**
4920 * xmlBufferResize:
4921 * @buf: the buffer to resize
4922 * @size: the desired size
4923 *
4924 * Resize a buffer to accomodate minimum size of @size.
4925 *
4926 * Returns 0 in case of problems, 1 otherwise
4927 */
4928int
4929xmlBufferResize(xmlBufferPtr buf, unsigned int size)
4930{
4931 unsigned int newSize;
4932 xmlChar* rebuf = NULL;
4933
4934 /*take care of empty case*/
4935 newSize = (buf->size ? buf->size*2 : size);
4936
4937 /* Don't resize if we don't have to */
4938 if (size < buf->size)
4939 return 1;
4940
4941 /* figure out new size */
4942 switch (buf->alloc){
4943 case XML_BUFFER_ALLOC_DOUBLEIT:
4944 while (size > newSize) newSize *= 2;
4945 break;
4946 case XML_BUFFER_ALLOC_EXACT:
4947 newSize = size+10;
4948 break;
4949 default:
4950 newSize = size+10;
4951 break;
4952 }
4953
4954 if (buf->content == NULL)
4955 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4956 else
4957 rebuf = (xmlChar *) xmlRealloc(buf->content,
4958 newSize * sizeof(xmlChar));
4959 if (rebuf == NULL) {
4960 xmlGenericError(xmlGenericErrorContext,
4961 "xmlBufferAdd : out of memory!\n");
4962 return 0;
4963 }
4964 buf->content = rebuf;
4965 buf->size = newSize;
4966
4967 return 1;
4968}
4969
4970/**
4971 * xmlBufferAdd:
4972 * @buf: the buffer to dump
4973 * @str: the xmlChar string
4974 * @len: the number of xmlChar to add
4975 *
4976 * Add a string range to an XML buffer. if len == -1, the lenght of
4977 * str is recomputed.
4978 */
4979void
4980xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
4981 unsigned int needSize;
4982
4983 if (str == NULL) {
4984#ifdef DEBUG_BUFFER
4985 xmlGenericError(xmlGenericErrorContext,
4986 "xmlBufferAdd: str == NULL\n");
4987#endif
4988 return;
4989 }
4990 if (len < -1) {
4991#ifdef DEBUG_BUFFER
4992 xmlGenericError(xmlGenericErrorContext,
4993 "xmlBufferAdd: len < 0\n");
4994#endif
4995 return;
4996 }
4997 if (len == 0) return;
4998
4999 if (len < 0)
5000 len = xmlStrlen(str);
5001
5002 if (len <= 0) return;
5003
5004 needSize = buf->use + len + 2;
5005 if (needSize > buf->size){
5006 if (!xmlBufferResize(buf, needSize)){
5007 xmlGenericError(xmlGenericErrorContext,
5008 "xmlBufferAdd : out of memory!\n");
5009 return;
5010 }
5011 }
5012
5013 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5014 buf->use += len;
5015 buf->content[buf->use] = 0;
5016}
5017
5018/**
5019 * xmlBufferAddHead:
5020 * @buf: the buffer
5021 * @str: the xmlChar string
5022 * @len: the number of xmlChar to add
5023 *
5024 * Add a string range to the beginning of an XML buffer.
5025 * if len == -1, the lenght of @str is recomputed.
5026 */
5027void
5028xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5029 unsigned int needSize;
5030
5031 if (str == NULL) {
5032#ifdef DEBUG_BUFFER
5033 xmlGenericError(xmlGenericErrorContext,
5034 "xmlBufferAdd: str == NULL\n");
5035#endif
5036 return;
5037 }
5038 if (len < -1) {
5039#ifdef DEBUG_BUFFER
5040 xmlGenericError(xmlGenericErrorContext,
5041 "xmlBufferAdd: len < 0\n");
5042#endif
5043 return;
5044 }
5045 if (len == 0) return;
5046
5047 if (len < 0)
5048 len = xmlStrlen(str);
5049
5050 if (len <= 0) return;
5051
5052 needSize = buf->use + len + 2;
5053 if (needSize > buf->size){
5054 if (!xmlBufferResize(buf, needSize)){
5055 xmlGenericError(xmlGenericErrorContext,
5056 "xmlBufferAddHead : out of memory!\n");
5057 return;
5058 }
5059 }
5060
5061 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5062 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5063 buf->use += len;
5064 buf->content[buf->use] = 0;
5065}
5066
5067/**
5068 * xmlBufferCat:
5069 * @buf: the buffer to dump
5070 * @str: the xmlChar string
5071 *
5072 * Append a zero terminated string to an XML buffer.
5073 */
5074void
5075xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5076 if (str != NULL)
5077 xmlBufferAdd(buf, str, -1);
5078}
5079
5080/**
5081 * xmlBufferCCat:
5082 * @buf: the buffer to dump
5083 * @str: the C char string
5084 *
5085 * Append a zero terminated C string to an XML buffer.
5086 */
5087void
5088xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5089 const char *cur;
5090
5091 if (str == NULL) {
5092#ifdef DEBUG_BUFFER
5093 xmlGenericError(xmlGenericErrorContext,
5094 "xmlBufferAdd: str == NULL\n");
5095#endif
5096 return;
5097 }
5098 for (cur = str;*cur != 0;cur++) {
5099 if (buf->use + 10 >= buf->size) {
5100 if (!xmlBufferResize(buf, buf->use+10)){
5101 xmlGenericError(xmlGenericErrorContext,
5102 "xmlBufferCCat : out of memory!\n");
5103 return;
5104 }
5105 }
5106 buf->content[buf->use++] = *cur;
5107 }
5108 buf->content[buf->use] = 0;
5109}
5110
5111/**
5112 * xmlBufferWriteCHAR:
5113 * @buf: the XML buffer
5114 * @string: the string to add
5115 *
5116 * routine which manages and grows an output buffer. This one adds
5117 * xmlChars at the end of the buffer.
5118 */
5119void
5120#ifdef VMS
5121xmlBufferWriteXmlCHAR
5122#else
5123xmlBufferWriteCHAR
5124#endif
5125(xmlBufferPtr buf, const xmlChar *string) {
5126 xmlBufferCat(buf, string);
5127}
5128
5129/**
5130 * xmlBufferWriteChar:
5131 * @buf: the XML buffer output
5132 * @string: the string to add
5133 *
5134 * routine which manage and grows an output buffer. This one add
5135 * C chars at the end of the array.
5136 */
5137void
5138xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5139 xmlBufferCCat(buf, string);
5140}
5141
5142
5143/**
5144 * xmlBufferWriteQuotedString:
5145 * @buf: the XML buffer output
5146 * @string: the string to add
5147 *
5148 * routine which manage and grows an output buffer. This one writes
5149 * a quoted or double quoted xmlChar string, checking first if it holds
5150 * quote or double-quotes internally
5151 */
5152void
5153xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5154 if (xmlStrchr(string, '"')) {
5155 if (xmlStrchr(string, '\'')) {
5156#ifdef DEBUG_BUFFER
5157 xmlGenericError(xmlGenericErrorContext,
5158 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5159#endif
5160 }
5161 xmlBufferCCat(buf, "'");
5162 xmlBufferCat(buf, string);
5163 xmlBufferCCat(buf, "'");
5164 } else {
5165 xmlBufferCCat(buf, "\"");
5166 xmlBufferCat(buf, string);
5167 xmlBufferCCat(buf, "\"");
5168 }
5169}
5170
5171
5172/************************************************************************
5173 * *
5174 * Dumping XML tree content to a simple buffer *
5175 * *
5176 ************************************************************************/
5177
5178void
5179xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5180 int format);
5181static void
5182xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5183 int format);
5184void
5185htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5186
5187/**
5188 * xmlNsDump:
5189 * @buf: the XML buffer output
5190 * @cur: a namespace
5191 *
5192 * Dump a local Namespace definition.
5193 * Should be called in the context of attributes dumps.
5194 */
5195static void
5196xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5197 if (cur == NULL) {
5198#ifdef DEBUG_TREE
5199 xmlGenericError(xmlGenericErrorContext,
5200 "xmlNsDump : Ns == NULL\n");
5201#endif
5202 return;
5203 }
5204 if (cur->type == XML_LOCAL_NAMESPACE) {
5205 /* Within the context of an element attributes */
5206 if (cur->prefix != NULL) {
5207 xmlBufferWriteChar(buf, " xmlns:");
5208 xmlBufferWriteCHAR(buf, cur->prefix);
5209 } else
5210 xmlBufferWriteChar(buf, " xmlns");
5211 xmlBufferWriteChar(buf, "=");
5212 xmlBufferWriteQuotedString(buf, cur->href);
5213 }
5214}
5215
5216/**
5217 * xmlNsListDump:
5218 * @buf: the XML buffer output
5219 * @cur: the first namespace
5220 *
5221 * Dump a list of local Namespace definitions.
5222 * Should be called in the context of attributes dumps.
5223 */
5224static void
5225xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5226 while (cur != NULL) {
5227 xmlNsDump(buf, cur);
5228 cur = cur->next;
5229 }
5230}
5231
5232/**
5233 * xmlDtdDump:
5234 * @buf: the XML buffer output
5235 * @doc: the document
5236 *
5237 * Dump the XML document DTD, if any.
5238 */
5239static void
5240xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5241 if (dtd == NULL) {
5242#ifdef DEBUG_TREE
5243 xmlGenericError(xmlGenericErrorContext,
5244 "xmlDtdDump : no internal subset\n");
5245#endif
5246 return;
5247 }
5248 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5249 xmlBufferWriteCHAR(buf, dtd->name);
5250 if (dtd->ExternalID != NULL) {
5251 xmlBufferWriteChar(buf, " PUBLIC ");
5252 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5253 xmlBufferWriteChar(buf, " ");
5254 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5255 } else if (dtd->SystemID != NULL) {
5256 xmlBufferWriteChar(buf, " SYSTEM ");
5257 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5258 }
5259 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5260 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5261 xmlBufferWriteChar(buf, ">");
5262 return;
5263 }
5264 xmlBufferWriteChar(buf, " [\n");
5265 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5266#if 0
5267 if (dtd->entities != NULL)
5268 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5269 if (dtd->notations != NULL)
5270 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5271 if (dtd->elements != NULL)
5272 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5273 if (dtd->attributes != NULL)
5274 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5275#endif
5276 xmlBufferWriteChar(buf, "]>");
5277}
5278
5279/**
5280 * xmlAttrDump:
5281 * @buf: the XML buffer output
5282 * @doc: the document
5283 * @cur: the attribute pointer
5284 *
5285 * Dump an XML attribute
5286 */
5287static void
5288xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5289 xmlChar *value;
5290
5291 if (cur == NULL) {
5292#ifdef DEBUG_TREE
5293 xmlGenericError(xmlGenericErrorContext,
5294 "xmlAttrDump : property == NULL\n");
5295#endif
5296 return;
5297 }
5298 xmlBufferWriteChar(buf, " ");
5299 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5300 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5301 xmlBufferWriteChar(buf, ":");
5302 }
5303 xmlBufferWriteCHAR(buf, cur->name);
5304 value = xmlNodeListGetString(doc, cur->children, 0);
5305 if (value != NULL) {
5306 xmlBufferWriteChar(buf, "=");
5307 xmlBufferWriteQuotedString(buf, value);
5308 xmlFree(value);
5309 } else {
5310 xmlBufferWriteChar(buf, "=\"\"");
5311 }
5312}
5313
5314/**
5315 * xmlAttrListDump:
5316 * @buf: the XML buffer output
5317 * @doc: the document
5318 * @cur: the first attribute pointer
5319 *
5320 * Dump a list of XML attributes
5321 */
5322static void
5323xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5324 if (cur == NULL) {
5325#ifdef DEBUG_TREE
5326 xmlGenericError(xmlGenericErrorContext,
5327 "xmlAttrListDump : property == NULL\n");
5328#endif
5329 return;
5330 }
5331 while (cur != NULL) {
5332 xmlAttrDump(buf, doc, cur);
5333 cur = cur->next;
5334 }
5335}
5336
5337
5338
5339/**
5340 * xmlNodeListDump:
5341 * @buf: the XML buffer output
5342 * @doc: the document
5343 * @cur: the first node
5344 * @level: the imbrication level for indenting
5345 * @format: is formatting allowed
5346 *
5347 * Dump an XML node list, recursive behaviour,children are printed too.
5348 */
5349static void
5350xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5351 int format) {
5352 int i;
5353
5354 if (cur == NULL) {
5355#ifdef DEBUG_TREE
5356 xmlGenericError(xmlGenericErrorContext,
5357 "xmlNodeListDump : node == NULL\n");
5358#endif
5359 return;
5360 }
5361 while (cur != NULL) {
5362 if ((format) && (xmlIndentTreeOutput) &&
5363 (cur->type == XML_ELEMENT_NODE))
5364 for (i = 0;i < level;i++)
5365 xmlBufferWriteChar(buf, " ");
5366 xmlNodeDump(buf, doc, cur, level, format);
5367 if (format) {
5368 xmlBufferWriteChar(buf, "\n");
5369 }
5370 cur = cur->next;
5371 }
5372}
5373
5374/**
5375 * xmlNodeDump:
5376 * @buf: the XML buffer output
5377 * @doc: the document
5378 * @cur: the current node
5379 * @level: the imbrication level for indenting
5380 * @format: is formatting allowed
5381 *
5382 * Dump an XML node, recursive behaviour,children are printed too.
5383 */
5384void
5385xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5386 int format) {
5387 int i;
5388 xmlNodePtr tmp;
5389
5390 if (cur == NULL) {
5391#ifdef DEBUG_TREE
5392 xmlGenericError(xmlGenericErrorContext,
5393 "xmlNodeDump : node == NULL\n");
5394#endif
5395 return;
5396 }
5397 if (cur->type == XML_XINCLUDE_START)
5398 return;
5399 if (cur->type == XML_XINCLUDE_END)
5400 return;
5401 if (cur->type == XML_DTD_NODE) {
5402 xmlDtdDump(buf, (xmlDtdPtr) cur);
5403 return;
5404 }
5405 if (cur->type == XML_ELEMENT_DECL) {
5406 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5407 return;
5408 }
5409 if (cur->type == XML_ATTRIBUTE_DECL) {
5410 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5411 return;
5412 }
5413 if (cur->type == XML_ENTITY_DECL) {
5414 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5415 return;
5416 }
5417 if (cur->type == XML_TEXT_NODE) {
5418 if (cur->content != NULL) {
5419 if ((cur->name == xmlStringText) ||
5420 (cur->name != xmlStringTextNoenc)) {
5421 xmlChar *buffer;
5422
5423#ifndef XML_USE_BUFFER_CONTENT
5424 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5425#else
5426 buffer = xmlEncodeEntitiesReentrant(doc,
5427 xmlBufferContent(cur->content));
5428#endif
5429 if (buffer != NULL) {
5430 xmlBufferWriteCHAR(buf, buffer);
5431 xmlFree(buffer);
5432 }
5433 } else {
5434 /*
5435 * Disable escaping, needed for XSLT
5436 */
5437#ifndef XML_USE_BUFFER_CONTENT
5438 xmlBufferWriteCHAR(buf, cur->content);
5439#else
5440 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5441#endif
5442 }
5443 }
5444 return;
5445 }
5446 if (cur->type == XML_PI_NODE) {
5447 if (cur->content != NULL) {
5448 xmlBufferWriteChar(buf, "<?");
5449 xmlBufferWriteCHAR(buf, cur->name);
5450 if (cur->content != NULL) {
5451 xmlBufferWriteChar(buf, " ");
5452#ifndef XML_USE_BUFFER_CONTENT
5453 xmlBufferWriteCHAR(buf, cur->content);
5454#else
5455 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5456#endif
5457 }
5458 xmlBufferWriteChar(buf, "?>");
5459 } else {
5460 xmlBufferWriteChar(buf, "<?");
5461 xmlBufferWriteCHAR(buf, cur->name);
5462 xmlBufferWriteChar(buf, "?>");
5463 }
5464 return;
5465 }
5466 if (cur->type == XML_COMMENT_NODE) {
5467 if (cur->content != NULL) {
5468 xmlBufferWriteChar(buf, "<!--");
5469#ifndef XML_USE_BUFFER_CONTENT
5470 xmlBufferWriteCHAR(buf, cur->content);
5471#else
5472 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5473#endif
5474 xmlBufferWriteChar(buf, "-->");
5475 }
5476 return;
5477 }
5478 if (cur->type == XML_ENTITY_REF_NODE) {
5479 xmlBufferWriteChar(buf, "&");
5480 xmlBufferWriteCHAR(buf, cur->name);
5481 xmlBufferWriteChar(buf, ";");
5482 return;
5483 }
5484 if (cur->type == XML_CDATA_SECTION_NODE) {
5485 xmlBufferWriteChar(buf, "<![CDATA[");
5486 if (cur->content != NULL)
5487#ifndef XML_USE_BUFFER_CONTENT
5488 xmlBufferWriteCHAR(buf, cur->content);
5489#else
5490 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5491#endif
5492 xmlBufferWriteChar(buf, "]]>");
5493 return;
5494 }
5495
5496 if (format == 1) {
5497 tmp = cur->children;
5498 while (tmp != NULL) {
5499 if ((tmp->type == XML_TEXT_NODE) ||
5500 (tmp->type == XML_ENTITY_REF_NODE)) {
5501 format = 0;
5502 break;
5503 }
5504 tmp = tmp->next;
5505 }
5506 }
5507 xmlBufferWriteChar(buf, "<");
5508 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5509 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5510 xmlBufferWriteChar(buf, ":");
5511 }
5512
5513 xmlBufferWriteCHAR(buf, cur->name);
5514 if (cur->nsDef)
5515 xmlNsListDump(buf, cur->nsDef);
5516 if (cur->properties != NULL)
5517 xmlAttrListDump(buf, doc, cur->properties);
5518
5519 if ((cur->content == NULL) && (cur->children == NULL) &&
5520 (!xmlSaveNoEmptyTags)) {
5521 xmlBufferWriteChar(buf, "/>");
5522 return;
5523 }
5524 xmlBufferWriteChar(buf, ">");
5525 if (cur->content != NULL) {
5526 xmlChar *buffer;
5527
5528#ifndef XML_USE_BUFFER_CONTENT
5529 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5530#else
5531 buffer = xmlEncodeEntitiesReentrant(doc,
5532 xmlBufferContent(cur->content));
5533#endif
5534 if (buffer != NULL) {
5535 xmlBufferWriteCHAR(buf, buffer);
5536 xmlFree(buffer);
5537 }
5538 }
5539 if (cur->children != NULL) {
5540 if (format) xmlBufferWriteChar(buf, "\n");
5541 xmlNodeListDump(buf, doc, cur->children,
5542 (level >= 0?level+1:-1), format);
5543 if ((xmlIndentTreeOutput) && (format))
5544 for (i = 0;i < level;i++)
5545 xmlBufferWriteChar(buf, " ");
5546 }
5547 xmlBufferWriteChar(buf, "</");
5548 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5549 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5550 xmlBufferWriteChar(buf, ":");
5551 }
5552
5553 xmlBufferWriteCHAR(buf, cur->name);
5554 xmlBufferWriteChar(buf, ">");
5555}
5556
5557/**
5558 * xmlElemDump:
5559 * @f: the FILE * for the output
5560 * @doc: the document
5561 * @cur: the current node
5562 *
5563 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5564 */
5565void
5566xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5567 xmlBufferPtr buf;
5568
5569 if (cur == NULL) {
5570#ifdef DEBUG_TREE
5571 xmlGenericError(xmlGenericErrorContext,
5572 "xmlElemDump : cur == NULL\n");
5573#endif
5574 return;
5575 }
5576 if (doc == NULL) {
5577#ifdef DEBUG_TREE
5578 xmlGenericError(xmlGenericErrorContext,
5579 "xmlElemDump : doc == NULL\n");
5580#endif
5581 }
5582 buf = xmlBufferCreate();
5583 if (buf == NULL) return;
5584 if ((doc != NULL) &&
5585 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5586#ifdef LIBXML_HTML_ENABLED
5587 htmlNodeDump(buf, doc, cur);
5588#else
5589 xmlGenericError(xmlGenericErrorContext,
5590 "HTML support not compiled in\n");
5591#endif /* LIBXML_HTML_ENABLED */
5592 } else
5593 xmlNodeDump(buf, doc, cur, 0, 1);
5594 xmlBufferDump(f, buf);
5595 xmlBufferFree(buf);
5596}
5597
5598/************************************************************************
5599 * *
5600 * Dumping XML tree content to an I/O output buffer *
5601 * *
5602 ************************************************************************/
5603
5604void
5605xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5606 int level, int format, const char *encoding);
5607static void
5608xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5609 int level, int format, const char *encoding);
5610/**
5611 * xmlNsDumpOutput:
5612 * @buf: the XML buffer output
5613 * @cur: a namespace
5614 *
5615 * Dump a local Namespace definition.
5616 * Should be called in the context of attributes dumps.
5617 */
5618static void
5619xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5620 if (cur == NULL) {
5621#ifdef DEBUG_TREE
5622 xmlGenericError(xmlGenericErrorContext,
5623 "xmlNsDump : Ns == NULL\n");
5624#endif
5625 return;
5626 }
5627 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5628 /* Within the context of an element attributes */
5629 if (cur->prefix != NULL) {
5630 xmlOutputBufferWriteString(buf, " xmlns:");
5631 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5632 } else
5633 xmlOutputBufferWriteString(buf, " xmlns");
5634 xmlOutputBufferWriteString(buf, "=");
5635 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5636 }
5637}
5638
5639/**
5640 * xmlNsListDumpOutput:
5641 * @buf: the XML buffer output
5642 * @cur: the first namespace
5643 *
5644 * Dump a list of local Namespace definitions.
5645 * Should be called in the context of attributes dumps.
5646 */
5647static void
5648xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5649 while (cur != NULL) {
5650 xmlNsDumpOutput(buf, cur);
5651 cur = cur->next;
5652 }
5653}
5654
5655/**
5656 * xmlDtdDumpOutput:
5657 * @buf: the XML buffer output
5658 * @doc: the document
5659 * @encoding: an optional encoding string
5660 *
5661 * Dump the XML document DTD, if any.
5662 */
5663static void
5664xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5665 if (dtd == NULL) {
5666#ifdef DEBUG_TREE
5667 xmlGenericError(xmlGenericErrorContext,
5668 "xmlDtdDump : no internal subset\n");
5669#endif
5670 return;
5671 }
5672 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5673 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5674 if (dtd->ExternalID != NULL) {
5675 xmlOutputBufferWriteString(buf, " PUBLIC ");
5676 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5677 xmlOutputBufferWriteString(buf, " ");
5678 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5679 } else if (dtd->SystemID != NULL) {
5680 xmlOutputBufferWriteString(buf, " SYSTEM ");
5681 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5682 }
5683 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5684 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5685 xmlOutputBufferWriteString(buf, ">");
5686 return;
5687 }
5688 xmlOutputBufferWriteString(buf, " [\n");
5689 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5690 xmlOutputBufferWriteString(buf, "]>");
5691}
5692
5693/**
5694 * xmlAttrDumpOutput:
5695 * @buf: the XML buffer output
5696 * @doc: the document
5697 * @cur: the attribute pointer
5698 * @encoding: an optional encoding string
5699 *
5700 * Dump an XML attribute
5701 */
5702static void
5703xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005704 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005705 xmlChar *value;
5706
5707 if (cur == NULL) {
5708#ifdef DEBUG_TREE
5709 xmlGenericError(xmlGenericErrorContext,
5710 "xmlAttrDump : property == NULL\n");
5711#endif
5712 return;
5713 }
5714 xmlOutputBufferWriteString(buf, " ");
5715 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5716 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5717 xmlOutputBufferWriteString(buf, ":");
5718 }
5719 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5720 value = xmlNodeListGetString(doc, cur->children, 0);
5721 if (value) {
5722 xmlOutputBufferWriteString(buf, "=");
5723 xmlBufferWriteQuotedString(buf->buffer, value);
5724 xmlFree(value);
5725 } else {
5726 xmlOutputBufferWriteString(buf, "=\"\"");
5727 }
5728}
5729
5730/**
5731 * xmlAttrListDumpOutput:
5732 * @buf: the XML buffer output
5733 * @doc: the document
5734 * @cur: the first attribute pointer
5735 * @encoding: an optional encoding string
5736 *
5737 * Dump a list of XML attributes
5738 */
5739static void
5740xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5741 xmlAttrPtr cur, const char *encoding) {
5742 if (cur == NULL) {
5743#ifdef DEBUG_TREE
5744 xmlGenericError(xmlGenericErrorContext,
5745 "xmlAttrListDump : property == NULL\n");
5746#endif
5747 return;
5748 }
5749 while (cur != NULL) {
5750 xmlAttrDumpOutput(buf, doc, cur, encoding);
5751 cur = cur->next;
5752 }
5753}
5754
5755
5756
5757/**
5758 * xmlNodeListDumpOutput:
5759 * @buf: the XML buffer output
5760 * @doc: the document
5761 * @cur: the first node
5762 * @level: the imbrication level for indenting
5763 * @format: is formatting allowed
5764 * @encoding: an optional encoding string
5765 *
5766 * Dump an XML node list, recursive behaviour,children are printed too.
5767 */
5768static void
5769xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5770 xmlNodePtr cur, int level, int format, const char *encoding) {
5771 int i;
5772
5773 if (cur == NULL) {
5774#ifdef DEBUG_TREE
5775 xmlGenericError(xmlGenericErrorContext,
5776 "xmlNodeListDump : node == NULL\n");
5777#endif
5778 return;
5779 }
5780 while (cur != NULL) {
5781 if ((format) && (xmlIndentTreeOutput) &&
5782 (cur->type == XML_ELEMENT_NODE))
5783 for (i = 0;i < level;i++)
5784 xmlOutputBufferWriteString(buf, " ");
5785 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5786 if (format) {
5787 xmlOutputBufferWriteString(buf, "\n");
5788 }
5789 cur = cur->next;
5790 }
5791}
5792
5793/**
5794 * xmlNodeDumpOutput:
5795 * @buf: the XML buffer output
5796 * @doc: the document
5797 * @cur: the current node
5798 * @level: the imbrication level for indenting
5799 * @format: is formatting allowed
5800 * @encoding: an optional encoding string
5801 *
5802 * Dump an XML node, recursive behaviour,children are printed too.
5803 */
5804void
5805xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5806 int level, int format, const char *encoding) {
5807 int i;
5808 xmlNodePtr tmp;
5809
5810 if (cur == NULL) {
5811#ifdef DEBUG_TREE
5812 xmlGenericError(xmlGenericErrorContext,
5813 "xmlNodeDump : node == NULL\n");
5814#endif
5815 return;
5816 }
5817 if (cur->type == XML_XINCLUDE_START)
5818 return;
5819 if (cur->type == XML_XINCLUDE_END)
5820 return;
5821 if (cur->type == XML_DTD_NODE) {
5822 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5823 return;
5824 }
5825 if (cur->type == XML_ELEMENT_DECL) {
5826 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5827 return;
5828 }
5829 if (cur->type == XML_ATTRIBUTE_DECL) {
5830 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5831 return;
5832 }
5833 if (cur->type == XML_ENTITY_DECL) {
5834 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5835 return;
5836 }
5837 if (cur->type == XML_TEXT_NODE) {
5838 if (cur->content != NULL) {
5839 if ((cur->name == xmlStringText) ||
5840 (cur->name != xmlStringTextNoenc)) {
5841 xmlChar *buffer;
5842
5843#ifndef XML_USE_BUFFER_CONTENT
5844 if (encoding == NULL)
5845 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5846 else
5847 buffer = xmlEncodeSpecialChars(doc, cur->content);
5848#else
5849 if (encoding == NULL)
5850 buffer = xmlEncodeEntitiesReentrant(doc,
5851 xmlBufferContent(cur->content));
5852 else
5853 buffer = xmlEncodeSpecialChars(doc,
5854 xmlBufferContent(cur->content));
5855#endif
5856 if (buffer != NULL) {
5857 xmlOutputBufferWriteString(buf, (const char *)buffer);
5858 xmlFree(buffer);
5859 }
5860 } else {
5861 /*
5862 * Disable escaping, needed for XSLT
5863 */
5864#ifndef XML_USE_BUFFER_CONTENT
5865 xmlOutputBufferWriteString(buf, (const char *) cur->content);
5866#else
5867 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5868#endif
5869 }
5870 }
5871
5872 return;
5873 }
5874 if (cur->type == XML_PI_NODE) {
5875 if (cur->content != NULL) {
5876 xmlOutputBufferWriteString(buf, "<?");
5877 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5878 if (cur->content != NULL) {
5879 xmlOutputBufferWriteString(buf, " ");
5880#ifndef XML_USE_BUFFER_CONTENT
5881 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5882#else
5883 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5884#endif
5885 }
5886 xmlOutputBufferWriteString(buf, "?>");
5887 } else {
5888 xmlOutputBufferWriteString(buf, "<?");
5889 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5890 xmlOutputBufferWriteString(buf, "?>");
5891 }
5892 return;
5893 }
5894 if (cur->type == XML_COMMENT_NODE) {
5895 if (cur->content != NULL) {
5896 xmlOutputBufferWriteString(buf, "<!--");
5897#ifndef XML_USE_BUFFER_CONTENT
5898 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5899#else
5900 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5901#endif
5902 xmlOutputBufferWriteString(buf, "-->");
5903 }
5904 return;
5905 }
5906 if (cur->type == XML_ENTITY_REF_NODE) {
5907 xmlOutputBufferWriteString(buf, "&");
5908 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5909 xmlOutputBufferWriteString(buf, ";");
5910 return;
5911 }
5912 if (cur->type == XML_CDATA_SECTION_NODE) {
5913 xmlOutputBufferWriteString(buf, "<![CDATA[");
5914 if (cur->content != NULL)
5915#ifndef XML_USE_BUFFER_CONTENT
5916 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5917#else
5918 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5919#endif
5920 xmlOutputBufferWriteString(buf, "]]>");
5921 return;
5922 }
5923
5924 if (format == 1) {
5925 tmp = cur->children;
5926 while (tmp != NULL) {
5927 if ((tmp->type == XML_TEXT_NODE) ||
5928 (tmp->type == XML_ENTITY_REF_NODE)) {
5929 format = 0;
5930 break;
5931 }
5932 tmp = tmp->next;
5933 }
5934 }
5935 xmlOutputBufferWriteString(buf, "<");
5936 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5937 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5938 xmlOutputBufferWriteString(buf, ":");
5939 }
5940
5941 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5942 if (cur->nsDef)
5943 xmlNsListDumpOutput(buf, cur->nsDef);
5944 if (cur->properties != NULL)
5945 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5946
5947 if ((cur->content == NULL) && (cur->children == NULL) &&
5948 (!xmlSaveNoEmptyTags)) {
5949 xmlOutputBufferWriteString(buf, "/>");
5950 return;
5951 }
5952 xmlOutputBufferWriteString(buf, ">");
5953 if (cur->content != NULL) {
5954 xmlChar *buffer;
5955
5956#ifndef XML_USE_BUFFER_CONTENT
5957 if (encoding == NULL)
5958 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5959 else
5960 buffer = xmlEncodeSpecialChars(doc, cur->content);
5961#else
5962 if (encoding == NULL)
5963 buffer = xmlEncodeEntitiesReentrant(doc,
5964 xmlBufferContent(cur->content));
5965 else
5966 buffer = xmlEncodeSpecialChars(doc,
5967 xmlBufferContent(cur->content));
5968#endif
5969 if (buffer != NULL) {
5970 xmlOutputBufferWriteString(buf, (const char *)buffer);
5971 xmlFree(buffer);
5972 }
5973 }
5974 if (cur->children != NULL) {
5975 if (format) xmlOutputBufferWriteString(buf, "\n");
5976 xmlNodeListDumpOutput(buf, doc, cur->children,
5977 (level >= 0?level+1:-1), format, encoding);
5978 if ((xmlIndentTreeOutput) && (format))
5979 for (i = 0;i < level;i++)
5980 xmlOutputBufferWriteString(buf, " ");
5981 }
5982 xmlOutputBufferWriteString(buf, "</");
5983 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5984 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5985 xmlOutputBufferWriteString(buf, ":");
5986 }
5987
5988 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5989 xmlOutputBufferWriteString(buf, ">");
5990}
5991
5992/**
5993 * xmlDocContentDumpOutput:
5994 * @buf: the XML buffer output
5995 * @cur: the document
5996 * @encoding: an optional encoding string
5997 * @format: should formatting spaces been added
5998 *
5999 * Dump an XML document.
6000 */
6001static void
6002xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6003 const char *encoding, int format) {
6004 xmlOutputBufferWriteString(buf, "<?xml version=");
6005 if (cur->version != NULL)
6006 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6007 else
6008 xmlOutputBufferWriteString(buf, "\"1.0\"");
6009 if (encoding == NULL) {
6010 if (cur->encoding != NULL)
6011 encoding = (const char *) cur->encoding;
6012 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6013 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6014 }
6015 if (encoding != NULL) {
6016 xmlOutputBufferWriteString(buf, " encoding=");
6017 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6018 }
6019 switch (cur->standalone) {
6020 case 0:
6021 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6022 break;
6023 case 1:
6024 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6025 break;
6026 }
6027 xmlOutputBufferWriteString(buf, "?>\n");
6028 if (cur->children != NULL) {
6029 xmlNodePtr child = cur->children;
6030
6031 while (child != NULL) {
6032 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6033 xmlOutputBufferWriteString(buf, "\n");
6034 child = child->next;
6035 }
6036 }
6037}
6038
6039/************************************************************************
6040 * *
6041 * Saving functions front-ends *
6042 * *
6043 ************************************************************************/
6044
6045/**
6046 * xmlDocDumpMemoryEnc:
6047 * @out_doc: Document to generate XML text from
6048 * @doc_txt_ptr: Memory pointer for allocated XML text
6049 * @doc_txt_len: Length of the generated XML text
6050 * @txt_encoding: Character encoding to use when generating XML text
6051 * @format: should formatting spaces been added
6052 *
6053 * Dump the current DOM tree into memory using the character encoding specified
6054 * by the caller. Note it is up to the caller of this function to free the
6055 * allocated memory.
6056 */
6057
6058void
6059xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006060 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006061 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006062 int dummy = 0;
6063
6064 xmlCharEncoding doc_charset;
6065 xmlOutputBufferPtr out_buff = NULL;
6066 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6067
6068 if (doc_txt_len == NULL) {
6069 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6070 }
6071
6072 if (doc_txt_ptr == NULL) {
6073 *doc_txt_len = 0;
6074 xmlGenericError(xmlGenericErrorContext,
6075 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6076 return;
6077 }
6078
6079 *doc_txt_ptr = NULL;
6080 *doc_txt_len = 0;
6081
6082 if (out_doc == NULL) {
6083 /* No document, no output */
6084 xmlGenericError(xmlGenericErrorContext,
6085 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6086 return;
6087 }
6088
6089 /*
6090 * Validate the encoding value, if provided.
6091 * This logic is copied from xmlSaveFileEnc.
6092 */
6093
6094 if (txt_encoding == NULL)
6095 txt_encoding = (const char *) out_doc->encoding;
6096 if (txt_encoding != NULL) {
6097 doc_charset = xmlParseCharEncoding(txt_encoding);
6098
6099 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6100 xmlGenericError(xmlGenericErrorContext,
6101 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6102 return;
6103
6104 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6105 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6106 if ( conv_hdlr == NULL ) {
6107 xmlGenericError(xmlGenericErrorContext,
6108 "%s: %s %s '%s'\n",
6109 "xmlDocDumpFormatMemoryEnc",
6110 "Failed to identify encoding handler for",
6111 "character set",
6112 txt_encoding);
6113 return;
6114 }
6115 }
6116 }
6117
6118 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6119 xmlGenericError(xmlGenericErrorContext,
6120 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6121 return;
6122 }
6123
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006124 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006125 xmlOutputBufferFlush(out_buff);
6126 if (out_buff->conv != NULL) {
6127 *doc_txt_len = out_buff->conv->use;
6128 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6129 } else {
6130 *doc_txt_len = out_buff->buffer->use;
6131 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6132 }
6133 (void)xmlOutputBufferClose(out_buff);
6134
6135 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6136 *doc_txt_len = 0;
6137 xmlGenericError(xmlGenericErrorContext,
6138 "xmlDocDumpFormatMemoryEnc: %s\n",
6139 "Failed to allocate memory for document text representation.");
6140 }
6141
6142 return;
6143}
6144
6145/**
6146 * xmlDocDumpMemory:
6147 * @cur: the document
6148 * @mem: OUT: the memory pointer
6149 * @size: OUT: the memory lenght
6150 *
6151 * Dump an XML document in memory and return the xmlChar * and it's size.
6152 * It's up to the caller to free the memory.
6153 */
6154void
6155xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6156 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6157}
6158
6159/**
6160 * xmlDocDumpFormatMemory:
6161 * @cur: the document
6162 * @mem: OUT: the memory pointer
6163 * @size: OUT: the memory lenght
6164 * @format: should formatting spaces been added
6165 *
6166 *
6167 * Dump an XML document in memory and return the xmlChar * and it's size.
6168 * It's up to the caller to free the memory.
6169 */
6170void
6171xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6172 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6173}
6174
6175/**
6176 * xmlDocDumpMemoryEnc:
6177 * @out_doc: Document to generate XML text from
6178 * @doc_txt_ptr: Memory pointer for allocated XML text
6179 * @doc_txt_len: Length of the generated XML text
6180 * @txt_encoding: Character encoding to use when generating XML text
6181 *
6182 * Dump the current DOM tree into memory using the character encoding specified
6183 * by the caller. Note it is up to the caller of this function to free the
6184 * allocated memory.
6185 */
6186
6187void
6188xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6189 int * doc_txt_len, const char * txt_encoding) {
6190 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006191 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006192}
6193
6194/**
6195 * xmlGetDocCompressMode:
6196 * @doc: the document
6197 *
6198 * get the compression ratio for a document, ZLIB based
6199 * Returns 0 (uncompressed) to 9 (max compression)
6200 */
6201int
6202xmlGetDocCompressMode (xmlDocPtr doc) {
6203 if (doc == NULL) return(-1);
6204 return(doc->compression);
6205}
6206
6207/**
6208 * xmlSetDocCompressMode:
6209 * @doc: the document
6210 * @mode: the compression ratio
6211 *
6212 * set the compression ratio for a document, ZLIB based
6213 * Correct values: 0 (uncompressed) to 9 (max compression)
6214 */
6215void
6216xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6217 if (doc == NULL) return;
6218 if (mode < 0) doc->compression = 0;
6219 else if (mode > 9) doc->compression = 9;
6220 else doc->compression = mode;
6221}
6222
6223/**
6224 * xmlGetCompressMode:
6225 *
6226 * get the default compression mode used, ZLIB based.
6227 * Returns 0 (uncompressed) to 9 (max compression)
6228 */
6229int
6230 xmlGetCompressMode(void) {
6231 return(xmlCompressMode);
6232}
6233
6234/**
6235 * xmlSetCompressMode:
6236 * @mode: the compression ratio
6237 *
6238 * set the default compression mode used, ZLIB based
6239 * Correct values: 0 (uncompressed) to 9 (max compression)
6240 */
6241void
6242xmlSetCompressMode(int mode) {
6243 if (mode < 0) xmlCompressMode = 0;
6244 else if (mode > 9) xmlCompressMode = 9;
6245 else xmlCompressMode = mode;
6246}
6247
6248/**
6249 * xmlDocDump:
6250 * @f: the FILE*
6251 * @cur: the document
6252 *
6253 * Dump an XML document to an open FILE.
6254 *
6255 * returns: the number of byte written or -1 in case of failure.
6256 */
6257int
6258xmlDocDump(FILE *f, xmlDocPtr cur) {
6259 xmlOutputBufferPtr buf;
6260 const char * encoding;
6261 xmlCharEncodingHandlerPtr handler = NULL;
6262 int ret;
6263
6264 if (cur == NULL) {
6265#ifdef DEBUG_TREE
6266 xmlGenericError(xmlGenericErrorContext,
6267 "xmlDocDump : document == NULL\n");
6268#endif
6269 return(-1);
6270 }
6271 encoding = (const char *) cur->encoding;
6272
6273 if (encoding != NULL) {
6274 xmlCharEncoding enc;
6275
6276 enc = xmlParseCharEncoding(encoding);
6277
6278 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6279 xmlGenericError(xmlGenericErrorContext,
6280 "xmlDocDump: document not in UTF8\n");
6281 return(-1);
6282 }
6283 if (enc != XML_CHAR_ENCODING_UTF8) {
6284 handler = xmlFindCharEncodingHandler(encoding);
6285 if (handler == NULL) {
6286 xmlFree((char *) cur->encoding);
6287 cur->encoding = NULL;
6288 }
6289 }
6290 }
6291 buf = xmlOutputBufferCreateFile(f, handler);
6292 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006293 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006294
6295 ret = xmlOutputBufferClose(buf);
6296 return(ret);
6297}
6298
6299/**
6300 * xmlSaveFileTo:
6301 * @buf: an output I/O buffer
6302 * @cur: the document
6303 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6304 *
6305 * Dump an XML document to an I/O buffer.
6306 *
6307 * returns: the number of byte written or -1 in case of failure.
6308 */
6309int
6310xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
6311 int ret;
6312
6313 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006314 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006315 ret = xmlOutputBufferClose(buf);
6316 return(ret);
6317}
6318
6319/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006320 * xmlSaveFormatFileTo:
6321 * @buf: an output I/O buffer
6322 * @cur: the document
6323 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6324 * @format: should formatting spaces been added
6325 *
6326 * Dump an XML document to an I/O buffer.
6327 *
6328 * returns: the number of byte written or -1 in case of failure.
6329 */
6330int
6331xmlSaveFormatFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding, int format) {
6332 int ret;
6333
6334 if (buf == NULL) return(0);
6335 xmlDocContentDumpOutput(buf, cur, encoding, format);
6336 ret = xmlOutputBufferClose(buf);
6337 return(ret);
6338}
6339
6340/**
Owen Taylor3473f882001-02-23 17:55:21 +00006341 * xmlSaveFileEnc:
6342 * @filename: the filename (or URL)
6343 * @cur: the document
6344 * @encoding: the name of an encoding (or NULL)
6345 *
6346 * Dump an XML document, converting it to the given encoding
6347 *
6348 * returns: the number of byte written or -1 in case of failure.
6349 */
6350int
6351xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6352 xmlOutputBufferPtr buf;
6353 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006354 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006355 int ret;
6356
6357 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006358
6359 enc = xmlParseCharEncoding(encoding);
6360 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6361 xmlGenericError(xmlGenericErrorContext,
6362 "xmlSaveFileEnc: document not in UTF8\n");
6363 return(-1);
6364 }
6365 if (enc != XML_CHAR_ENCODING_UTF8) {
6366 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006367 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006368 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006369 }
6370 }
6371
6372 /*
6373 * save the content to a temp buffer.
6374 */
6375 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
6376 if (buf == NULL) return(-1);
6377
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006378 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006379
6380 ret = xmlOutputBufferClose(buf);
6381 return(ret);
6382}
6383
6384/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006385 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006386 * @filename: the filename (or URL)
6387 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006388 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006389 *
6390 * Dump an XML document to a file. Will use compression if
6391 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillard67fee942001-04-26 18:59:03 +00006392 * used. If format is set then the document will be indented on output.
6393 *
Owen Taylor3473f882001-02-23 17:55:21 +00006394 * returns: the number of byte written or -1 in case of failure.
6395 */
6396int
Daniel Veillard67fee942001-04-26 18:59:03 +00006397xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006398 xmlOutputBufferPtr buf;
6399 const char *encoding;
6400 xmlCharEncodingHandlerPtr handler = NULL;
6401 int ret;
6402
6403 if (cur == NULL)
6404 return(-1);
6405 encoding = (const char *) cur->encoding;
6406
6407 /*
6408 * save the content to a temp buffer.
6409 */
6410#ifdef HAVE_ZLIB_H
6411 if (cur->compression < 0) cur->compression = xmlCompressMode;
6412#endif
6413 if (encoding != NULL) {
6414 xmlCharEncoding enc;
6415
6416 enc = xmlParseCharEncoding(encoding);
6417
6418 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6419 xmlGenericError(xmlGenericErrorContext,
6420 "xmlSaveFile: document not in UTF8\n");
6421 return(-1);
6422 }
6423 if (enc != XML_CHAR_ENCODING_UTF8) {
6424 handler = xmlFindCharEncodingHandler(encoding);
6425 if (handler == NULL) {
6426 xmlFree((char *) cur->encoding);
6427 cur->encoding = NULL;
6428 }
6429 }
6430 }
6431
6432 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
6433 if (buf == NULL) return(-1);
6434
Daniel Veillard67fee942001-04-26 18:59:03 +00006435 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006436
6437 ret = xmlOutputBufferClose(buf);
6438 return(ret);
6439}
6440
Daniel Veillard67fee942001-04-26 18:59:03 +00006441/**
6442 * xmlSaveFile:
6443 * @filename: the filename (or URL)
6444 * @cur: the document
6445 *
6446 * Dump an XML document to a file. Will use compression if
6447 * compiled in and enabled. If @filename is "-" the stdout file is
6448 * used.
6449 * returns: the number of byte written or -1 in case of failure.
6450 */
6451int
6452xmlSaveFile(const char *filename, xmlDocPtr cur) {
6453 return(xmlSaveFormatFile(filename, cur, 0));
6454}
6455