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