blob: 2719074d4ec6f6a2e26b1a200bcf64bb175886c0 [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * tree.c : implemetation of access function for an XML tree.
3 *
4 * See Copyright for the status of this software.
5 *
6 * $Id$
7 *
8 * TODO Cleanup the Dump mechanism.
9 */
10
Daniel Veillard151b1b01998-09-23 00:49:46 +000011#include "config.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000012#include <stdio.h>
13#include <ctype.h>
14#include <malloc.h>
15#include <string.h> /* for memset() only ! */
16
Daniel Veillard151b1b01998-09-23 00:49:46 +000017#ifdef HAVE_ZLIB_H
18#include <zlib.h>
19#endif
20
Daniel Veillard260a68f1998-08-13 03:39:55 +000021#include "tree.h"
22#include "entities.h"
23
24static CHAR xmlStringText[] = { 't', 'e', 'x', 't', 0 };
25int oldXMLWDcompatibility = 0;
26int xmlIndentTreeOutput = 1;
27
Daniel Veillard15a8df41998-09-24 19:15:06 +000028static int xmlCompressMode = 0;
29
Daniel Veillard260a68f1998-08-13 03:39:55 +000030/************************************************************************
31 * *
32 * Allocation and deallocation of basic structures *
33 * *
34 ************************************************************************/
35
36/*
37 * Upgrade old Namespace and move them to the root of the document.
38 */
39
40void xmlUpgradeOldNs(xmlDocPtr doc) {
41 xmlNsPtr cur;
42
43 if ((doc == NULL) || (doc->oldNs == NULL)) return;
44 if (doc->root == NULL) {
45 fprintf(stderr, "xmlUpgradeOldNs: failed no root !\n");
46 return;
47 }
48
49 cur = doc->oldNs;
50 while (cur->next != NULL) {
51 cur->type = XML_LOCAL_NAMESPACE;
52 cur = cur->next;
53 }
54 cur->type = XML_LOCAL_NAMESPACE;
55 cur->next = doc->root->nsDef;
56 doc->root->nsDef = doc->oldNs;
57 doc->oldNs = NULL;
58}
59
60/*
61 * Creation of a new Namespace.
62 */
63xmlNsPtr xmlNewNs(xmlNodePtr node, const CHAR *href, const CHAR *prefix) {
64 xmlNsPtr cur;
65
66 if (href == NULL) {
67 fprintf(stderr, "xmlNewNs: href == NULL !\n");
68 return(NULL);
69 }
70
71 /*
72 * Allocate a new DTD and fill the fields.
73 */
74 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
75 if (cur == NULL) {
76 fprintf(stderr, "xmlNewNs : malloc failed\n");
77 return(NULL);
78 }
79
80 cur->type = XML_LOCAL_NAMESPACE;
81 if (href != NULL)
82 cur->href = xmlStrdup(href);
83 else
84 cur->href = NULL;
85 if (prefix != NULL)
86 cur->prefix = xmlStrdup(prefix);
87 else
88 cur->prefix = NULL;
89
90 /*
91 * Add it at the end to preserve parsing order ...
92 */
93 cur->next = NULL;
94 if (node != NULL) {
95 if (node->nsDef == NULL) {
96 node->nsDef = cur;
97 } else {
98 xmlNsPtr prev = node->nsDef;
99
100 while (prev->next != NULL) prev = prev->next;
101 prev->next = cur;
102 }
103 }
104
105 return(cur);
106}
107
108/*
109 * Creation of a new global namespace (the old way ...).
110 */
111xmlNsPtr xmlNewGlobalNs(xmlDocPtr doc, const CHAR *href, const CHAR *prefix) {
112 xmlNsPtr cur;
113
114 /*
115 * Allocate a new DTD and fill the fields.
116 */
117 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
118 if (cur == NULL) {
119 fprintf(stderr, "xmlNewNs : malloc failed\n");
120 return(NULL);
121 }
122
123 cur->type = XML_GLOBAL_NAMESPACE;
124 if (href != NULL)
125 cur->href = xmlStrdup(href);
126 else
127 cur->href = NULL;
128 if (prefix != NULL)
129 cur->prefix = xmlStrdup(prefix);
130 else
131 cur->prefix = NULL;
132
133 /*
134 * Add it at the end to preserve parsing order ...
135 */
136 cur->next = NULL;
137 if (doc != NULL) {
138 if (doc->oldNs == NULL) {
139 doc->oldNs = cur;
140 } else {
141 xmlNsPtr prev = doc->oldNs;
142
143 while (prev->next != NULL) prev = prev->next;
144 prev->next = cur;
145 }
146 }
147
148 return(cur);
149}
150
151/*
152 * Set the node namespace a posteriori
153 */
154void xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
155 if (node == NULL) {
156 fprintf(stderr, "xmlSetNs: node == NULL\n");
157 return;
158 }
159 node->ns = ns;
160}
161
162/*
163 * Freeing a Namespace
164 */
165void xmlFreeNs(xmlNsPtr cur) {
166 if (cur == NULL) {
167 fprintf(stderr, "xmlFreeNs : ns == NULL\n");
168 return;
169 }
170 if (cur->href != NULL) free((char *) cur->href);
171 if (cur->prefix != NULL) free((char *) cur->prefix);
172 memset(cur, -1, sizeof(xmlNs));
173 free(cur);
174}
175
176/*
177 * Freeing a Namespace list
178 */
179void xmlFreeNsList(xmlNsPtr cur) {
180 xmlNsPtr next;
181 if (cur == NULL) {
182 fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
183 return;
184 }
185 while (cur != NULL) {
186 next = cur->next;
187 xmlFreeNs(cur);
188 cur = next;
189 }
190}
191
192/*
193 * Creation of a new DTD.
194 */
195xmlDtdPtr xmlNewDtd(xmlDocPtr doc, const CHAR *name,
196 const CHAR *ExternalID, const CHAR *SystemID) {
197 xmlDtdPtr cur;
198
199 if (doc->dtd != NULL) {
200 fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
201 /* !!! */ (char *) name, doc->name, /* !!! */ (char *)doc->dtd->name);
202 }
203
204 /*
205 * Allocate a new DTD and fill the fields.
206 */
207 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
208 if (cur == NULL) {
209 fprintf(stderr, "xmlNewNs : malloc failed\n");
210 return(NULL);
211 }
212
213 if (name != NULL)
214 cur->name = xmlStrdup(name);
215 else
216 cur->name = NULL;
217 if (ExternalID != NULL)
218 cur->ExternalID = xmlStrdup(ExternalID);
219 else
220 cur->ExternalID = NULL;
221 if (SystemID != NULL)
222 cur->SystemID = xmlStrdup(SystemID);
223 else
224 cur->SystemID = NULL;
225 cur->elements = NULL;
226 cur->entities = NULL;
227 doc->dtd = cur;
228
229 return(cur);
230}
231
232/*
233 * Freeing a DTD
234 */
235void xmlFreeDtd(xmlDtdPtr cur) {
236 if (cur == NULL) {
237 fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
238 return;
239 }
240 if (cur->name != NULL) free((char *) cur->name);
241 if (cur->SystemID != NULL) free((char *) cur->SystemID);
242 if (cur->ExternalID != NULL) free((char *) cur->ExternalID);
243 if (cur->elements != NULL)
244 fprintf(stderr, "xmlFreeDtd: cur->elements != NULL !!! \n");
245 if (cur->entities != NULL)
246 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
247 memset(cur, -1, sizeof(xmlDtd));
248 free(cur);
249}
250
251/*
252 * Creation of a new document
253 */
254xmlDocPtr xmlNewDoc(const CHAR *version) {
255 xmlDocPtr cur;
256
257 if (version == NULL) {
258 fprintf(stderr, "xmlNewDoc : version == NULL\n");
259 return(NULL);
260 }
261
262 /*
263 * Allocate a new document and fill the fields.
264 */
265 cur = (xmlDocPtr) malloc(sizeof(xmlDoc));
266 if (cur == NULL) {
267 fprintf(stderr, "xmlNewDoc : malloc failed\n");
268 return(NULL);
269 }
270
271 cur->version = xmlStrdup(version);
272 cur->name = NULL;
273 cur->root = NULL;
274 cur->dtd = NULL;
275 cur->oldNs = NULL;
276 cur->encoding = NULL;
277 cur->entities = NULL;
278 cur->standalone = -1;
Daniel Veillard15a8df41998-09-24 19:15:06 +0000279 cur->compression = xmlCompressMode;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000280 return(cur);
281}
282
283/*
284 * Freeing a document : all the tree is freed too.
285 */
286void xmlFreeDoc(xmlDocPtr cur) {
287 if (cur == NULL) {
288 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
289 return;
290 }
291 free((char *) cur->version);
292 if (cur->name != NULL) free((char *) cur->name);
293 if (cur->encoding != NULL) free((char *) cur->encoding);
294 if (cur->root != NULL) xmlFreeNode(cur->root);
295 if (cur->dtd != NULL) xmlFreeDtd(cur->dtd);
296 if (cur->entities != NULL)
297 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
298 memset(cur, -1, sizeof(xmlDoc));
299 free(cur);
300}
301
302/*
303 * Creation of a new property of a node.
304 */
305xmlAttrPtr xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
306 xmlAttrPtr cur;
307
308 if (name == NULL) {
309 fprintf(stderr, "xmlNewProp : name == NULL\n");
310 return(NULL);
311 }
312
313 /*
314 * Allocate a new property and fill the fields.
315 */
316 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
317 if (cur == NULL) {
318 fprintf(stderr, "xmlNewProp : malloc failed\n");
319 return(NULL);
320 }
321
322 cur->node = node;
323 cur->name = xmlStrdup(name);
324 if (value != NULL)
325 cur->value = xmlStrdup(value);
326 else
327 cur->value = NULL;
328
329 /*
330 * Add it at the end to preserve parsing order ...
331 */
332 cur->next = NULL;
333 if (node != NULL) {
334 if (node->properties == NULL) {
335 node->properties = cur;
336 } else {
337 xmlAttrPtr prev = node->properties;
338
339 while (prev->next != NULL) prev = prev->next;
340 prev->next = cur;
341 }
342 }
343 return(cur);
344}
345
346/*
347 * Freeing a property list : Free a property and all its siblings,
348 * this is a recursive behaviour, all the childs
349 * are freed too.
350 */
351void xmlFreePropList(xmlAttrPtr cur) {
352 xmlAttrPtr next;
353 if (cur == NULL) {
354 fprintf(stderr, "xmlFreePropList : property == NULL\n");
355 return;
356 }
357 while (cur != NULL) {
358 next = cur->next;
359 xmlFreeProp(cur);
360 cur = next;
361 }
362}
363
364/*
365 * Freeing a property.
366 */
367void xmlFreeProp(xmlAttrPtr cur) {
368 if (cur == NULL) {
369 fprintf(stderr, "xmlFreeProp : property == NULL\n");
370 return;
371 }
372 if (cur->name != NULL) free((char *) cur->name);
373 if (cur->value != NULL) free((char *) cur->value);
374 memset(cur, -1, sizeof(xmlAttr));
375 free(cur);
376}
377
378/*
379 * Creation of a new node element in a given DTD.
380 * We assume that the "name" has already being strdup'd !
381 */
382xmlNodePtr xmlNewNode(xmlNsPtr ns, const CHAR *name, CHAR *content) {
383 xmlNodePtr cur;
384
385 if (name == NULL) {
386 fprintf(stderr, "xmlNewNode : name == NULL\n");
387 return(NULL);
388 }
389
390 /*
391 * Allocate a new node and fill the fields.
392 */
393 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
394 if (cur == NULL) {
395 fprintf(stderr, "xmlNewNode : malloc failed\n");
396 return(NULL);
397 }
398
399 cur->parent = NULL;
400 cur->next = NULL;
401 cur->childs = NULL;
402 cur->properties = NULL;
403 cur->type = 0;
404 cur->name = xmlStrdup(name);
405 cur->ns = ns;
406 cur->nsDef = NULL;
407 if (content != NULL)
408 cur->content = xmlStrdup(content);
409 else
410 cur->content = NULL;
411 return(cur);
412}
413
414/*
415 * Creation of a new node contening text.
416 */
417xmlNodePtr xmlNewText(const CHAR *content) {
418 xmlNodePtr cur;
419
420 /*
421 * Allocate a new node and fill the fields.
422 */
423 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
424 if (cur == NULL) {
425 fprintf(stderr, "xmlNewText : malloc failed\n");
426 return(NULL);
427 }
428
429 cur->parent = NULL;
430 cur->next = NULL;
431 cur->childs = NULL;
432 cur->properties = NULL;
433 cur->type = XML_TYPE_TEXT;
434 cur->name = xmlStrdup(xmlStringText);
435 cur->ns = NULL;
436 cur->nsDef = NULL;
437 if (content != NULL)
438 cur->content = xmlStrdup(content);
439 else
440 cur->content = NULL;
441 return(cur);
442}
443
444/*
445 * Creation of a new node contening text.
446 */
447xmlNodePtr xmlNewTextLen(const CHAR *content, int len) {
448 xmlNodePtr cur;
449
450 /*
451 * Allocate a new node and fill the fields.
452 */
453 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
454 if (cur == NULL) {
455 fprintf(stderr, "xmlNewText : malloc failed\n");
456 return(NULL);
457 }
458
459 cur->parent = NULL;
460 cur->next = NULL;
461 cur->childs = NULL;
462 cur->properties = NULL;
463 cur->type = XML_TYPE_TEXT;
464 cur->name = xmlStrdup(xmlStringText);
465 cur->ns = NULL;
466 cur->nsDef = NULL;
467 if (content != NULL)
468 cur->content = xmlStrndup(content, len);
469 else
470 cur->content = NULL;
471 return(cur);
472}
473
474/*
475 * Creation of a new node contening a comment.
476 */
477xmlNodePtr xmlNewComment(CHAR *content) {
478 xmlNodePtr cur;
479
480 /*
481 * Allocate a new node and fill the fields.
482 */
483 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
484 if (cur == NULL) {
485 fprintf(stderr, "xmlNewComment : malloc failed\n");
486 return(NULL);
487 }
488
489 cur->parent = NULL;
490 cur->next = NULL;
491 cur->childs = NULL;
492 cur->properties = NULL;
493 cur->type = XML_TYPE_COMMENT;
494 cur->name = xmlStrdup(xmlStringText);
495 cur->ns = NULL;
496 cur->nsDef = NULL;
497 if (content != NULL)
498 cur->content = xmlStrdup(content);
499 else
500 cur->content = NULL;
501 return(cur);
502}
503
504/*
505 * Creation of a new child element, added at the end.
506 */
507xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
508 const CHAR *name, CHAR *content) {
509 xmlNodePtr cur, prev;
510
511 if (parent == NULL) {
512 fprintf(stderr, "xmlNewChild : parent == NULL\n");
513 return(NULL);
514 }
515
516 if (name == NULL) {
517 fprintf(stderr, "xmlNewChild : name == NULL\n");
518 return(NULL);
519 }
520
521 /*
522 * Allocate a new node
523 */
524 if (ns == NULL)
525 cur = xmlNewNode(parent->ns, name, content);
526 else
527 cur = xmlNewNode(ns, name, content);
528 if (cur == NULL) return(NULL);
529
530 /*
531 * add the new element at the end of the childs list.
532 */
533 cur->parent = parent;
534 if (parent->childs == NULL) {
535 parent->childs = cur;
536 } else {
537 prev = parent->childs;
538 while (prev->next != NULL) prev = prev->next;
539 prev->next = cur;
540 }
541
542 return(cur);
543}
544
545/*
546 * Add a new child element, added at the end.
547 */
548xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
549 xmlNodePtr prev;
550
551 if (parent == NULL) {
552 fprintf(stderr, "xmladdChild : parent == NULL\n");
553 return(NULL);
554 }
555
556 if (cur == NULL) {
557 fprintf(stderr, "xmladdChild : child == NULL\n");
558 return(NULL);
559 }
560
561 /*
562 * add the new element at the end of the childs list.
563 */
564 cur->parent = parent;
565 if (parent->childs == NULL) {
566 parent->childs = cur;
567 } else {
568 prev = parent->childs;
569 while (prev->next != NULL) prev = prev->next;
570 prev->next = cur;
571 }
572
573 return(cur);
574}
575
576/*
577 * Search the last child, if any.
578 */
579xmlNodePtr xmlGetLastChild(xmlNodePtr parent) {
580 xmlNodePtr last;
581
582 if (parent == NULL) {
583 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
584 return(NULL);
585 }
586
587 /*
588 * add the new element at the end of the childs list.
589 */
590 if (parent->childs == NULL) {
591 return(NULL);
592 } else {
593 last = parent->childs;
594 while (last->next != NULL) last = last->next;
595 }
596 return(last);
597}
598
599/*
600 * Freeing a node list : Free a node and all its siblings,
601 * this is a recursive behaviour, all the childs
602 * are freed too.
603 */
604void xmlFreeNodeList(xmlNodePtr cur) {
605 xmlNodePtr next;
606 if (cur == NULL) {
607 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
608 return;
609 }
610 while (cur != NULL) {
611 next = cur->next;
612 xmlFreeNode(cur);
613 cur = next;
614 }
615}
616
617/*
618 * Freeing a node : this is a recursive behaviour, all the childs
619 * are freed too.
620 */
621void xmlFreeNode(xmlNodePtr cur) {
622 if (cur == NULL) {
623 fprintf(stderr, "xmlFreeNode : node == NULL\n");
624 return;
625 }
626 if (cur->properties != NULL) xmlFreePropList(cur->properties);
627 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
628 if (cur->content != NULL) free(cur->content);
629 if (cur->name != NULL) free((char *) cur->name);
630 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
631 memset(cur, -1, sizeof(xmlNode));
632 free(cur);
633}
634
635/************************************************************************
636 * *
637 * Content access functions *
638 * *
639 ************************************************************************/
640
641/*
642 * Changing the content of a node.
643 */
644void xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
645 if (cur == NULL) {
646 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
647 return;
648 }
649 if (cur->content != NULL) free(cur->content);
650 if (content != NULL)
651 cur->content = xmlStrdup(content);
652 else
653 cur->content = NULL;
654}
655
656/*
657 * Changing the content of a node.
658 */
659void xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
660 if (cur == NULL) {
661 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
662 return;
663 }
664 if (cur->content != NULL) free(cur->content);
665 if (content != NULL)
666 cur->content = xmlStrndup(content, len);
667 else
668 cur->content = NULL;
669}
670
671/*
672 * Adding content to a node.
673 */
674void xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
675 if (cur == NULL) {
676 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
677 return;
678 }
679 cur->content = xmlStrcat(cur->content, content);
680}
681
682/*
683 * Adding content to a node.
684 */
685void xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
686 if (cur == NULL) {
687 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
688 return;
689 }
690 cur->content = xmlStrncat(cur->content, content, len);
691}
692
693/*
694 * Search a Ns registered under a given name space for a document.
695 * recurse on the parents until it finds the defined namespace
696 * or return NULL otherwise.
697 *
698 * Note : nameSpace == NULL is valid, this is a search for the default
699 * namespace.
700 */
701xmlNsPtr xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
702 xmlNsPtr cur;
703
704 while (node != NULL) {
705 cur = node->nsDef;
706 while (cur != NULL) {
707 if ((cur->prefix == NULL) && (nameSpace == NULL))
708 return(cur);
709 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
710 (!xmlStrcmp(cur->prefix, nameSpace)))
711 return(cur);
712 cur = cur->next;
713 }
714 node = node->parent;
715 }
716 if (doc != NULL) {
717 cur = doc->oldNs;
718 while (cur != NULL) {
719 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
720 (!xmlStrcmp(cur->prefix, nameSpace)))
721 return(cur);
722 cur = cur->next;
723 }
724 }
725 return(NULL);
726}
727
728/*
729 * Search a Ns aliasing a given URI
730 * recurse on the parents until it finds the defined namespace
731 * or return NULL otherwise.
732 */
733xmlNsPtr xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
734 xmlNsPtr cur;
735
736 while (node != NULL) {
737 cur = node->nsDef;
738 while (cur != NULL) {
739 if ((cur->href != NULL) && (href != NULL) &&
740 (!xmlStrcmp(cur->href, href)))
741 return(cur);
742 cur = cur->next;
743 }
744 node = node->parent;
745 }
746 if (doc != NULL) {
747 cur = doc->oldNs;
748 while (cur != NULL) {
749 if ((cur->href != NULL) && (href != NULL) &&
750 (!xmlStrcmp(cur->href, href)))
751 return(cur);
752 cur = cur->next;
753 }
754 }
755 return(NULL);
756}
757
758/*
759 * Reading the content of a given property.
760 */
761const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
762 xmlAttrPtr prop = node->properties;
763
764 while (prop != NULL) {
765 if (!xmlStrcmp(prop->name, name)) return(prop->value);
766 prop = prop->next;
767 }
768 return(NULL);
769}
770
771/*
772 * Setting the content of a given property.
773 */
774xmlAttrPtr xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
775 xmlAttrPtr prop = node->properties;
776
777 while (prop != NULL) {
778 if (!xmlStrcmp(prop->name, name)) {
779 if (prop->value != NULL)
780 free((char *) prop->value);
781 prop->value = NULL;
782 if (value != NULL)
783 prop->value = xmlStrdup(value);
784 return(prop);
785 }
786 prop = prop->next;
787 }
788 prop = xmlNewProp(node, name, value);
789 return(prop);
790}
791
792/*
793 * Is this node a piece of text
794 */
795int xmlNodeIsText(xmlNodePtr node) {
796 if (node == NULL) return(0);
797
798 if (node->type == XML_TYPE_TEXT) return(1);
799 return(0);
800}
801
802/*
803 * Concat a piece of text to an existing text node
804 *
805 * TODO !!! Should be optimized with a bit of preallocation.
806 */
807void xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
808 if (node == NULL) return;
809
810 if (node->type != XML_TYPE_TEXT) {
811 fprintf(stderr, "xmlTextConcat: node is not text\n");
812 return;
813 }
814 node->content = xmlStrncat(node->content, content, len);
815}
816
817/************************************************************************
818 * *
819 * Output : to a FILE or in memory *
820 * *
821 ************************************************************************/
822
823/*
824 * routine which manage and grows an output buffer. One can write
825 * standard char array's (8 bits char) or CHAR's arrays.
826 */
827static CHAR *buffer = NULL;
828static int buffer_index = 0;
829static int buffer_size = 0;
830
831void xmlBufferWriteCHAR(const CHAR *string) {
832 const CHAR *cur;
833
834 if (buffer == NULL) {
835 buffer_size = 50000;
836 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
837 if (buffer == NULL) {
838 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
839 exit(1);
840 }
841 }
842
843 if (string == NULL) return;
844 for (cur = string;*cur != 0;cur++) {
845 if (buffer_index + 10 >= buffer_size) {
846 buffer_size *= 2;
847 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
848 if (buffer == NULL) {
849 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
850 exit(1);
851 }
852 }
853 buffer[buffer_index++] = *cur;
854 }
855 buffer[buffer_index] = 0;
856}
857
858void xmlBufferWriteChar(const char *string) {
859 const char *cur;
860
861 if (buffer == NULL) {
862 buffer_size = 50000;
863 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
864 if (buffer == NULL) {
865 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
866 exit(1);
867 }
868 }
869
870 if (string == NULL) return;
871 for (cur = string;*cur != 0;cur++) {
872 if (buffer_index + 10 >= buffer_size) {
873 buffer_size *= 2;
874 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
875 if (buffer == NULL) {
876 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
877 exit(1);
878 }
879 }
880 buffer[buffer_index++] = *cur;
881 }
882 buffer[buffer_index] = 0;
883}
884
885/*
886 * Dump the global Namespace inherited from the old WD.
887 * Within the context of the document header.
888 */
889static void xmlGlobalNsDump(xmlNsPtr cur) {
890 if (cur == NULL) {
891 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
892 return;
893 }
894 if (cur->type == XML_GLOBAL_NAMESPACE) {
895 xmlBufferWriteChar("<?namespace");
896 if (cur->href != NULL) {
897 xmlBufferWriteChar(" href=\"");
898 xmlBufferWriteCHAR(cur->href);
899 xmlBufferWriteChar("\"");
900 }
901 if (cur->prefix != NULL) {
902 xmlBufferWriteChar(" AS=\"");
903 xmlBufferWriteCHAR(cur->prefix);
904 xmlBufferWriteChar("\"");
905 }
906 xmlBufferWriteChar("?>\n");
907 }
908}
909
910/*
911 * Dump an old global XML Namespace list
912 */
913
914static void xmlGlobalNsListDump(xmlNsPtr cur) {
915 while (cur != NULL) {
916 xmlGlobalNsDump(cur);
917 cur = cur->next;
918 }
919}
920
921/*
922 * Dump a local Namespace definition.
923 * Within the context of an element attributes.
924 */
925static void xmlNsDump(xmlNsPtr cur) {
926 if (cur == NULL) {
927 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
928 return;
929 }
930 if (cur->type == XML_LOCAL_NAMESPACE) {
931 /* Within the context of an element attributes */
932 if (cur->prefix != NULL) {
933 xmlBufferWriteChar(" xmlns:");
934 xmlBufferWriteCHAR(cur->prefix);
935 } else
936 xmlBufferWriteChar(" xmlns");
937 xmlBufferWriteChar("=\"");
938 xmlBufferWriteCHAR(cur->href);
939 xmlBufferWriteChar("\"");
940 }
941}
942
943/*
944 * Dump an XML Namespace list
945 */
946
947static void xmlNsListDump(xmlNsPtr cur) {
948 while (cur != NULL) {
949 xmlNsDump(cur);
950 cur = cur->next;
951 }
952}
953
954/*
955 * Dump an XML DTD
956 */
957
958static void xmlDtdDump(xmlDocPtr doc) {
959 xmlDtdPtr cur = doc->dtd;
960
961 if (cur == NULL) {
962 fprintf(stderr, "xmlDtdDump : DTD == NULL\n");
963 return;
964 }
965 xmlBufferWriteChar("<!DOCTYPE ");
966 xmlBufferWriteCHAR(cur->name);
967 if (cur->ExternalID != NULL) {
968 xmlBufferWriteChar(" PUBLIC \"");
969 xmlBufferWriteCHAR(cur->ExternalID);
970 xmlBufferWriteChar("\" \"");
971 xmlBufferWriteCHAR(cur->SystemID);
972 xmlBufferWriteChar("\"");
973 } else if (cur->SystemID != NULL) {
974 xmlBufferWriteChar(" SYSTEM \"");
975 xmlBufferWriteCHAR(cur->SystemID);
976 xmlBufferWriteChar("\"");
977 }
978 if ((cur->entities == NULL) && (doc->entities == NULL)) {
979 xmlBufferWriteChar(">\n");
980 return;
981 }
982 xmlBufferWriteChar(" [\n");
983 if (cur->entities != NULL)
984 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
985 if (doc->entities != NULL)
986 xmlDumpEntitiesTable((xmlEntitiesTablePtr) doc->entities);
987 xmlBufferWriteChar("]");
988
989 /* TODO !!! a lot more things to dump ... */
990 xmlBufferWriteChar(">\n");
991}
992
993/*
994 * Dump an XML property
995 */
996
997static void xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
998 if (cur == NULL) {
999 fprintf(stderr, "xmlAttrDump : property == NULL\n");
1000 return;
1001 }
1002 xmlBufferWriteChar(" ");
1003 xmlBufferWriteCHAR(cur->name);
1004 if (cur->value) {
1005 xmlBufferWriteChar("=\"");
1006 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->value));
1007 xmlBufferWriteChar("\"");
1008 }
1009}
1010
1011/*
1012 * Dump an XML property list
1013 */
1014
1015static void xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
1016 if (cur == NULL) {
1017 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
1018 return;
1019 }
1020 while (cur != NULL) {
1021 xmlAttrDump(doc, cur);
1022 cur = cur->next;
1023 }
1024}
1025
1026/*
1027 * Dump an XML node list
1028 */
1029
1030static void xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
1031static void xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1032 if (cur == NULL) {
1033 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
1034 return;
1035 }
1036 while (cur != NULL) {
1037 xmlNodeDump(doc, cur, level);
1038 cur = cur->next;
1039 }
1040}
1041
1042/*
1043 * Dump an XML node
1044 */
1045
1046static void xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1047 int i;
1048
1049 if (cur == NULL) {
1050 fprintf(stderr, "xmlNodeDump : node == NULL\n");
1051 return;
1052 }
1053 if (cur->type == XML_TYPE_TEXT) {
1054 if (cur->content != NULL)
1055 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1056 return;
1057 }
1058 if (cur->type == XML_TYPE_COMMENT) {
1059 if (cur->content != NULL) {
1060 xmlBufferWriteChar("<!--");
1061 xmlBufferWriteCHAR(cur->content);
1062 xmlBufferWriteChar("-->");
1063 }
1064 return;
1065 }
1066 if (xmlIndentTreeOutput)
1067 for (i = 0;i < level;i++)
1068 xmlBufferWriteChar(" ");
1069
1070 xmlBufferWriteChar("<");
1071 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1072 xmlBufferWriteCHAR(cur->ns->prefix);
1073 xmlBufferWriteChar(":");
1074 }
1075
1076 xmlBufferWriteCHAR(cur->name);
1077 if (cur->nsDef)
1078 xmlNsListDump(cur->nsDef);
1079 if (cur->properties != NULL)
1080 xmlAttrListDump(doc, cur->properties);
1081
1082 if ((cur->content == NULL) && (cur->childs == NULL)) {
1083 xmlBufferWriteChar("/>\n");
1084 return;
1085 }
1086 xmlBufferWriteChar(">");
1087 if (cur->content != NULL)
1088 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1089 if (cur->childs != NULL) {
1090 xmlBufferWriteChar("\n");
1091 xmlNodeListDump(doc, cur->childs, level + 1);
1092 if (xmlIndentTreeOutput)
1093 for (i = 0;i < level;i++)
1094 xmlBufferWriteChar(" ");
1095 }
1096 xmlBufferWriteChar("</");
1097 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1098 xmlBufferWriteCHAR(cur->ns->prefix);
1099 xmlBufferWriteChar(":");
1100 }
1101
1102 xmlBufferWriteCHAR(cur->name);
1103 xmlBufferWriteChar(">\n");
1104}
1105
1106/*
1107 * Dump an XML document
1108 */
1109static void xmlDocContentDump(xmlDocPtr cur) {
1110 if (oldXMLWDcompatibility)
1111 xmlBufferWriteChar("<?XML version=\"");
1112 else
1113 xmlBufferWriteChar("<?xml version=\"");
1114 xmlBufferWriteCHAR(cur->version);
1115 xmlBufferWriteChar("\"");
1116 if (cur->encoding != NULL) {
1117 xmlBufferWriteChar(" encoding=\"");
1118 xmlBufferWriteCHAR(cur->encoding);
1119 xmlBufferWriteChar("\"");
1120 }
1121 switch (cur->standalone) {
1122 case 0:
1123 xmlBufferWriteChar(" standalone=\"no\"");
1124 break;
1125 case 1:
1126 xmlBufferWriteChar(" standalone=\"yes\"");
1127 break;
1128 }
1129 xmlBufferWriteChar("?>\n");
1130 if ((cur->dtd != NULL) || (cur->entities != NULL))
1131 xmlDtdDump(cur);
1132 if (cur->root != NULL) {
1133 /* global namespace definitions, the old way */
1134 if (oldXMLWDcompatibility)
1135 xmlGlobalNsListDump(cur->oldNs);
1136 else
1137 xmlUpgradeOldNs(cur);
1138 xmlNodeDump(cur, cur->root, 0);
1139 }
1140}
1141
1142/*
1143 * Dump an XML document to memory.
1144 */
1145
1146void xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
1147 if (cur == NULL) {
1148 fprintf(stderr, "xmlDocDump : document == NULL\n");
1149 *mem = NULL;
1150 *size = 0;
1151 return;
1152 }
1153 buffer_index = 0;
1154 xmlDocContentDump(cur);
1155
1156 *mem = buffer;
1157 *size = buffer_index;
1158}
1159
1160/*
Daniel Veillard15a8df41998-09-24 19:15:06 +00001161 * Get/Set a document compression mode.
Daniel Veillard151b1b01998-09-23 00:49:46 +00001162 */
1163
Daniel Veillard15a8df41998-09-24 19:15:06 +00001164int xmlGetDocCompressMode (xmlDocPtr doc) {
1165 if (doc == NULL) return(-1);
1166 return(doc->compression);
1167}
1168
1169void xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
1170 if (doc == NULL) return;
1171 if (mode < 0) doc->compression = 0;
1172 else if (mode > 9) doc->compression = 9;
1173 else doc->compression = mode;
1174}
1175
1176/*
1177 * Get/Set the global compression mode
1178 */
Daniel Veillard151b1b01998-09-23 00:49:46 +00001179
1180int xmlGetCompressMode(void) {
1181 return(xmlCompressMode);
1182}
1183void xmlSetCompressMode(int mode) {
1184 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00001185 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00001186 else xmlCompressMode = mode;
1187}
1188
1189/*
Daniel Veillard260a68f1998-08-13 03:39:55 +00001190 * Dump an XML document to the given FD
1191 */
1192
1193void xmlDocDump(FILE *f, xmlDocPtr cur) {
1194 if (cur == NULL) {
1195 fprintf(stderr, "xmlDocDump : document == NULL\n");
1196 return;
1197 }
1198 buffer_index = 0;
1199 xmlDocContentDump(cur);
1200
1201 fwrite(buffer, sizeof(CHAR), buffer_index, f);
1202}
1203
Daniel Veillard151b1b01998-09-23 00:49:46 +00001204/*
1205 * Dump an XML document to a file.
1206 */
1207
1208int xmlSaveFile(const char *filename, xmlDocPtr cur) {
1209#ifdef HAVE_ZLIB_H
1210 gzFile zoutput = NULL;
1211 char mode[15];
1212#endif
1213 FILE *output;
1214 int ret;
1215
1216#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00001217 if ((cur->compression > 0) && (cur->compression <= 9)) {
1218 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00001219 zoutput = gzopen(filename, mode);
1220 }
1221 if (zoutput == NULL) {
1222#endif
1223 output = fopen(filename, "w");
1224 if (output == NULL) return(-1);
1225#ifdef HAVE_ZLIB_H
1226 }
1227#endif
1228
1229 /*
1230 * save the content to a temp buffer.
1231 */
1232 buffer_index = 0;
1233 xmlDocContentDump(cur);
1234
1235#ifdef HAVE_ZLIB_H
1236 if (zoutput != NULL) {
1237 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
1238 gzclose(zoutput);
1239 return(ret);
1240 }
1241#endif
1242 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
1243 fclose(output);
1244 return(ret * sizeof(CHAR));
1245}
1246
Daniel Veillard260a68f1998-08-13 03:39:55 +00001247/************************************************************************
1248 * *
1249 * Debug *
1250 * *
1251 ************************************************************************/
1252
1253#ifdef STANDALONE
1254int main(void) {
1255 xmlDocPtr doc;
1256 xmlNodePtr tree, subtree;
1257 xmlNsPtr ns1;
1258 xmlNsPtr ns2;
1259
1260 /*
1261 * build a fake XML document
1262 */
1263 doc = xmlNewDoc("1.0");
1264 ns1 = xmlNewNs(doc, "http://www.ietf.org/standards/dav/", "D");
1265 ns2 = xmlNewNs(doc, "http://www.w3.com/standards/z39.50/", "Z");
1266 doc->root = xmlNewNode(ns1, "multistatus", NULL);
1267 tree = xmlNewChild(doc->root, NULL, "response", NULL);
1268 subtree = xmlNewChild(tree, NULL, "prop", NULL);
1269 xmlNewChild(subtree, ns2, "Authors", NULL);
1270 subtree = xmlNewChild(tree, NULL, "status", "HTTP/1.1 420 Method Failure");
1271 tree = xmlNewChild(doc->root, NULL, "response", NULL);
1272 subtree = xmlNewChild(tree, NULL, "prop", NULL);
1273 xmlNewChild(subtree, ns2, "Copyright-Owner", NULL);
1274 subtree = xmlNewChild(tree, NULL, "status", "HTTP/1.1 409 Conflict");
1275 tree = xmlNewChild(doc->root, NULL, "responsedescription",
1276 "Copyright Owner can not be deleted or altered");
1277
1278 /*
1279 * print it.
1280 */
1281 xmlDocDump(stdout, doc);
1282
1283 /*
1284 * free it.
1285 */
1286 xmlFreeDoc(doc);
1287 return(0);
1288}
1289#endif