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