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