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