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