blob: b2d67e44780c96490f185eb2d743bc9fa66a7fd7 [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>
Seth Alvese7f12e61998-10-01 20:51:15 +000014#include <stdlib.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000015#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 Veillard27864701998-10-08 03:47:24 +0000280 cur->servant = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000281 return(cur);
282}
283
284/*
285 * Freeing a document : all the tree is freed too.
286 */
287void xmlFreeDoc(xmlDocPtr cur) {
288 if (cur == NULL) {
289 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
290 return;
291 }
292 free((char *) cur->version);
293 if (cur->name != NULL) free((char *) cur->name);
294 if (cur->encoding != NULL) free((char *) cur->encoding);
295 if (cur->root != NULL) xmlFreeNode(cur->root);
296 if (cur->dtd != NULL) xmlFreeDtd(cur->dtd);
297 if (cur->entities != NULL)
298 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
299 memset(cur, -1, sizeof(xmlDoc));
300 free(cur);
301}
302
303/*
304 * Creation of a new property of a node.
305 */
306xmlAttrPtr xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
307 xmlAttrPtr cur;
308
309 if (name == NULL) {
310 fprintf(stderr, "xmlNewProp : name == NULL\n");
311 return(NULL);
312 }
313
314 /*
315 * Allocate a new property and fill the fields.
316 */
317 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
318 if (cur == NULL) {
319 fprintf(stderr, "xmlNewProp : malloc failed\n");
320 return(NULL);
321 }
322
323 cur->node = node;
324 cur->name = xmlStrdup(name);
325 if (value != NULL)
326 cur->value = xmlStrdup(value);
327 else
328 cur->value = NULL;
329
330 /*
331 * Add it at the end to preserve parsing order ...
332 */
333 cur->next = NULL;
334 if (node != NULL) {
335 if (node->properties == NULL) {
336 node->properties = cur;
337 } else {
338 xmlAttrPtr prev = node->properties;
339
340 while (prev->next != NULL) prev = prev->next;
341 prev->next = cur;
342 }
343 }
344 return(cur);
345}
346
347/*
348 * Freeing a property list : Free a property and all its siblings,
349 * this is a recursive behaviour, all the childs
350 * are freed too.
351 */
352void xmlFreePropList(xmlAttrPtr cur) {
353 xmlAttrPtr next;
354 if (cur == NULL) {
355 fprintf(stderr, "xmlFreePropList : property == NULL\n");
356 return;
357 }
358 while (cur != NULL) {
359 next = cur->next;
360 xmlFreeProp(cur);
361 cur = next;
362 }
363}
364
365/*
366 * Freeing a property.
367 */
368void xmlFreeProp(xmlAttrPtr cur) {
369 if (cur == NULL) {
370 fprintf(stderr, "xmlFreeProp : property == NULL\n");
371 return;
372 }
373 if (cur->name != NULL) free((char *) cur->name);
374 if (cur->value != NULL) free((char *) cur->value);
375 memset(cur, -1, sizeof(xmlAttr));
376 free(cur);
377}
378
379/*
380 * Creation of a new node element in a given DTD.
381 * We assume that the "name" has already being strdup'd !
382 */
383xmlNodePtr xmlNewNode(xmlNsPtr ns, const CHAR *name, CHAR *content) {
384 xmlNodePtr cur;
385
386 if (name == NULL) {
387 fprintf(stderr, "xmlNewNode : name == NULL\n");
388 return(NULL);
389 }
390
391 /*
392 * Allocate a new node and fill the fields.
393 */
394 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
395 if (cur == NULL) {
396 fprintf(stderr, "xmlNewNode : malloc failed\n");
397 return(NULL);
398 }
399
400 cur->parent = NULL;
401 cur->next = NULL;
402 cur->childs = NULL;
403 cur->properties = NULL;
404 cur->type = 0;
405 cur->name = xmlStrdup(name);
406 cur->ns = ns;
407 cur->nsDef = NULL;
Daniel Veillard27864701998-10-08 03:47:24 +0000408 cur->servant = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000409 if (content != NULL)
410 cur->content = xmlStrdup(content);
411 else
412 cur->content = NULL;
413 return(cur);
414}
415
416/*
417 * Creation of a new node contening text.
418 */
419xmlNodePtr xmlNewText(const CHAR *content) {
420 xmlNodePtr cur;
421
422 /*
423 * Allocate a new node and fill the fields.
424 */
425 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
426 if (cur == NULL) {
427 fprintf(stderr, "xmlNewText : malloc failed\n");
428 return(NULL);
429 }
430
431 cur->parent = NULL;
432 cur->next = NULL;
433 cur->childs = NULL;
434 cur->properties = NULL;
435 cur->type = XML_TYPE_TEXT;
436 cur->name = xmlStrdup(xmlStringText);
437 cur->ns = NULL;
438 cur->nsDef = NULL;
439 if (content != NULL)
440 cur->content = xmlStrdup(content);
441 else
442 cur->content = NULL;
443 return(cur);
444}
445
446/*
447 * Creation of a new node contening text.
448 */
449xmlNodePtr xmlNewTextLen(const CHAR *content, int len) {
450 xmlNodePtr cur;
451
452 /*
453 * Allocate a new node and fill the fields.
454 */
455 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
456 if (cur == NULL) {
457 fprintf(stderr, "xmlNewText : malloc failed\n");
458 return(NULL);
459 }
460
461 cur->parent = NULL;
462 cur->next = NULL;
463 cur->childs = NULL;
464 cur->properties = NULL;
465 cur->type = XML_TYPE_TEXT;
466 cur->name = xmlStrdup(xmlStringText);
467 cur->ns = NULL;
468 cur->nsDef = NULL;
469 if (content != NULL)
470 cur->content = xmlStrndup(content, len);
471 else
472 cur->content = NULL;
473 return(cur);
474}
475
476/*
477 * Creation of a new node contening a comment.
478 */
479xmlNodePtr xmlNewComment(CHAR *content) {
480 xmlNodePtr cur;
481
482 /*
483 * Allocate a new node and fill the fields.
484 */
485 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
486 if (cur == NULL) {
487 fprintf(stderr, "xmlNewComment : malloc failed\n");
488 return(NULL);
489 }
490
491 cur->parent = NULL;
492 cur->next = NULL;
493 cur->childs = NULL;
494 cur->properties = NULL;
495 cur->type = XML_TYPE_COMMENT;
496 cur->name = xmlStrdup(xmlStringText);
497 cur->ns = NULL;
498 cur->nsDef = NULL;
499 if (content != NULL)
500 cur->content = xmlStrdup(content);
501 else
502 cur->content = NULL;
503 return(cur);
504}
505
506/*
507 * Creation of a new child element, added at the end.
508 */
509xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
510 const CHAR *name, CHAR *content) {
511 xmlNodePtr cur, prev;
512
513 if (parent == NULL) {
514 fprintf(stderr, "xmlNewChild : parent == NULL\n");
515 return(NULL);
516 }
517
518 if (name == NULL) {
519 fprintf(stderr, "xmlNewChild : name == NULL\n");
520 return(NULL);
521 }
522
523 /*
524 * Allocate a new node
525 */
526 if (ns == NULL)
527 cur = xmlNewNode(parent->ns, name, content);
528 else
529 cur = xmlNewNode(ns, name, content);
530 if (cur == NULL) return(NULL);
531
532 /*
533 * add the new element at the end of the childs list.
534 */
535 cur->parent = parent;
536 if (parent->childs == NULL) {
537 parent->childs = cur;
538 } else {
539 prev = parent->childs;
540 while (prev->next != NULL) prev = prev->next;
541 prev->next = cur;
542 }
543
544 return(cur);
545}
546
547/*
548 * Add a new child element, added at the end.
549 */
550xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
551 xmlNodePtr prev;
552
553 if (parent == NULL) {
554 fprintf(stderr, "xmladdChild : parent == NULL\n");
555 return(NULL);
556 }
557
558 if (cur == NULL) {
559 fprintf(stderr, "xmladdChild : child == NULL\n");
560 return(NULL);
561 }
562
563 /*
564 * add the new element at the end of the childs list.
565 */
566 cur->parent = parent;
567 if (parent->childs == NULL) {
568 parent->childs = cur;
569 } else {
570 prev = parent->childs;
571 while (prev->next != NULL) prev = prev->next;
572 prev->next = cur;
573 }
574
575 return(cur);
576}
577
578/*
579 * Search the last child, if any.
580 */
581xmlNodePtr xmlGetLastChild(xmlNodePtr parent) {
582 xmlNodePtr last;
583
584 if (parent == NULL) {
585 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
586 return(NULL);
587 }
588
589 /*
590 * add the new element at the end of the childs list.
591 */
592 if (parent->childs == NULL) {
593 return(NULL);
594 } else {
595 last = parent->childs;
596 while (last->next != NULL) last = last->next;
597 }
598 return(last);
599}
600
601/*
602 * Freeing a node list : Free a node and all its siblings,
603 * this is a recursive behaviour, all the childs
604 * are freed too.
605 */
606void xmlFreeNodeList(xmlNodePtr cur) {
607 xmlNodePtr next;
608 if (cur == NULL) {
609 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
610 return;
611 }
612 while (cur != NULL) {
613 next = cur->next;
614 xmlFreeNode(cur);
615 cur = next;
616 }
617}
618
619/*
620 * Freeing a node : this is a recursive behaviour, all the childs
621 * are freed too.
622 */
623void xmlFreeNode(xmlNodePtr cur) {
624 if (cur == NULL) {
625 fprintf(stderr, "xmlFreeNode : node == NULL\n");
626 return;
627 }
628 if (cur->properties != NULL) xmlFreePropList(cur->properties);
629 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
630 if (cur->content != NULL) free(cur->content);
631 if (cur->name != NULL) free((char *) cur->name);
632 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
633 memset(cur, -1, sizeof(xmlNode));
634 free(cur);
635}
636
637/************************************************************************
638 * *
639 * Content access functions *
640 * *
641 ************************************************************************/
642
643/*
644 * Changing the content of a node.
645 */
646void xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
647 if (cur == NULL) {
648 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
649 return;
650 }
651 if (cur->content != NULL) free(cur->content);
652 if (content != NULL)
653 cur->content = xmlStrdup(content);
654 else
655 cur->content = NULL;
656}
657
658/*
659 * Changing the content of a node.
660 */
661void xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
662 if (cur == NULL) {
663 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
664 return;
665 }
666 if (cur->content != NULL) free(cur->content);
667 if (content != NULL)
668 cur->content = xmlStrndup(content, len);
669 else
670 cur->content = NULL;
671}
672
673/*
674 * Adding content to a node.
675 */
676void xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
677 if (cur == NULL) {
678 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
679 return;
680 }
681 cur->content = xmlStrcat(cur->content, content);
682}
683
684/*
685 * Adding content to a node.
686 */
687void xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
688 if (cur == NULL) {
689 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
690 return;
691 }
692 cur->content = xmlStrncat(cur->content, content, len);
693}
694
695/*
696 * Search a Ns registered under a given name space for a document.
697 * recurse on the parents until it finds the defined namespace
698 * or return NULL otherwise.
699 *
700 * Note : nameSpace == NULL is valid, this is a search for the default
701 * namespace.
702 */
703xmlNsPtr xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
704 xmlNsPtr cur;
705
706 while (node != NULL) {
707 cur = node->nsDef;
708 while (cur != NULL) {
709 if ((cur->prefix == NULL) && (nameSpace == NULL))
710 return(cur);
711 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
712 (!xmlStrcmp(cur->prefix, nameSpace)))
713 return(cur);
714 cur = cur->next;
715 }
716 node = node->parent;
717 }
718 if (doc != NULL) {
719 cur = doc->oldNs;
720 while (cur != NULL) {
721 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
722 (!xmlStrcmp(cur->prefix, nameSpace)))
723 return(cur);
724 cur = cur->next;
725 }
726 }
727 return(NULL);
728}
729
730/*
731 * Search a Ns aliasing a given URI
732 * recurse on the parents until it finds the defined namespace
733 * or return NULL otherwise.
734 */
735xmlNsPtr xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
736 xmlNsPtr cur;
737
738 while (node != NULL) {
739 cur = node->nsDef;
740 while (cur != NULL) {
741 if ((cur->href != NULL) && (href != NULL) &&
742 (!xmlStrcmp(cur->href, href)))
743 return(cur);
744 cur = cur->next;
745 }
746 node = node->parent;
747 }
748 if (doc != NULL) {
749 cur = doc->oldNs;
750 while (cur != NULL) {
751 if ((cur->href != NULL) && (href != NULL) &&
752 (!xmlStrcmp(cur->href, href)))
753 return(cur);
754 cur = cur->next;
755 }
756 }
757 return(NULL);
758}
759
760/*
761 * Reading the content of a given property.
762 */
763const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
764 xmlAttrPtr prop = node->properties;
765
766 while (prop != NULL) {
767 if (!xmlStrcmp(prop->name, name)) return(prop->value);
768 prop = prop->next;
769 }
770 return(NULL);
771}
772
773/*
774 * Setting the content of a given property.
775 */
776xmlAttrPtr xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
777 xmlAttrPtr prop = node->properties;
778
779 while (prop != NULL) {
780 if (!xmlStrcmp(prop->name, name)) {
781 if (prop->value != NULL)
782 free((char *) prop->value);
783 prop->value = NULL;
784 if (value != NULL)
785 prop->value = xmlStrdup(value);
786 return(prop);
787 }
788 prop = prop->next;
789 }
790 prop = xmlNewProp(node, name, value);
791 return(prop);
792}
793
794/*
795 * Is this node a piece of text
796 */
797int xmlNodeIsText(xmlNodePtr node) {
798 if (node == NULL) return(0);
799
800 if (node->type == XML_TYPE_TEXT) return(1);
801 return(0);
802}
803
804/*
805 * Concat a piece of text to an existing text node
806 *
807 * TODO !!! Should be optimized with a bit of preallocation.
808 */
809void xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
810 if (node == NULL) return;
811
812 if (node->type != XML_TYPE_TEXT) {
813 fprintf(stderr, "xmlTextConcat: node is not text\n");
814 return;
815 }
816 node->content = xmlStrncat(node->content, content, len);
817}
818
819/************************************************************************
820 * *
821 * Output : to a FILE or in memory *
822 * *
823 ************************************************************************/
824
825/*
826 * routine which manage and grows an output buffer. One can write
827 * standard char array's (8 bits char) or CHAR's arrays.
828 */
829static CHAR *buffer = NULL;
830static int buffer_index = 0;
831static int buffer_size = 0;
832
833void xmlBufferWriteCHAR(const CHAR *string) {
834 const CHAR *cur;
835
836 if (buffer == NULL) {
837 buffer_size = 50000;
838 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
839 if (buffer == NULL) {
840 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
841 exit(1);
842 }
843 }
844
845 if (string == NULL) return;
846 for (cur = string;*cur != 0;cur++) {
847 if (buffer_index + 10 >= buffer_size) {
848 buffer_size *= 2;
849 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
850 if (buffer == NULL) {
851 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
852 exit(1);
853 }
854 }
855 buffer[buffer_index++] = *cur;
856 }
857 buffer[buffer_index] = 0;
858}
859
860void xmlBufferWriteChar(const char *string) {
861 const char *cur;
862
863 if (buffer == NULL) {
864 buffer_size = 50000;
865 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
866 if (buffer == NULL) {
867 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
868 exit(1);
869 }
870 }
871
872 if (string == NULL) return;
873 for (cur = string;*cur != 0;cur++) {
874 if (buffer_index + 10 >= buffer_size) {
875 buffer_size *= 2;
876 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
877 if (buffer == NULL) {
878 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
879 exit(1);
880 }
881 }
882 buffer[buffer_index++] = *cur;
883 }
884 buffer[buffer_index] = 0;
885}
886
887/*
888 * Dump the global Namespace inherited from the old WD.
889 * Within the context of the document header.
890 */
891static void xmlGlobalNsDump(xmlNsPtr cur) {
892 if (cur == NULL) {
893 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
894 return;
895 }
896 if (cur->type == XML_GLOBAL_NAMESPACE) {
897 xmlBufferWriteChar("<?namespace");
898 if (cur->href != NULL) {
899 xmlBufferWriteChar(" href=\"");
900 xmlBufferWriteCHAR(cur->href);
901 xmlBufferWriteChar("\"");
902 }
903 if (cur->prefix != NULL) {
904 xmlBufferWriteChar(" AS=\"");
905 xmlBufferWriteCHAR(cur->prefix);
906 xmlBufferWriteChar("\"");
907 }
908 xmlBufferWriteChar("?>\n");
909 }
910}
911
912/*
913 * Dump an old global XML Namespace list
914 */
915
916static void xmlGlobalNsListDump(xmlNsPtr cur) {
917 while (cur != NULL) {
918 xmlGlobalNsDump(cur);
919 cur = cur->next;
920 }
921}
922
923/*
924 * Dump a local Namespace definition.
925 * Within the context of an element attributes.
926 */
927static void xmlNsDump(xmlNsPtr cur) {
928 if (cur == NULL) {
929 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
930 return;
931 }
932 if (cur->type == XML_LOCAL_NAMESPACE) {
933 /* Within the context of an element attributes */
934 if (cur->prefix != NULL) {
935 xmlBufferWriteChar(" xmlns:");
936 xmlBufferWriteCHAR(cur->prefix);
937 } else
938 xmlBufferWriteChar(" xmlns");
939 xmlBufferWriteChar("=\"");
940 xmlBufferWriteCHAR(cur->href);
941 xmlBufferWriteChar("\"");
942 }
943}
944
945/*
946 * Dump an XML Namespace list
947 */
948
949static void xmlNsListDump(xmlNsPtr cur) {
950 while (cur != NULL) {
951 xmlNsDump(cur);
952 cur = cur->next;
953 }
954}
955
956/*
957 * Dump an XML DTD
958 */
959
960static void xmlDtdDump(xmlDocPtr doc) {
961 xmlDtdPtr cur = doc->dtd;
962
963 if (cur == NULL) {
964 fprintf(stderr, "xmlDtdDump : DTD == NULL\n");
965 return;
966 }
967 xmlBufferWriteChar("<!DOCTYPE ");
968 xmlBufferWriteCHAR(cur->name);
969 if (cur->ExternalID != NULL) {
970 xmlBufferWriteChar(" PUBLIC \"");
971 xmlBufferWriteCHAR(cur->ExternalID);
972 xmlBufferWriteChar("\" \"");
973 xmlBufferWriteCHAR(cur->SystemID);
974 xmlBufferWriteChar("\"");
975 } else if (cur->SystemID != NULL) {
976 xmlBufferWriteChar(" SYSTEM \"");
977 xmlBufferWriteCHAR(cur->SystemID);
978 xmlBufferWriteChar("\"");
979 }
980 if ((cur->entities == NULL) && (doc->entities == NULL)) {
981 xmlBufferWriteChar(">\n");
982 return;
983 }
984 xmlBufferWriteChar(" [\n");
985 if (cur->entities != NULL)
986 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
987 if (doc->entities != NULL)
988 xmlDumpEntitiesTable((xmlEntitiesTablePtr) doc->entities);
989 xmlBufferWriteChar("]");
990
991 /* TODO !!! a lot more things to dump ... */
992 xmlBufferWriteChar(">\n");
993}
994
995/*
996 * Dump an XML property
997 */
998
999static void xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
1000 if (cur == NULL) {
1001 fprintf(stderr, "xmlAttrDump : property == NULL\n");
1002 return;
1003 }
1004 xmlBufferWriteChar(" ");
1005 xmlBufferWriteCHAR(cur->name);
1006 if (cur->value) {
1007 xmlBufferWriteChar("=\"");
1008 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->value));
1009 xmlBufferWriteChar("\"");
1010 }
1011}
1012
1013/*
1014 * Dump an XML property list
1015 */
1016
1017static void xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
1018 if (cur == NULL) {
1019 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
1020 return;
1021 }
1022 while (cur != NULL) {
1023 xmlAttrDump(doc, cur);
1024 cur = cur->next;
1025 }
1026}
1027
1028/*
1029 * Dump an XML node list
1030 */
1031
1032static void xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
1033static void xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1034 if (cur == NULL) {
1035 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
1036 return;
1037 }
1038 while (cur != NULL) {
1039 xmlNodeDump(doc, cur, level);
1040 cur = cur->next;
1041 }
1042}
1043
1044/*
1045 * Dump an XML node
1046 */
1047
1048static void xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1049 int i;
1050
1051 if (cur == NULL) {
1052 fprintf(stderr, "xmlNodeDump : node == NULL\n");
1053 return;
1054 }
1055 if (cur->type == XML_TYPE_TEXT) {
1056 if (cur->content != NULL)
1057 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1058 return;
1059 }
1060 if (cur->type == XML_TYPE_COMMENT) {
1061 if (cur->content != NULL) {
1062 xmlBufferWriteChar("<!--");
1063 xmlBufferWriteCHAR(cur->content);
1064 xmlBufferWriteChar("-->");
1065 }
1066 return;
1067 }
1068 if (xmlIndentTreeOutput)
1069 for (i = 0;i < level;i++)
1070 xmlBufferWriteChar(" ");
1071
1072 xmlBufferWriteChar("<");
1073 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1074 xmlBufferWriteCHAR(cur->ns->prefix);
1075 xmlBufferWriteChar(":");
1076 }
1077
1078 xmlBufferWriteCHAR(cur->name);
1079 if (cur->nsDef)
1080 xmlNsListDump(cur->nsDef);
1081 if (cur->properties != NULL)
1082 xmlAttrListDump(doc, cur->properties);
1083
1084 if ((cur->content == NULL) && (cur->childs == NULL)) {
1085 xmlBufferWriteChar("/>\n");
1086 return;
1087 }
1088 xmlBufferWriteChar(">");
1089 if (cur->content != NULL)
1090 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1091 if (cur->childs != NULL) {
1092 xmlBufferWriteChar("\n");
1093 xmlNodeListDump(doc, cur->childs, level + 1);
1094 if (xmlIndentTreeOutput)
1095 for (i = 0;i < level;i++)
1096 xmlBufferWriteChar(" ");
1097 }
1098 xmlBufferWriteChar("</");
1099 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1100 xmlBufferWriteCHAR(cur->ns->prefix);
1101 xmlBufferWriteChar(":");
1102 }
1103
1104 xmlBufferWriteCHAR(cur->name);
1105 xmlBufferWriteChar(">\n");
1106}
1107
1108/*
1109 * Dump an XML document
1110 */
1111static void xmlDocContentDump(xmlDocPtr cur) {
1112 if (oldXMLWDcompatibility)
1113 xmlBufferWriteChar("<?XML version=\"");
1114 else
1115 xmlBufferWriteChar("<?xml version=\"");
1116 xmlBufferWriteCHAR(cur->version);
1117 xmlBufferWriteChar("\"");
1118 if (cur->encoding != NULL) {
1119 xmlBufferWriteChar(" encoding=\"");
1120 xmlBufferWriteCHAR(cur->encoding);
1121 xmlBufferWriteChar("\"");
1122 }
1123 switch (cur->standalone) {
1124 case 0:
1125 xmlBufferWriteChar(" standalone=\"no\"");
1126 break;
1127 case 1:
1128 xmlBufferWriteChar(" standalone=\"yes\"");
1129 break;
1130 }
1131 xmlBufferWriteChar("?>\n");
1132 if ((cur->dtd != NULL) || (cur->entities != NULL))
1133 xmlDtdDump(cur);
1134 if (cur->root != NULL) {
1135 /* global namespace definitions, the old way */
1136 if (oldXMLWDcompatibility)
1137 xmlGlobalNsListDump(cur->oldNs);
1138 else
1139 xmlUpgradeOldNs(cur);
1140 xmlNodeDump(cur, cur->root, 0);
1141 }
1142}
1143
1144/*
1145 * Dump an XML document to memory.
1146 */
1147
1148void xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
1149 if (cur == NULL) {
1150 fprintf(stderr, "xmlDocDump : document == NULL\n");
1151 *mem = NULL;
1152 *size = 0;
1153 return;
1154 }
1155 buffer_index = 0;
1156 xmlDocContentDump(cur);
1157
1158 *mem = buffer;
1159 *size = buffer_index;
1160}
1161
1162/*
Daniel Veillard15a8df41998-09-24 19:15:06 +00001163 * Get/Set a document compression mode.
Daniel Veillard151b1b01998-09-23 00:49:46 +00001164 */
1165
Daniel Veillard15a8df41998-09-24 19:15:06 +00001166int xmlGetDocCompressMode (xmlDocPtr doc) {
1167 if (doc == NULL) return(-1);
1168 return(doc->compression);
1169}
1170
1171void xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
1172 if (doc == NULL) return;
1173 if (mode < 0) doc->compression = 0;
1174 else if (mode > 9) doc->compression = 9;
1175 else doc->compression = mode;
1176}
1177
1178/*
1179 * Get/Set the global compression mode
1180 */
Daniel Veillard151b1b01998-09-23 00:49:46 +00001181
1182int xmlGetCompressMode(void) {
1183 return(xmlCompressMode);
1184}
1185void xmlSetCompressMode(int mode) {
1186 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00001187 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00001188 else xmlCompressMode = mode;
1189}
1190
1191/*
Daniel Veillard260a68f1998-08-13 03:39:55 +00001192 * Dump an XML document to the given FD
1193 */
1194
1195void xmlDocDump(FILE *f, xmlDocPtr cur) {
1196 if (cur == NULL) {
1197 fprintf(stderr, "xmlDocDump : document == NULL\n");
1198 return;
1199 }
1200 buffer_index = 0;
1201 xmlDocContentDump(cur);
1202
1203 fwrite(buffer, sizeof(CHAR), buffer_index, f);
1204}
1205
Daniel Veillard151b1b01998-09-23 00:49:46 +00001206/*
1207 * Dump an XML document to a file.
1208 */
1209
1210int xmlSaveFile(const char *filename, xmlDocPtr cur) {
1211#ifdef HAVE_ZLIB_H
1212 gzFile zoutput = NULL;
1213 char mode[15];
1214#endif
1215 FILE *output;
1216 int ret;
1217
1218#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00001219 if ((cur->compression > 0) && (cur->compression <= 9)) {
1220 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00001221 zoutput = gzopen(filename, mode);
1222 }
1223 if (zoutput == NULL) {
1224#endif
1225 output = fopen(filename, "w");
1226 if (output == NULL) return(-1);
1227#ifdef HAVE_ZLIB_H
1228 }
1229#endif
1230
1231 /*
1232 * save the content to a temp buffer.
1233 */
1234 buffer_index = 0;
1235 xmlDocContentDump(cur);
1236
1237#ifdef HAVE_ZLIB_H
1238 if (zoutput != NULL) {
1239 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
1240 gzclose(zoutput);
1241 return(ret);
1242 }
1243#endif
1244 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
1245 fclose(output);
1246 return(ret * sizeof(CHAR));
1247}
1248
Daniel Veillard260a68f1998-08-13 03:39:55 +00001249/************************************************************************
1250 * *
1251 * Debug *
1252 * *
1253 ************************************************************************/
1254
1255#ifdef STANDALONE
1256int main(void) {
1257 xmlDocPtr doc;
1258 xmlNodePtr tree, subtree;
1259 xmlNsPtr ns1;
1260 xmlNsPtr ns2;
1261
1262 /*
1263 * build a fake XML document
1264 */
1265 doc = xmlNewDoc("1.0");
1266 ns1 = xmlNewNs(doc, "http://www.ietf.org/standards/dav/", "D");
1267 ns2 = xmlNewNs(doc, "http://www.w3.com/standards/z39.50/", "Z");
1268 doc->root = xmlNewNode(ns1, "multistatus", NULL);
1269 tree = xmlNewChild(doc->root, NULL, "response", NULL);
1270 subtree = xmlNewChild(tree, NULL, "prop", NULL);
1271 xmlNewChild(subtree, ns2, "Authors", NULL);
1272 subtree = xmlNewChild(tree, NULL, "status", "HTTP/1.1 420 Method Failure");
1273 tree = xmlNewChild(doc->root, NULL, "response", NULL);
1274 subtree = xmlNewChild(tree, NULL, "prop", NULL);
1275 xmlNewChild(subtree, ns2, "Copyright-Owner", NULL);
1276 subtree = xmlNewChild(tree, NULL, "status", "HTTP/1.1 409 Conflict");
1277 tree = xmlNewChild(doc->root, NULL, "responsedescription",
1278 "Copyright Owner can not be deleted or altered");
1279
1280 /*
1281 * print it.
1282 */
1283 xmlDocDump(stdout, doc);
1284
1285 /*
1286 * free it.
1287 */
1288 xmlFreeDoc(doc);
1289 return(0);
1290}
1291#endif