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