blob: c4eddec572ca4577d81ddf06c3fbeb06bdbaa3b9 [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
Daniel Veillard0bef1311998-10-14 02:36:47 +0000400 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000401 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000402 cur->next = NULL;
403 cur->prev = NULL;
404 cur->childs = NULL;
405 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000406 cur->type = 0;
407 cur->name = xmlStrdup(name);
408 cur->ns = ns;
409 cur->nsDef = NULL;
Daniel Veillard27864701998-10-08 03:47:24 +0000410 cur->servant = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000411 if (content != NULL)
412 cur->content = xmlStrdup(content);
413 else
414 cur->content = NULL;
415 return(cur);
416}
417
Daniel Veillard0bef1311998-10-14 02:36:47 +0000418xmlNodePtr xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
419 const CHAR *name, CHAR *content) {
420 xmlNodePtr cur;
421
422 cur = xmlNewNode(ns, name, content);
423 if (cur != NULL) cur->doc = doc;
424 return(cur);
425}
426
427
Daniel Veillard260a68f1998-08-13 03:39:55 +0000428/*
429 * Creation of a new node contening text.
430 */
431xmlNodePtr xmlNewText(const CHAR *content) {
432 xmlNodePtr cur;
433
434 /*
435 * Allocate a new node and fill the fields.
436 */
437 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
438 if (cur == NULL) {
439 fprintf(stderr, "xmlNewText : malloc failed\n");
440 return(NULL);
441 }
442
Daniel Veillard0bef1311998-10-14 02:36:47 +0000443 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000444 cur->parent = NULL;
445 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000446 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000447 cur->childs = NULL;
448 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000449 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000450 cur->name = xmlStrdup(xmlStringText);
451 cur->ns = NULL;
452 cur->nsDef = NULL;
453 if (content != NULL)
454 cur->content = xmlStrdup(content);
455 else
456 cur->content = NULL;
457 return(cur);
458}
459
Daniel Veillard0bef1311998-10-14 02:36:47 +0000460xmlNodePtr xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
461 xmlNodePtr cur;
462
463 cur = xmlNewText(content);
464 if (cur != NULL) cur->doc = doc;
465 return(cur);
466}
467
Daniel Veillard260a68f1998-08-13 03:39:55 +0000468/*
469 * Creation of a new node contening text.
470 */
471xmlNodePtr xmlNewTextLen(const CHAR *content, int len) {
472 xmlNodePtr cur;
473
474 /*
475 * Allocate a new node and fill the fields.
476 */
477 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
478 if (cur == NULL) {
479 fprintf(stderr, "xmlNewText : malloc failed\n");
480 return(NULL);
481 }
482
Daniel Veillard0bef1311998-10-14 02:36:47 +0000483 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000484 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000485 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000486 cur->next = NULL;
487 cur->childs = NULL;
488 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000489 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000490 cur->name = xmlStrdup(xmlStringText);
491 cur->ns = NULL;
492 cur->nsDef = NULL;
493 if (content != NULL)
494 cur->content = xmlStrndup(content, len);
495 else
496 cur->content = NULL;
497 return(cur);
498}
499
Daniel Veillard0bef1311998-10-14 02:36:47 +0000500xmlNodePtr xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
501 xmlNodePtr cur;
502
503 cur = xmlNewTextLen(content, len);
504 if (cur != NULL) cur->doc = doc;
505 return(cur);
506}
507
Daniel Veillard260a68f1998-08-13 03:39:55 +0000508/*
509 * Creation of a new node contening a comment.
510 */
511xmlNodePtr xmlNewComment(CHAR *content) {
512 xmlNodePtr cur;
513
514 /*
515 * Allocate a new node and fill the fields.
516 */
517 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
518 if (cur == NULL) {
519 fprintf(stderr, "xmlNewComment : malloc failed\n");
520 return(NULL);
521 }
522
Daniel Veillard0bef1311998-10-14 02:36:47 +0000523 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000524 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000525 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000526 cur->next = NULL;
527 cur->childs = NULL;
528 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000529 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000530 cur->name = xmlStrdup(xmlStringText);
531 cur->ns = NULL;
532 cur->nsDef = NULL;
533 if (content != NULL)
534 cur->content = xmlStrdup(content);
535 else
536 cur->content = NULL;
537 return(cur);
538}
539
Daniel Veillard0bef1311998-10-14 02:36:47 +0000540xmlNodePtr xmlNewDocComment(xmlDocPtr doc, CHAR *content) {
541 xmlNodePtr cur;
542
543 cur = xmlNewComment(content);
544 if (cur != NULL) cur->doc = doc;
545 return(cur);
546}
547
Daniel Veillard260a68f1998-08-13 03:39:55 +0000548/*
549 * Creation of a new child element, added at the end.
550 */
551xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
552 const CHAR *name, CHAR *content) {
553 xmlNodePtr cur, prev;
554
555 if (parent == NULL) {
556 fprintf(stderr, "xmlNewChild : parent == NULL\n");
557 return(NULL);
558 }
559
560 if (name == NULL) {
561 fprintf(stderr, "xmlNewChild : name == NULL\n");
562 return(NULL);
563 }
564
565 /*
566 * Allocate a new node
567 */
568 if (ns == NULL)
569 cur = xmlNewNode(parent->ns, name, content);
570 else
571 cur = xmlNewNode(ns, name, content);
572 if (cur == NULL) return(NULL);
573
574 /*
575 * add the new element at the end of the childs list.
576 */
577 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000578 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000579 if (parent->childs == NULL) {
580 parent->childs = cur;
581 } else {
582 prev = parent->childs;
583 while (prev->next != NULL) prev = prev->next;
584 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000585 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000586 }
587
588 return(cur);
589}
590
591/*
592 * Add a new child element, added at the end.
593 */
594xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
595 xmlNodePtr prev;
596
597 if (parent == NULL) {
598 fprintf(stderr, "xmladdChild : parent == NULL\n");
599 return(NULL);
600 }
601
602 if (cur == NULL) {
603 fprintf(stderr, "xmladdChild : child == NULL\n");
604 return(NULL);
605 }
606
Daniel Veillard0bef1311998-10-14 02:36:47 +0000607 if ((cur->doc != NULL) && (parent->doc != NULL) &&
608 (cur->doc != parent->doc)) {
609 fprintf(stderr, "Elements moved to a different document\n");
610 }
611
Daniel Veillard260a68f1998-08-13 03:39:55 +0000612 /*
613 * add the new element at the end of the childs list.
614 */
615 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000616 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000617 if (parent->childs == NULL) {
618 parent->childs = cur;
619 } else {
620 prev = parent->childs;
621 while (prev->next != NULL) prev = prev->next;
622 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000623 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000624 }
625
626 return(cur);
627}
628
629/*
630 * Search the last child, if any.
631 */
632xmlNodePtr xmlGetLastChild(xmlNodePtr parent) {
633 xmlNodePtr last;
634
635 if (parent == NULL) {
636 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
637 return(NULL);
638 }
639
640 /*
641 * add the new element at the end of the childs list.
642 */
643 if (parent->childs == NULL) {
644 return(NULL);
645 } else {
646 last = parent->childs;
647 while (last->next != NULL) last = last->next;
648 }
649 return(last);
650}
651
652/*
653 * Freeing a node list : Free a node and all its siblings,
654 * this is a recursive behaviour, all the childs
655 * are freed too.
656 */
657void xmlFreeNodeList(xmlNodePtr cur) {
658 xmlNodePtr next;
659 if (cur == NULL) {
660 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
661 return;
662 }
663 while (cur != NULL) {
664 next = cur->next;
665 xmlFreeNode(cur);
666 cur = next;
667 }
668}
669
670/*
671 * Freeing a node : this is a recursive behaviour, all the childs
672 * are freed too.
673 */
674void xmlFreeNode(xmlNodePtr cur) {
675 if (cur == NULL) {
676 fprintf(stderr, "xmlFreeNode : node == NULL\n");
677 return;
678 }
679 if (cur->properties != NULL) xmlFreePropList(cur->properties);
680 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
681 if (cur->content != NULL) free(cur->content);
682 if (cur->name != NULL) free((char *) cur->name);
683 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
684 memset(cur, -1, sizeof(xmlNode));
685 free(cur);
686}
687
688/************************************************************************
689 * *
690 * Content access functions *
691 * *
692 ************************************************************************/
693
694/*
695 * Changing the content of a node.
696 */
697void xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
698 if (cur == NULL) {
699 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
700 return;
701 }
702 if (cur->content != NULL) free(cur->content);
703 if (content != NULL)
704 cur->content = xmlStrdup(content);
705 else
706 cur->content = NULL;
707}
708
709/*
710 * Changing the content of a node.
711 */
712void xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
713 if (cur == NULL) {
714 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
715 return;
716 }
717 if (cur->content != NULL) free(cur->content);
718 if (content != NULL)
719 cur->content = xmlStrndup(content, len);
720 else
721 cur->content = NULL;
722}
723
724/*
725 * Adding content to a node.
726 */
727void xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
728 if (cur == NULL) {
729 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
730 return;
731 }
732 cur->content = xmlStrcat(cur->content, content);
733}
734
735/*
736 * Adding content to a node.
737 */
738void xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
739 if (cur == NULL) {
740 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
741 return;
742 }
743 cur->content = xmlStrncat(cur->content, content, len);
744}
745
746/*
747 * Search a Ns registered under a given name space for a document.
748 * recurse on the parents until it finds the defined namespace
749 * or return NULL otherwise.
750 *
751 * Note : nameSpace == NULL is valid, this is a search for the default
752 * namespace.
753 */
754xmlNsPtr xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
755 xmlNsPtr cur;
756
757 while (node != NULL) {
758 cur = node->nsDef;
759 while (cur != NULL) {
760 if ((cur->prefix == NULL) && (nameSpace == NULL))
761 return(cur);
762 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
763 (!xmlStrcmp(cur->prefix, nameSpace)))
764 return(cur);
765 cur = cur->next;
766 }
767 node = node->parent;
768 }
769 if (doc != NULL) {
770 cur = doc->oldNs;
771 while (cur != NULL) {
772 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
773 (!xmlStrcmp(cur->prefix, nameSpace)))
774 return(cur);
775 cur = cur->next;
776 }
777 }
778 return(NULL);
779}
780
781/*
782 * Search a Ns aliasing a given URI
783 * recurse on the parents until it finds the defined namespace
784 * or return NULL otherwise.
785 */
786xmlNsPtr xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
787 xmlNsPtr cur;
788
789 while (node != NULL) {
790 cur = node->nsDef;
791 while (cur != NULL) {
792 if ((cur->href != NULL) && (href != NULL) &&
793 (!xmlStrcmp(cur->href, href)))
794 return(cur);
795 cur = cur->next;
796 }
797 node = node->parent;
798 }
799 if (doc != NULL) {
800 cur = doc->oldNs;
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 }
808 return(NULL);
809}
810
811/*
812 * Reading the content of a given property.
813 */
814const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
815 xmlAttrPtr prop = node->properties;
816
817 while (prop != NULL) {
818 if (!xmlStrcmp(prop->name, name)) return(prop->value);
819 prop = prop->next;
820 }
821 return(NULL);
822}
823
824/*
825 * Setting the content of a given property.
826 */
827xmlAttrPtr xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
828 xmlAttrPtr prop = node->properties;
829
830 while (prop != NULL) {
831 if (!xmlStrcmp(prop->name, name)) {
832 if (prop->value != NULL)
833 free((char *) prop->value);
834 prop->value = NULL;
835 if (value != NULL)
836 prop->value = xmlStrdup(value);
837 return(prop);
838 }
839 prop = prop->next;
840 }
841 prop = xmlNewProp(node, name, value);
842 return(prop);
843}
844
845/*
846 * Is this node a piece of text
847 */
848int xmlNodeIsText(xmlNodePtr node) {
849 if (node == NULL) return(0);
850
Daniel Veillard0bef1311998-10-14 02:36:47 +0000851 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000852 return(0);
853}
854
855/*
856 * Concat a piece of text to an existing text node
857 *
858 * TODO !!! Should be optimized with a bit of preallocation.
859 */
860void xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
861 if (node == NULL) return;
862
Daniel Veillard0bef1311998-10-14 02:36:47 +0000863 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000864 fprintf(stderr, "xmlTextConcat: node is not text\n");
865 return;
866 }
867 node->content = xmlStrncat(node->content, content, len);
868}
869
870/************************************************************************
871 * *
872 * Output : to a FILE or in memory *
873 * *
874 ************************************************************************/
875
876/*
877 * routine which manage and grows an output buffer. One can write
878 * standard char array's (8 bits char) or CHAR's arrays.
879 */
880static CHAR *buffer = NULL;
881static int buffer_index = 0;
882static int buffer_size = 0;
883
884void xmlBufferWriteCHAR(const CHAR *string) {
885 const CHAR *cur;
886
887 if (buffer == NULL) {
888 buffer_size = 50000;
889 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
890 if (buffer == NULL) {
891 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
892 exit(1);
893 }
894 }
895
896 if (string == NULL) return;
897 for (cur = string;*cur != 0;cur++) {
898 if (buffer_index + 10 >= buffer_size) {
899 buffer_size *= 2;
900 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
901 if (buffer == NULL) {
902 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
903 exit(1);
904 }
905 }
906 buffer[buffer_index++] = *cur;
907 }
908 buffer[buffer_index] = 0;
909}
910
911void xmlBufferWriteChar(const char *string) {
912 const char *cur;
913
914 if (buffer == NULL) {
915 buffer_size = 50000;
916 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
917 if (buffer == NULL) {
918 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
919 exit(1);
920 }
921 }
922
923 if (string == NULL) return;
924 for (cur = string;*cur != 0;cur++) {
925 if (buffer_index + 10 >= buffer_size) {
926 buffer_size *= 2;
927 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
928 if (buffer == NULL) {
929 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
930 exit(1);
931 }
932 }
933 buffer[buffer_index++] = *cur;
934 }
935 buffer[buffer_index] = 0;
936}
937
938/*
939 * Dump the global Namespace inherited from the old WD.
940 * Within the context of the document header.
941 */
942static void xmlGlobalNsDump(xmlNsPtr cur) {
943 if (cur == NULL) {
944 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
945 return;
946 }
947 if (cur->type == XML_GLOBAL_NAMESPACE) {
948 xmlBufferWriteChar("<?namespace");
949 if (cur->href != NULL) {
950 xmlBufferWriteChar(" href=\"");
951 xmlBufferWriteCHAR(cur->href);
952 xmlBufferWriteChar("\"");
953 }
954 if (cur->prefix != NULL) {
955 xmlBufferWriteChar(" AS=\"");
956 xmlBufferWriteCHAR(cur->prefix);
957 xmlBufferWriteChar("\"");
958 }
959 xmlBufferWriteChar("?>\n");
960 }
961}
962
963/*
964 * Dump an old global XML Namespace list
965 */
966
967static void xmlGlobalNsListDump(xmlNsPtr cur) {
968 while (cur != NULL) {
969 xmlGlobalNsDump(cur);
970 cur = cur->next;
971 }
972}
973
974/*
975 * Dump a local Namespace definition.
976 * Within the context of an element attributes.
977 */
978static void xmlNsDump(xmlNsPtr cur) {
979 if (cur == NULL) {
980 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
981 return;
982 }
983 if (cur->type == XML_LOCAL_NAMESPACE) {
984 /* Within the context of an element attributes */
985 if (cur->prefix != NULL) {
986 xmlBufferWriteChar(" xmlns:");
987 xmlBufferWriteCHAR(cur->prefix);
988 } else
989 xmlBufferWriteChar(" xmlns");
990 xmlBufferWriteChar("=\"");
991 xmlBufferWriteCHAR(cur->href);
992 xmlBufferWriteChar("\"");
993 }
994}
995
996/*
997 * Dump an XML Namespace list
998 */
999
1000static void xmlNsListDump(xmlNsPtr cur) {
1001 while (cur != NULL) {
1002 xmlNsDump(cur);
1003 cur = cur->next;
1004 }
1005}
1006
1007/*
1008 * Dump an XML DTD
1009 */
1010
1011static void xmlDtdDump(xmlDocPtr doc) {
1012 xmlDtdPtr cur = doc->dtd;
1013
1014 if (cur == NULL) {
1015 fprintf(stderr, "xmlDtdDump : DTD == NULL\n");
1016 return;
1017 }
1018 xmlBufferWriteChar("<!DOCTYPE ");
1019 xmlBufferWriteCHAR(cur->name);
1020 if (cur->ExternalID != NULL) {
1021 xmlBufferWriteChar(" PUBLIC \"");
1022 xmlBufferWriteCHAR(cur->ExternalID);
1023 xmlBufferWriteChar("\" \"");
1024 xmlBufferWriteCHAR(cur->SystemID);
1025 xmlBufferWriteChar("\"");
1026 } else if (cur->SystemID != NULL) {
1027 xmlBufferWriteChar(" SYSTEM \"");
1028 xmlBufferWriteCHAR(cur->SystemID);
1029 xmlBufferWriteChar("\"");
1030 }
1031 if ((cur->entities == NULL) && (doc->entities == NULL)) {
1032 xmlBufferWriteChar(">\n");
1033 return;
1034 }
1035 xmlBufferWriteChar(" [\n");
1036 if (cur->entities != NULL)
1037 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1038 if (doc->entities != NULL)
1039 xmlDumpEntitiesTable((xmlEntitiesTablePtr) doc->entities);
1040 xmlBufferWriteChar("]");
1041
1042 /* TODO !!! a lot more things to dump ... */
1043 xmlBufferWriteChar(">\n");
1044}
1045
1046/*
1047 * Dump an XML property
1048 */
1049
1050static void xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
1051 if (cur == NULL) {
1052 fprintf(stderr, "xmlAttrDump : property == NULL\n");
1053 return;
1054 }
1055 xmlBufferWriteChar(" ");
1056 xmlBufferWriteCHAR(cur->name);
1057 if (cur->value) {
1058 xmlBufferWriteChar("=\"");
1059 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->value));
1060 xmlBufferWriteChar("\"");
1061 }
1062}
1063
1064/*
1065 * Dump an XML property list
1066 */
1067
1068static void xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
1069 if (cur == NULL) {
1070 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
1071 return;
1072 }
1073 while (cur != NULL) {
1074 xmlAttrDump(doc, cur);
1075 cur = cur->next;
1076 }
1077}
1078
1079/*
1080 * Dump an XML node list
1081 */
1082
1083static void xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
1084static void xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1085 if (cur == NULL) {
1086 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
1087 return;
1088 }
1089 while (cur != NULL) {
1090 xmlNodeDump(doc, cur, level);
1091 cur = cur->next;
1092 }
1093}
1094
1095/*
1096 * Dump an XML node
1097 */
1098
1099static void xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
1100 int i;
1101
1102 if (cur == NULL) {
1103 fprintf(stderr, "xmlNodeDump : node == NULL\n");
1104 return;
1105 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001106 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001107 if (cur->content != NULL)
1108 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1109 return;
1110 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001111 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001112 if (cur->content != NULL) {
1113 xmlBufferWriteChar("<!--");
1114 xmlBufferWriteCHAR(cur->content);
1115 xmlBufferWriteChar("-->");
1116 }
1117 return;
1118 }
1119 if (xmlIndentTreeOutput)
1120 for (i = 0;i < level;i++)
1121 xmlBufferWriteChar(" ");
1122
1123 xmlBufferWriteChar("<");
1124 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1125 xmlBufferWriteCHAR(cur->ns->prefix);
1126 xmlBufferWriteChar(":");
1127 }
1128
1129 xmlBufferWriteCHAR(cur->name);
1130 if (cur->nsDef)
1131 xmlNsListDump(cur->nsDef);
1132 if (cur->properties != NULL)
1133 xmlAttrListDump(doc, cur->properties);
1134
1135 if ((cur->content == NULL) && (cur->childs == NULL)) {
1136 xmlBufferWriteChar("/>\n");
1137 return;
1138 }
1139 xmlBufferWriteChar(">");
1140 if (cur->content != NULL)
1141 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1142 if (cur->childs != NULL) {
1143 xmlBufferWriteChar("\n");
1144 xmlNodeListDump(doc, cur->childs, level + 1);
1145 if (xmlIndentTreeOutput)
1146 for (i = 0;i < level;i++)
1147 xmlBufferWriteChar(" ");
1148 }
1149 xmlBufferWriteChar("</");
1150 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1151 xmlBufferWriteCHAR(cur->ns->prefix);
1152 xmlBufferWriteChar(":");
1153 }
1154
1155 xmlBufferWriteCHAR(cur->name);
1156 xmlBufferWriteChar(">\n");
1157}
1158
1159/*
1160 * Dump an XML document
1161 */
1162static void xmlDocContentDump(xmlDocPtr cur) {
1163 if (oldXMLWDcompatibility)
1164 xmlBufferWriteChar("<?XML version=\"");
1165 else
1166 xmlBufferWriteChar("<?xml version=\"");
1167 xmlBufferWriteCHAR(cur->version);
1168 xmlBufferWriteChar("\"");
1169 if (cur->encoding != NULL) {
1170 xmlBufferWriteChar(" encoding=\"");
1171 xmlBufferWriteCHAR(cur->encoding);
1172 xmlBufferWriteChar("\"");
1173 }
1174 switch (cur->standalone) {
1175 case 0:
1176 xmlBufferWriteChar(" standalone=\"no\"");
1177 break;
1178 case 1:
1179 xmlBufferWriteChar(" standalone=\"yes\"");
1180 break;
1181 }
1182 xmlBufferWriteChar("?>\n");
1183 if ((cur->dtd != NULL) || (cur->entities != NULL))
1184 xmlDtdDump(cur);
1185 if (cur->root != NULL) {
1186 /* global namespace definitions, the old way */
1187 if (oldXMLWDcompatibility)
1188 xmlGlobalNsListDump(cur->oldNs);
1189 else
1190 xmlUpgradeOldNs(cur);
1191 xmlNodeDump(cur, cur->root, 0);
1192 }
1193}
1194
1195/*
1196 * Dump an XML document to memory.
1197 */
1198
1199void xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
1200 if (cur == NULL) {
1201 fprintf(stderr, "xmlDocDump : document == NULL\n");
1202 *mem = NULL;
1203 *size = 0;
1204 return;
1205 }
1206 buffer_index = 0;
1207 xmlDocContentDump(cur);
1208
1209 *mem = buffer;
1210 *size = buffer_index;
1211}
1212
1213/*
Daniel Veillard15a8df41998-09-24 19:15:06 +00001214 * Get/Set a document compression mode.
Daniel Veillard151b1b01998-09-23 00:49:46 +00001215 */
1216
Daniel Veillard15a8df41998-09-24 19:15:06 +00001217int xmlGetDocCompressMode (xmlDocPtr doc) {
1218 if (doc == NULL) return(-1);
1219 return(doc->compression);
1220}
1221
1222void xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
1223 if (doc == NULL) return;
1224 if (mode < 0) doc->compression = 0;
1225 else if (mode > 9) doc->compression = 9;
1226 else doc->compression = mode;
1227}
1228
1229/*
1230 * Get/Set the global compression mode
1231 */
Daniel Veillard151b1b01998-09-23 00:49:46 +00001232
1233int xmlGetCompressMode(void) {
1234 return(xmlCompressMode);
1235}
1236void xmlSetCompressMode(int mode) {
1237 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00001238 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00001239 else xmlCompressMode = mode;
1240}
1241
1242/*
Daniel Veillard260a68f1998-08-13 03:39:55 +00001243 * Dump an XML document to the given FD
1244 */
1245
1246void xmlDocDump(FILE *f, xmlDocPtr cur) {
1247 if (cur == NULL) {
1248 fprintf(stderr, "xmlDocDump : document == NULL\n");
1249 return;
1250 }
1251 buffer_index = 0;
1252 xmlDocContentDump(cur);
1253
1254 fwrite(buffer, sizeof(CHAR), buffer_index, f);
1255}
1256
Daniel Veillard151b1b01998-09-23 00:49:46 +00001257/*
1258 * Dump an XML document to a file.
1259 */
1260
1261int xmlSaveFile(const char *filename, xmlDocPtr cur) {
1262#ifdef HAVE_ZLIB_H
1263 gzFile zoutput = NULL;
1264 char mode[15];
1265#endif
1266 FILE *output;
1267 int ret;
1268
1269#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00001270 if ((cur->compression > 0) && (cur->compression <= 9)) {
1271 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00001272 zoutput = gzopen(filename, mode);
1273 }
1274 if (zoutput == NULL) {
1275#endif
1276 output = fopen(filename, "w");
1277 if (output == NULL) return(-1);
1278#ifdef HAVE_ZLIB_H
1279 }
1280#endif
1281
1282 /*
1283 * save the content to a temp buffer.
1284 */
1285 buffer_index = 0;
1286 xmlDocContentDump(cur);
1287
1288#ifdef HAVE_ZLIB_H
1289 if (zoutput != NULL) {
1290 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
1291 gzclose(zoutput);
1292 return(ret);
1293 }
1294#endif
1295 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
1296 fclose(output);
1297 return(ret * sizeof(CHAR));
1298}
1299
Daniel Veillard260a68f1998-08-13 03:39:55 +00001300/************************************************************************
1301 * *
1302 * Debug *
1303 * *
1304 ************************************************************************/
1305
1306#ifdef STANDALONE
1307int main(void) {
1308 xmlDocPtr doc;
1309 xmlNodePtr tree, subtree;
1310 xmlNsPtr ns1;
1311 xmlNsPtr ns2;
1312
1313 /*
1314 * build a fake XML document
1315 */
1316 doc = xmlNewDoc("1.0");
1317 ns1 = xmlNewNs(doc, "http://www.ietf.org/standards/dav/", "D");
1318 ns2 = xmlNewNs(doc, "http://www.w3.com/standards/z39.50/", "Z");
1319 doc->root = xmlNewNode(ns1, "multistatus", NULL);
1320 tree = xmlNewChild(doc->root, NULL, "response", NULL);
1321 subtree = xmlNewChild(tree, NULL, "prop", NULL);
1322 xmlNewChild(subtree, ns2, "Authors", NULL);
1323 subtree = xmlNewChild(tree, NULL, "status", "HTTP/1.1 420 Method Failure");
1324 tree = xmlNewChild(doc->root, NULL, "response", NULL);
1325 subtree = xmlNewChild(tree, NULL, "prop", NULL);
1326 xmlNewChild(subtree, ns2, "Copyright-Owner", NULL);
1327 subtree = xmlNewChild(tree, NULL, "status", "HTTP/1.1 409 Conflict");
1328 tree = xmlNewChild(doc->root, NULL, "responsedescription",
1329 "Copyright Owner can not be deleted or altered");
1330
1331 /*
1332 * print it.
1333 */
1334 xmlDocDump(stdout, doc);
1335
1336 /*
1337 * free it.
1338 */
1339 xmlFreeDoc(doc);
1340 return(0);
1341}
1342#endif