blob: a477934be1826e1986bf2efd1a7421628985e7ca [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
Daniel Veillard97b58771998-10-20 06:14:16 +000036/**
37 * xmlUpgradeOldNs:
38 * @doc: a document pointer
39 *
40 * Upgrade old style Namespaces (PI) and move them to the root of the document.
Daniel Veillard260a68f1998-08-13 03:39:55 +000041 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000042void
43xmlUpgradeOldNs(xmlDocPtr doc) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000044 xmlNsPtr cur;
45
46 if ((doc == NULL) || (doc->oldNs == NULL)) return;
47 if (doc->root == NULL) {
48 fprintf(stderr, "xmlUpgradeOldNs: failed no root !\n");
49 return;
50 }
51
52 cur = doc->oldNs;
53 while (cur->next != NULL) {
54 cur->type = XML_LOCAL_NAMESPACE;
55 cur = cur->next;
56 }
57 cur->type = XML_LOCAL_NAMESPACE;
58 cur->next = doc->root->nsDef;
59 doc->root->nsDef = doc->oldNs;
60 doc->oldNs = NULL;
61}
62
Daniel Veillard97b58771998-10-20 06:14:16 +000063/**
64 * xmlNewNs:
65 * @node: the element carrying the namespace
66 * @href: the URI associated
67 * @prefix: the prefix for the namespace
68 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000069 * Creation of a new Namespace.
Daniel Veillard97b58771998-10-20 06:14:16 +000070 * return values: returns a new namespace pointer
Daniel Veillard260a68f1998-08-13 03:39:55 +000071 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000072xmlNsPtr
73xmlNewNs(xmlNodePtr node, const CHAR *href, const CHAR *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000074 xmlNsPtr cur;
75
76 if (href == NULL) {
77 fprintf(stderr, "xmlNewNs: href == NULL !\n");
78 return(NULL);
79 }
80
81 /*
82 * Allocate a new DTD and fill the fields.
83 */
84 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
85 if (cur == NULL) {
86 fprintf(stderr, "xmlNewNs : malloc failed\n");
87 return(NULL);
88 }
89
90 cur->type = XML_LOCAL_NAMESPACE;
91 if (href != NULL)
92 cur->href = xmlStrdup(href);
93 else
94 cur->href = NULL;
95 if (prefix != NULL)
96 cur->prefix = xmlStrdup(prefix);
97 else
98 cur->prefix = NULL;
99
100 /*
101 * Add it at the end to preserve parsing order ...
102 */
103 cur->next = NULL;
104 if (node != NULL) {
105 if (node->nsDef == NULL) {
106 node->nsDef = cur;
107 } else {
108 xmlNsPtr prev = node->nsDef;
109
110 while (prev->next != NULL) prev = prev->next;
111 prev->next = cur;
112 }
113 }
114
115 return(cur);
116}
117
Daniel Veillard97b58771998-10-20 06:14:16 +0000118/**
119 * xmlNewGlobalNs:
120 * @doc: the document carrying the namespace
121 * @href: the URI associated
122 * @prefix: the prefix for the namespace
123 *
124 * Creation of a Namespace, the old way using PI and without scoping, to AVOID.
125 * return values: returns a new namespace pointer
Daniel Veillard260a68f1998-08-13 03:39:55 +0000126 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000127xmlNsPtr
128xmlNewGlobalNs(xmlDocPtr doc, const CHAR *href, const CHAR *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000129 xmlNsPtr cur;
130
131 /*
132 * Allocate a new DTD and fill the fields.
133 */
134 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
135 if (cur == NULL) {
136 fprintf(stderr, "xmlNewNs : malloc failed\n");
137 return(NULL);
138 }
139
140 cur->type = XML_GLOBAL_NAMESPACE;
141 if (href != NULL)
142 cur->href = xmlStrdup(href);
143 else
144 cur->href = NULL;
145 if (prefix != NULL)
146 cur->prefix = xmlStrdup(prefix);
147 else
148 cur->prefix = NULL;
149
150 /*
151 * Add it at the end to preserve parsing order ...
152 */
153 cur->next = NULL;
154 if (doc != NULL) {
155 if (doc->oldNs == NULL) {
156 doc->oldNs = cur;
157 } else {
158 xmlNsPtr prev = doc->oldNs;
159
160 while (prev->next != NULL) prev = prev->next;
161 prev->next = cur;
162 }
163 }
164
165 return(cur);
166}
167
Daniel Veillard97b58771998-10-20 06:14:16 +0000168/**
169 * xmlSetNs:
170 * @node: a node in the document
171 * @ns: a namespace pointer
172 *
173 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000174 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000175void
176xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000177 if (node == NULL) {
178 fprintf(stderr, "xmlSetNs: node == NULL\n");
179 return;
180 }
181 node->ns = ns;
182}
183
Daniel Veillard97b58771998-10-20 06:14:16 +0000184/**
185 * xmlFreeNs:
186 * @cur: the namespace pointer
187 *
188 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000189 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000190void
191xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000192 if (cur == NULL) {
193 fprintf(stderr, "xmlFreeNs : ns == NULL\n");
194 return;
195 }
196 if (cur->href != NULL) free((char *) cur->href);
197 if (cur->prefix != NULL) free((char *) cur->prefix);
198 memset(cur, -1, sizeof(xmlNs));
199 free(cur);
200}
201
Daniel Veillard97b58771998-10-20 06:14:16 +0000202/**
203 * xmlFreeNsList:
204 * @cur: the first namespace pointer
205 *
206 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000207 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000208void
209xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000210 xmlNsPtr next;
211 if (cur == NULL) {
212 fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
213 return;
214 }
215 while (cur != NULL) {
216 next = cur->next;
217 xmlFreeNs(cur);
218 cur = next;
219 }
220}
221
Daniel Veillard97b58771998-10-20 06:14:16 +0000222/**
223 * xmlNewDtd:
224 * @doc: the document pointer
225 * @name: the DTD name
226 * @ExternalID: the external ID
227 * @SystemID: the system ID
228 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000229 * Creation of a new DTD.
Daniel Veillard97b58771998-10-20 06:14:16 +0000230 * return values: a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000231 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000232xmlDtdPtr
233xmlNewDtd(xmlDocPtr doc, const CHAR *name,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000234 const CHAR *ExternalID, const CHAR *SystemID) {
235 xmlDtdPtr cur;
236
237 if (doc->dtd != NULL) {
238 fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
239 /* !!! */ (char *) name, doc->name, /* !!! */ (char *)doc->dtd->name);
240 }
241
242 /*
243 * Allocate a new DTD and fill the fields.
244 */
245 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
246 if (cur == NULL) {
247 fprintf(stderr, "xmlNewNs : malloc failed\n");
248 return(NULL);
249 }
250
251 if (name != NULL)
252 cur->name = xmlStrdup(name);
253 else
254 cur->name = NULL;
255 if (ExternalID != NULL)
256 cur->ExternalID = xmlStrdup(ExternalID);
257 else
258 cur->ExternalID = NULL;
259 if (SystemID != NULL)
260 cur->SystemID = xmlStrdup(SystemID);
261 else
262 cur->SystemID = NULL;
263 cur->elements = NULL;
264 cur->entities = NULL;
265 doc->dtd = cur;
266
267 return(cur);
268}
269
Daniel Veillard97b58771998-10-20 06:14:16 +0000270/**
271 * xmlFreeDtd:
272 * @cur: the DTD structure to free up
273 *
274 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000275 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000276void
277xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000278 if (cur == NULL) {
279 fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
280 return;
281 }
282 if (cur->name != NULL) free((char *) cur->name);
283 if (cur->SystemID != NULL) free((char *) cur->SystemID);
284 if (cur->ExternalID != NULL) free((char *) cur->ExternalID);
285 if (cur->elements != NULL)
286 fprintf(stderr, "xmlFreeDtd: cur->elements != NULL !!! \n");
287 if (cur->entities != NULL)
288 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
289 memset(cur, -1, sizeof(xmlDtd));
290 free(cur);
291}
292
Daniel Veillard97b58771998-10-20 06:14:16 +0000293/**
294 * xmlNewDoc:
295 * @version: CHAR string giving the version of XML "1.0"
296 *
297 * Create a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000298 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000299xmlDocPtr
300xmlNewDoc(const CHAR *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000301 xmlDocPtr cur;
302
303 if (version == NULL) {
304 fprintf(stderr, "xmlNewDoc : version == NULL\n");
305 return(NULL);
306 }
307
308 /*
309 * Allocate a new document and fill the fields.
310 */
311 cur = (xmlDocPtr) malloc(sizeof(xmlDoc));
312 if (cur == NULL) {
313 fprintf(stderr, "xmlNewDoc : malloc failed\n");
314 return(NULL);
315 }
316
Daniel Veillard33942841998-10-18 19:12:41 +0000317 cur->type = XML_DOCUMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000318 cur->version = xmlStrdup(version);
319 cur->name = NULL;
320 cur->root = NULL;
321 cur->dtd = NULL;
322 cur->oldNs = NULL;
323 cur->encoding = NULL;
324 cur->entities = NULL;
325 cur->standalone = -1;
Daniel Veillard15a8df41998-09-24 19:15:06 +0000326 cur->compression = xmlCompressMode;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000327#ifndef WITHOUT_CORBA
328 cur->_private = NULL;
329 cur->vepv = NULL;
330#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000331 return(cur);
332}
333
Daniel Veillard97b58771998-10-20 06:14:16 +0000334/**
335 * xmlFreeDoc:
336 * @cur: pointer to the document
337 * @:
338 *
339 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000340 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000341void
342xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000343 if (cur == NULL) {
344 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
345 return;
346 }
347 free((char *) cur->version);
348 if (cur->name != NULL) free((char *) cur->name);
349 if (cur->encoding != NULL) free((char *) cur->encoding);
350 if (cur->root != NULL) xmlFreeNode(cur->root);
351 if (cur->dtd != NULL) xmlFreeDtd(cur->dtd);
352 if (cur->entities != NULL)
353 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
354 memset(cur, -1, sizeof(xmlDoc));
355 free(cur);
356}
357
Daniel Veillard97b58771998-10-20 06:14:16 +0000358/**
Daniel Veillard16253641998-10-28 22:58:05 +0000359 * xmlStringLenGetNodeList:
360 * @doc: the document
361 * @value: the value of the text
362 * @int len: the length of the string value
363 *
364 * Parse the value string and build the node list associated. Should
365 * produce a flat tree with only TEXTs and ENTITY_REFs.
366 * return values: a pointer to the first child
367 */
368xmlNodePtr
369xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
370 xmlNodePtr ret = NULL, last = NULL;
371 xmlNodePtr node;
372 CHAR *val;
373 const CHAR *cur = value;
374 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000375 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000376
377 if (value == NULL) return(NULL);
378
379 q = cur;
380 while ((*cur != 0) && (cur - value < len)) {
381 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000382 /*
383 * Save the current text.
384 */
Daniel Veillard16253641998-10-28 22:58:05 +0000385 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000386 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
387 xmlNodeAddContentLen(last, q, cur - q);
388 } else {
389 node = xmlNewDocTextLen(doc, q, cur - q);
390 if (node == NULL) return(ret);
391 if (last == NULL)
392 last = ret = node;
393 else {
394 last->next = node;
395 node->prev = last;
396 last = node;
397 }
Daniel Veillard16253641998-10-28 22:58:05 +0000398 }
399 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000400 /*
401 * Read the entity string
402 */
Daniel Veillard16253641998-10-28 22:58:05 +0000403 cur++;
404 q = cur;
405 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
406 if ((*cur == 0) || (cur - value >= len)) {
407 fprintf(stderr,
408 "xmlStringGetNodeList: unterminated entity %30s\n", q);
409 return(ret);
410 }
411 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000412 /*
413 * Predefined entities don't generate nodes
414 */
Daniel Veillard16253641998-10-28 22:58:05 +0000415 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000416 ent = xmlGetDocEntity(doc, val);
417 if ((ent != NULL) &&
418 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
419 if (last == NULL) {
420 node = xmlNewDocText(doc, ent->content);
421 last = ret = node;
422 } else
423 xmlNodeAddContent(last, ent->content);
424
425 } else {
426 /*
427 * Create a new REFERENCE_REF node
428 */
429 node = xmlNewReference(doc, val);
430 if (node == NULL) return(ret);
431 if (last == NULL)
432 last = ret = node;
433 else {
434 last->next = node;
435 node->prev = last;
436 last = node;
437 }
Daniel Veillard16253641998-10-28 22:58:05 +0000438 }
439 free(val);
440 }
441 cur++;
442 q = cur;
443 } else
444 cur++;
445 }
446 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000447 /*
448 * Handle the last piece of text.
449 */
450 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
451 xmlNodeAddContentLen(last, q, cur - q);
452 } else {
453 node = xmlNewDocTextLen(doc, q, cur - q);
454 if (node == NULL) return(ret);
455 if (last == NULL)
456 last = ret = node;
457 else {
458 last->next = node;
459 node->prev = last;
460 last = node;
461 }
Daniel Veillard16253641998-10-28 22:58:05 +0000462 }
463 }
464 return(ret);
465}
466
467/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000468 * xmlStringGetNodeList:
469 * @doc: the document
470 * @value: the value of the attribute
471 *
472 * Parse the value string and build the node list associated. Should
473 * produce a flat tree with only TEXTs and ENTITY_REFs.
474 * return values: a pointer to the first child
475 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000476xmlNodePtr
477xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000478 xmlNodePtr ret = NULL, last = NULL;
479 xmlNodePtr node;
480 CHAR *val;
481 const CHAR *cur = value;
482 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000483 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000484
485 if (value == NULL) return(NULL);
486
487 q = cur;
488 while (*cur != 0) {
489 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000490 /*
491 * Save the current text.
492 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000493 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000494 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
495 xmlNodeAddContentLen(last, q, cur - q);
496 } else {
497 node = xmlNewDocTextLen(doc, q, cur - q);
498 if (node == NULL) return(ret);
499 if (last == NULL)
500 last = ret = node;
501 else {
502 last->next = node;
503 node->prev = last;
504 last = node;
505 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000506 }
507 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000508 /*
509 * Read the entity string
510 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000511 cur++;
512 q = cur;
513 while ((*cur != 0) && (*cur != ';')) cur++;
514 if (*cur == 0) {
515 fprintf(stderr,
516 "xmlStringGetNodeList: unterminated entity %30s\n", q);
517 return(ret);
518 }
519 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000520 /*
521 * Predefined entities don't generate nodes
522 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000523 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000524 ent = xmlGetDocEntity(doc, val);
525 if ((ent != NULL) &&
526 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
527 if (last == NULL) {
528 node = xmlNewDocText(doc, ent->content);
529 last = ret = node;
530 } else
531 xmlNodeAddContent(last, ent->content);
532
533 } else {
534 /*
535 * Create a new REFERENCE_REF node
536 */
537 val = xmlStrndup(q, cur - q);
538 node = xmlNewReference(doc, val);
539 if (node == NULL) return(ret);
540 if (last == NULL)
541 last = ret = node;
542 else {
543 last->next = node;
544 node->prev = last;
545 last = node;
546 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000547 }
548 free(val);
549 }
550 cur++;
551 q = cur;
552 } else
553 cur++;
554 }
555 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000556 /*
557 * Handle the last piece of text.
558 */
559 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
560 xmlNodeAddContentLen(last, q, cur - q);
561 } else {
562 node = xmlNewDocTextLen(doc, q, cur - q);
563 if (node == NULL) return(ret);
564 if (last == NULL)
565 last = ret = node;
566 else {
567 last->next = node;
568 node->prev = last;
569 last = node;
570 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000571 }
572 }
573 return(ret);
574}
575
576/**
577 * xmlNodeListGetString:
578 * @doc: the document
579 * @list: a Node list
580 * @inLine: should we replace entity contents or show their external form
581 *
582 * Returns the string equivalent to the text contained in the Node list
583 * made of TEXTs and ENTITY_REFs
584 * return values: a pointer to the string copy, the calller must free it.
585 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000586CHAR *
587xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000588 xmlNodePtr node = list;
589 CHAR *ret = NULL;
590 xmlEntityPtr ent;
591
592 if (list == NULL) return(NULL);
593
594 while (node != NULL) {
595 if (node->type == XML_TEXT_NODE) {
596 if (inLine)
597 ret = xmlStrcat(ret, node->content);
598 else
599 ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
600 } else if (node->type == XML_ENTITY_REF_NODE) {
601 if (inLine) {
602 ent = xmlGetDocEntity(doc, node->name);
603 if (ent != NULL)
604 ret = xmlStrcat(ret, ent->content);
605 else
606 ret = xmlStrcat(ret, node->content);
607 } else {
608 CHAR buf[2];
609 buf[0] = '&'; buf[1] = 0;
610 ret = xmlStrncat(ret, buf, 1);
611 ret = xmlStrcat(ret, node->name);
612 buf[0] = ';'; buf[1] = 0;
613 ret = xmlStrncat(ret, buf, 1);
614 }
615 }
616#if 0
617 else {
618 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
619 node->type);
620 }
621#endif
622 node = node->next;
623 }
624 return(ret);
625}
626
627/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000628 * xmlNewProp:
629 * @node: the holding node
630 * @name: the name of the attribute
631 * @value: the value of the attribute
632 *
633 * Create a new property carried by a node.
634 * return values: a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000635 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000636xmlAttrPtr
637xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000638 xmlAttrPtr cur;
639
640 if (name == NULL) {
641 fprintf(stderr, "xmlNewProp : name == NULL\n");
642 return(NULL);
643 }
644
645 /*
646 * Allocate a new property and fill the fields.
647 */
648 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
649 if (cur == NULL) {
650 fprintf(stderr, "xmlNewProp : malloc failed\n");
651 return(NULL);
652 }
653
Daniel Veillard33942841998-10-18 19:12:41 +0000654 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000655 cur->node = node;
656 cur->name = xmlStrdup(name);
657 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +0000658 cur->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000659 else
Daniel Veillardccb09631998-10-27 06:21:04 +0000660 cur->val = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000661#ifndef WITHOUT_CORBA
662 cur->_private = NULL;
663 cur->vepv = NULL;
664#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000665
666 /*
667 * Add it at the end to preserve parsing order ...
668 */
669 cur->next = NULL;
670 if (node != NULL) {
671 if (node->properties == NULL) {
672 node->properties = cur;
673 } else {
674 xmlAttrPtr prev = node->properties;
675
676 while (prev->next != NULL) prev = prev->next;
677 prev->next = cur;
678 }
679 }
680 return(cur);
681}
682
Daniel Veillard97b58771998-10-20 06:14:16 +0000683/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000684 * xmlNewDocProp:
685 * @doc: the document
686 * @name: the name of the attribute
687 * @value: the value of the attribute
688 *
689 * Create a new property carried by a document.
690 * return values: a pointer to the attribute
691 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000692xmlAttrPtr
693xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000694 xmlAttrPtr cur;
695
696 if (name == NULL) {
697 fprintf(stderr, "xmlNewProp : name == NULL\n");
698 return(NULL);
699 }
700
701 /*
702 * Allocate a new property and fill the fields.
703 */
704 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
705 if (cur == NULL) {
706 fprintf(stderr, "xmlNewProp : malloc failed\n");
707 return(NULL);
708 }
709
710 cur->type = XML_ATTRIBUTE_NODE;
711 cur->node = NULL;
712 cur->name = xmlStrdup(name);
713 if (value != NULL)
714 cur->val = xmlStringGetNodeList(doc, value);
715 else
716 cur->val = NULL;
717#ifndef WITHOUT_CORBA
718 cur->_private = NULL;
719 cur->vepv = NULL;
720#endif
721
722 cur->next = NULL;
723 return(cur);
724}
725
726/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000727 * xmlFreePropList:
728 * @cur: the first property in the list
729 *
730 * Free a property and all its siblings, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000731 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000732void
733xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000734 xmlAttrPtr next;
735 if (cur == NULL) {
736 fprintf(stderr, "xmlFreePropList : property == NULL\n");
737 return;
738 }
739 while (cur != NULL) {
740 next = cur->next;
741 xmlFreeProp(cur);
742 cur = next;
743 }
744}
745
Daniel Veillard97b58771998-10-20 06:14:16 +0000746/**
747 * xmlFreeProp:
748 * @cur: the first property in the list
749 *
750 * Free one property, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000751 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000752void
753xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000754 if (cur == NULL) {
755 fprintf(stderr, "xmlFreeProp : property == NULL\n");
756 return;
757 }
758 if (cur->name != NULL) free((char *) cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +0000759 if (cur->val != NULL) xmlFreeNodeList(cur->val);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000760 memset(cur, -1, sizeof(xmlAttr));
761 free(cur);
762}
763
Daniel Veillard97b58771998-10-20 06:14:16 +0000764/**
765 * xmlNewNode:
766 * @ns: namespace if any
767 * @name: the node name
768 * @content: the text content if any
769 *
770 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +0000771 * If content is non NULL, a child list containing the TEXTs and
772 * ENTITY_REFs node will be created.
Daniel Veillard97b58771998-10-20 06:14:16 +0000773 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000774 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000775xmlNodePtr
776xmlNewNode(xmlNsPtr ns, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000777 xmlNodePtr cur;
778
779 if (name == NULL) {
780 fprintf(stderr, "xmlNewNode : name == NULL\n");
781 return(NULL);
782 }
783
784 /*
785 * Allocate a new node and fill the fields.
786 */
787 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
788 if (cur == NULL) {
789 fprintf(stderr, "xmlNewNode : malloc failed\n");
790 return(NULL);
791 }
792
Daniel Veillard33942841998-10-18 19:12:41 +0000793 cur->type = XML_ELEMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000794 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000795 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000796 cur->next = NULL;
797 cur->prev = NULL;
798 cur->childs = NULL;
799 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000800 cur->name = xmlStrdup(name);
801 cur->ns = ns;
802 cur->nsDef = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000803 cur->content = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000804#ifndef WITHOUT_CORBA
805 cur->_private = NULL;
806 cur->vepv = NULL;
807#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000808 return(cur);
809}
810
Daniel Veillard97b58771998-10-20 06:14:16 +0000811/**
812 * xmlNewDocNode:
813 * @doc: the document
814 * @ns: namespace if any
815 * @name: the node name
816 * @content: the text content if any
817 *
818 * Creation of a new node element within a document. @ns and @content
819 * are optionnal (NULL).
820 * return values: a pointer to the new node object.
821 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000822xmlNodePtr
823xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard0bef1311998-10-14 02:36:47 +0000824 const CHAR *name, CHAR *content) {
825 xmlNodePtr cur;
826
Daniel Veillardccb09631998-10-27 06:21:04 +0000827 cur = xmlNewNode(ns, name);
828 if (cur != NULL) {
829 cur->doc = doc;
830 if (content != NULL)
831 cur->childs = xmlStringGetNodeList(doc, content);
832 }
Daniel Veillard0bef1311998-10-14 02:36:47 +0000833 return(cur);
834}
835
836
Daniel Veillard97b58771998-10-20 06:14:16 +0000837/**
838 * xmlNewText:
839 * @content: the text content
840 *
841 * Creation of a new text node.
842 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000843 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000844xmlNodePtr
845xmlNewText(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000846 xmlNodePtr cur;
847
848 /*
849 * Allocate a new node and fill the fields.
850 */
851 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
852 if (cur == NULL) {
853 fprintf(stderr, "xmlNewText : malloc failed\n");
854 return(NULL);
855 }
856
Daniel Veillard33942841998-10-18 19:12:41 +0000857 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000858 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000859 cur->parent = NULL;
860 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000861 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000862 cur->childs = NULL;
863 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000864 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000865 cur->name = xmlStrdup(xmlStringText);
866 cur->ns = NULL;
867 cur->nsDef = NULL;
868 if (content != NULL)
869 cur->content = xmlStrdup(content);
870 else
871 cur->content = NULL;
872 return(cur);
873}
874
Daniel Veillard97b58771998-10-20 06:14:16 +0000875/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000876 * xmlNewReference:
877 * @doc: the document
878 * @name: the reference name, or the reference string with & and ;
879 *
880 * Creation of a new reference node.
881 * return values: a pointer to the new node object.
882 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000883xmlNodePtr
884xmlNewReference(xmlDocPtr doc, const CHAR *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000885 xmlNodePtr cur;
886 xmlEntityPtr ent;
887
888 /*
889 * Allocate a new node and fill the fields.
890 */
891 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
892 if (cur == NULL) {
893 fprintf(stderr, "xmlNewText : malloc failed\n");
894 return(NULL);
895 }
896
897 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillard10c6a8f1998-10-28 01:00:12 +0000898 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +0000899 cur->parent = NULL;
900 cur->next = NULL;
901 cur->prev = NULL;
902 cur->childs = NULL;
903 cur->properties = NULL;
904 if (name[0] == '&') {
905 int len;
906 name++;
907 len = xmlStrlen(name);
908 if (name[len - 1] == ';')
909 cur->name = xmlStrndup(name, len - 1);
910 else
911 cur->name = xmlStrndup(name, len);
912 } else
913 cur->name = xmlStrdup(name);
914 cur->ns = NULL;
915 cur->nsDef = NULL;
916
917 ent = xmlGetDocEntity(doc, cur->name);
918 if (ent != NULL)
919 cur->content = ent->content;
920 else
921 cur->content = NULL;
922 return(cur);
923}
924
925/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000926 * xmlNewDocText:
927 * @doc: the document
928 * @content: the text content
929 *
930 * Creation of a new text node within a document.
931 * return values: a pointer to the new node object.
932 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000933xmlNodePtr
934xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +0000935 xmlNodePtr cur;
936
937 cur = xmlNewText(content);
938 if (cur != NULL) cur->doc = doc;
939 return(cur);
940}
941
Daniel Veillard97b58771998-10-20 06:14:16 +0000942/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000943 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +0000944 * @content: the text content
945 * @len: the text len.
946 *
947 * Creation of a new text node with an extra parameter for the content's lenght
948 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000949 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000950xmlNodePtr
951xmlNewTextLen(const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000952 xmlNodePtr cur;
953
954 /*
955 * Allocate a new node and fill the fields.
956 */
957 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
958 if (cur == NULL) {
959 fprintf(stderr, "xmlNewText : malloc failed\n");
960 return(NULL);
961 }
962
Daniel Veillard33942841998-10-18 19:12:41 +0000963 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000964 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000965 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000966 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000967 cur->next = NULL;
968 cur->childs = NULL;
969 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000970 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000971 cur->name = xmlStrdup(xmlStringText);
972 cur->ns = NULL;
973 cur->nsDef = NULL;
974 if (content != NULL)
975 cur->content = xmlStrndup(content, len);
976 else
977 cur->content = NULL;
978 return(cur);
979}
980
Daniel Veillard97b58771998-10-20 06:14:16 +0000981/**
982 * xmlNewDocTextLen:
983 * @doc: the document
984 * @content: the text content
985 * @len: the text len.
986 *
987 * Creation of a new text node with an extra content lenght parameter. The
988 * text node pertain to a given document.
989 * return values: a pointer to the new node object.
990 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000991xmlNodePtr
992xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +0000993 xmlNodePtr cur;
994
995 cur = xmlNewTextLen(content, len);
996 if (cur != NULL) cur->doc = doc;
997 return(cur);
998}
999
Daniel Veillard97b58771998-10-20 06:14:16 +00001000/**
1001 * xmlNewComment:
1002 * @content: the comment content
1003 *
1004 * Creation of a new node containing a comment.
1005 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001006 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001007xmlNodePtr
1008xmlNewComment(CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001009 xmlNodePtr cur;
1010
1011 /*
1012 * Allocate a new node and fill the fields.
1013 */
1014 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1015 if (cur == NULL) {
1016 fprintf(stderr, "xmlNewComment : malloc failed\n");
1017 return(NULL);
1018 }
1019
Daniel Veillard33942841998-10-18 19:12:41 +00001020 cur->type = XML_COMMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001021 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001022 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001023 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001024 cur->next = NULL;
1025 cur->childs = NULL;
1026 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001027 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001028 cur->name = xmlStrdup(xmlStringText);
1029 cur->ns = NULL;
1030 cur->nsDef = NULL;
1031 if (content != NULL)
1032 cur->content = xmlStrdup(content);
1033 else
1034 cur->content = NULL;
1035 return(cur);
1036}
1037
Daniel Veillard97b58771998-10-20 06:14:16 +00001038/**
1039 * xmlNewComment:
1040 * @doc: the document
1041 * @content: the comment content
1042 *
1043 * Creation of a new node containing a commentwithin a document.
1044 * return values: a pointer to the new node object.
1045 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001046xmlNodePtr
1047xmlNewDocComment(xmlDocPtr doc, CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001048 xmlNodePtr cur;
1049
1050 cur = xmlNewComment(content);
1051 if (cur != NULL) cur->doc = doc;
1052 return(cur);
1053}
1054
Daniel Veillard97b58771998-10-20 06:14:16 +00001055/**
1056 * xmlNewChild:
1057 * @parent: the parent node
1058 * @ns: a namespace if any
1059 * @name: the name of the child
1060 * @content: the content of the child if any.
1061 *
1062 *
1063 * Creation of a new child element, added at the end of @parent childs list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001064 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1065 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard97b58771998-10-20 06:14:16 +00001066 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001067 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001068xmlNodePtr
1069xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001070 const CHAR *name, CHAR *content) {
1071 xmlNodePtr cur, prev;
1072
1073 if (parent == NULL) {
1074 fprintf(stderr, "xmlNewChild : parent == NULL\n");
1075 return(NULL);
1076 }
1077
1078 if (name == NULL) {
1079 fprintf(stderr, "xmlNewChild : name == NULL\n");
1080 return(NULL);
1081 }
1082
1083 /*
1084 * Allocate a new node
1085 */
1086 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001087 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001088 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001089 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001090 if (cur == NULL) return(NULL);
1091
1092 /*
1093 * add the new element at the end of the childs list.
1094 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001095 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001096 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001097 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001098 if (parent->childs == NULL) {
1099 parent->childs = cur;
1100 } else {
1101 prev = parent->childs;
1102 while (prev->next != NULL) prev = prev->next;
1103 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001104 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001105 }
1106
1107 return(cur);
1108}
1109
Daniel Veillard97b58771998-10-20 06:14:16 +00001110/**
1111 * xmlAddChild:
1112 * @parent: the parent node
1113 * @cur: the child node
1114 *
1115 * Add a new child element, to @parent, at the end of the child list.
1116 * return values: the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001117 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001118xmlNodePtr
1119xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001120 xmlNodePtr prev;
1121
1122 if (parent == NULL) {
1123 fprintf(stderr, "xmladdChild : parent == NULL\n");
1124 return(NULL);
1125 }
1126
1127 if (cur == NULL) {
1128 fprintf(stderr, "xmladdChild : child == NULL\n");
1129 return(NULL);
1130 }
1131
Daniel Veillard0bef1311998-10-14 02:36:47 +00001132 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1133 (cur->doc != parent->doc)) {
1134 fprintf(stderr, "Elements moved to a different document\n");
1135 }
1136
Daniel Veillard260a68f1998-08-13 03:39:55 +00001137 /*
1138 * add the new element at the end of the childs list.
1139 */
1140 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001141 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillardccb09631998-10-27 06:21:04 +00001142 /*
1143 * Handle the case where parent->content != NULL, in that case it will
1144 * create a intermediate TEXT node.
1145 */
1146 if (parent->content != NULL) {
1147 xmlNodePtr text;
1148
1149 text = xmlNewDocText(parent->doc, parent->content);
1150 if (text != NULL) {
1151 text->next = parent->childs;
1152 if (text->next != NULL)
1153 text->next->prev = text;
1154 parent->childs = text;
1155 free(parent->content);
1156 parent->content = NULL;
1157 }
1158 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001159 if (parent->childs == NULL) {
1160 parent->childs = cur;
1161 } else {
1162 prev = parent->childs;
1163 while (prev->next != NULL) prev = prev->next;
1164 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001165 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001166 }
1167
1168 return(cur);
1169}
1170
Daniel Veillard97b58771998-10-20 06:14:16 +00001171/**
1172 * xmlGetLastChild:
1173 * @parent: the parent node
1174 *
1175 * Search the last child of a node.
1176 * return values: the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001177 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001178xmlNodePtr
1179xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001180 xmlNodePtr last;
1181
1182 if (parent == NULL) {
1183 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1184 return(NULL);
1185 }
1186
1187 /*
1188 * add the new element at the end of the childs list.
1189 */
1190 if (parent->childs == NULL) {
1191 return(NULL);
1192 } else {
1193 last = parent->childs;
1194 while (last->next != NULL) last = last->next;
1195 }
1196 return(last);
1197}
1198
Daniel Veillard97b58771998-10-20 06:14:16 +00001199/**
1200 * xmlFreeNodeList:
1201 * @cur: the first node in the list
1202 *
1203 * Free a node and all its siblings, this is a recursive behaviour, all
1204 * the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001205 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001206void
1207xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001208 xmlNodePtr next;
1209 if (cur == NULL) {
1210 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1211 return;
1212 }
1213 while (cur != NULL) {
1214 next = cur->next;
1215 xmlFreeNode(cur);
1216 cur = next;
1217 }
1218}
1219
Daniel Veillard97b58771998-10-20 06:14:16 +00001220/**
1221 * xmlFreeNode:
1222 * @cur: the node
1223 *
1224 * Free a node, this is a recursive behaviour, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001225 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001226void
1227xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001228 if (cur == NULL) {
1229 fprintf(stderr, "xmlFreeNode : node == NULL\n");
1230 return;
1231 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001232 cur->doc = NULL;
1233 cur->parent = NULL;
1234 cur->next = NULL;
1235 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001236 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
Daniel Veillardccb09631998-10-27 06:21:04 +00001237 if (cur->properties != NULL) xmlFreePropList(cur->properties);
1238 if (cur->type != XML_ENTITY_REF_NODE)
1239 if (cur->content != NULL) free(cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001240 if (cur->name != NULL) free((char *) cur->name);
1241 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1242 memset(cur, -1, sizeof(xmlNode));
1243 free(cur);
1244}
1245
Daniel Veillard16253641998-10-28 22:58:05 +00001246/**
1247 * xmlUnlinkNode:
1248 * @cur: the node
1249 *
1250 * Unlink a node from it's current context, the node is not freed
1251 */
1252void
1253xmlUnlinkNode(xmlNodePtr cur) {
1254 if (cur == NULL) {
1255 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1256 return;
1257 }
1258 if ((cur->parent != NULL) && (cur->parent->childs == cur))
1259 cur->parent->childs = cur->next;
1260 if (cur->next != NULL)
1261 cur->next->prev = cur->prev;
1262 if (cur->prev != NULL)
1263 cur->prev->next = cur->next;
1264 cur->next = cur->prev = NULL;
1265 cur->parent = NULL;
1266}
1267
Daniel Veillard260a68f1998-08-13 03:39:55 +00001268/************************************************************************
1269 * *
1270 * Content access functions *
1271 * *
1272 ************************************************************************/
1273
Daniel Veillard97b58771998-10-20 06:14:16 +00001274/**
Daniel Veillard16253641998-10-28 22:58:05 +00001275 * xmlNodeGetContent:
1276 * @cur: the node being read
1277 *
1278 * Read the value of a node, this can be either the text carried
1279 * directly by this node if it's a TEXT node or the aggregate string
1280 * of the values carried by this node child's (TEXT and ENTITY_REF).
1281 * Entity references are substitued.
1282 * Return value: a new CHAR * or NULL if no content is available.
1283 */
1284CHAR *
1285xmlNodeGetContent(xmlNodePtr cur) {
1286 if (cur == NULL) return(NULL);
1287 switch (cur->type) {
1288 case XML_DOCUMENT_FRAG_NODE:
1289 case XML_ELEMENT_NODE:
1290 return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1291 break;
1292 case XML_ATTRIBUTE_NODE:
1293 case XML_CDATA_SECTION_NODE:
1294 case XML_ENTITY_REF_NODE:
1295 case XML_ENTITY_NODE:
1296 case XML_PI_NODE:
1297 case XML_COMMENT_NODE:
1298 case XML_DOCUMENT_NODE:
1299 case XML_DOCUMENT_TYPE_NODE:
1300 case XML_NOTATION_NODE:
1301 return(NULL);
1302 case XML_TEXT_NODE:
1303 if (cur->content != NULL)
1304 return(xmlStrdup(cur->content));
1305 return(NULL);
1306 }
1307 return(NULL);
1308}
1309
1310/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001311 * xmlNodeSetContent:
1312 * @cur: the node being modified
1313 * @content: the new value of the content
1314 *
1315 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001316 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001317void
1318xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001319 if (cur == NULL) {
1320 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1321 return;
1322 }
Daniel Veillard16253641998-10-28 22:58:05 +00001323 switch (cur->type) {
1324 case XML_DOCUMENT_FRAG_NODE:
1325 case XML_ELEMENT_NODE:
1326 if (cur->content != NULL) {
1327 free(cur->content);
1328 cur->content = NULL;
1329 }
1330 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1331 cur->childs = xmlStringGetNodeList(cur->doc, content);
1332 break;
1333 case XML_ATTRIBUTE_NODE:
1334 break;
1335 case XML_TEXT_NODE:
1336 case XML_CDATA_SECTION_NODE:
1337 case XML_ENTITY_REF_NODE:
1338 case XML_ENTITY_NODE:
1339 case XML_PI_NODE:
1340 case XML_COMMENT_NODE:
1341 if (cur->content != NULL) free(cur->content);
1342 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1343 if (content != NULL)
1344 cur->content = xmlStrdup(content);
1345 else
1346 cur->content = NULL;
1347 case XML_DOCUMENT_NODE:
1348 case XML_DOCUMENT_TYPE_NODE:
1349 break;
1350 case XML_NOTATION_NODE:
1351 break;
1352 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001353}
1354
Daniel Veillard97b58771998-10-20 06:14:16 +00001355/**
1356 * xmlNodeSetContentLen:
1357 * @cur: the node being modified
1358 * @content: the new value of the content
1359 * @len: the size of @content
1360 *
1361 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001362 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001363void
1364xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001365 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001366 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001367 return;
1368 }
Daniel Veillard16253641998-10-28 22:58:05 +00001369 switch (cur->type) {
1370 case XML_DOCUMENT_FRAG_NODE:
1371 case XML_ELEMENT_NODE:
1372 if (cur->content != NULL) {
1373 free(cur->content);
1374 cur->content = NULL;
1375 }
1376 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1377 cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
1378 break;
1379 case XML_ATTRIBUTE_NODE:
1380 break;
1381 case XML_TEXT_NODE:
1382 case XML_CDATA_SECTION_NODE:
1383 case XML_ENTITY_REF_NODE:
1384 case XML_ENTITY_NODE:
1385 case XML_PI_NODE:
1386 case XML_COMMENT_NODE:
1387 if (cur->content != NULL) free(cur->content);
1388 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1389 if (content != NULL)
1390 cur->content = xmlStrndup(content, len);
1391 else
1392 cur->content = NULL;
1393 case XML_DOCUMENT_NODE:
1394 case XML_DOCUMENT_TYPE_NODE:
1395 break;
1396 case XML_NOTATION_NODE:
1397 if (cur->content != NULL) free(cur->content);
1398 if (content != NULL)
1399 cur->content = xmlStrndup(content, len);
1400 else
1401 cur->content = NULL;
1402 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001403 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001404}
1405
Daniel Veillard97b58771998-10-20 06:14:16 +00001406/**
1407 * xmlNodeAddContentLen:
1408 * @cur: the node being modified
1409 * @content: extra content
1410 * @len: the size of @content
1411 *
1412 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001413 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001414void
1415xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001416 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001417 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1418 return;
1419 }
1420 if (len <= 0) return;
1421 switch (cur->type) {
1422 case XML_DOCUMENT_FRAG_NODE:
1423 case XML_ELEMENT_NODE: {
1424 xmlNodePtr last = NULL, new;
1425
1426 if (cur->childs != NULL) {
1427 last = cur->childs;
1428 while (last->next != NULL) last = last->next;
1429 } else {
1430 if (cur->content != NULL) {
1431 cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
1432 free(cur->content);
1433 cur->content = NULL;
1434 if (cur->childs != NULL) {
1435 last = cur->childs;
1436 while (last->next != NULL) last = last->next;
1437 }
1438 }
1439 }
1440 new = xmlStringLenGetNodeList(cur->doc, content, len);
1441 if (new != NULL) {
1442 xmlAddChild(cur, new);
1443 if ((last != NULL) && (last->next == new))
1444 xmlTextMerge(last, new);
1445 }
1446 break;
1447 }
1448 case XML_ATTRIBUTE_NODE:
1449 break;
1450 case XML_TEXT_NODE:
1451 case XML_CDATA_SECTION_NODE:
1452 case XML_ENTITY_REF_NODE:
1453 case XML_ENTITY_NODE:
1454 case XML_PI_NODE:
1455 case XML_COMMENT_NODE:
1456 if (content != NULL)
1457 cur->content = xmlStrncat(cur->content, content, len);
1458 case XML_DOCUMENT_NODE:
1459 case XML_DOCUMENT_TYPE_NODE:
1460 break;
1461 case XML_NOTATION_NODE:
1462 if (content != NULL)
1463 cur->content = xmlStrncat(cur->content, content, len);
1464 break;
1465 }
1466}
1467
1468/**
1469 * xmlNodeAddContent:
1470 * @cur: the node being modified
1471 * @content: extra content
1472 *
1473 * Append the extra substring to the node content.
1474 */
1475void
1476xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1477 int len;
1478
1479 if (cur == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001480 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1481 return;
1482 }
Daniel Veillard16253641998-10-28 22:58:05 +00001483 if (content == NULL) return;
1484 len = xmlStrlen(content);
1485 xmlNodeAddContentLen(cur, content, len);
1486}
1487
1488/**
1489 * xmlTextMerge:
1490 * @first: the first text node
1491 * @second: the second text node being merged
1492 *
1493 * Merge two text nodes into one
1494 * Return values: the first text node augmented
1495 */
1496xmlNodePtr
1497xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1498 if (first == NULL) return(second);
1499 if (second == NULL) return(first);
1500 if (first->type != XML_TEXT_NODE) return(first);
1501 if (second->type != XML_TEXT_NODE) return(first);
1502 xmlNodeAddContent(first, second->content);
1503 xmlUnlinkNode(second);
1504 xmlFreeNode(second);
1505 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001506}
1507
Daniel Veillard97b58771998-10-20 06:14:16 +00001508/**
1509 * xmlSearchNs:
1510 * @doc: the document
1511 * @node: the current node
1512 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00001513 *
Daniel Veillard97b58771998-10-20 06:14:16 +00001514 * Search a Ns registered under a given name space for a document.
1515 * recurse on the parents until it finds the defined namespace
1516 * or return NULL otherwise.
1517 * @nameSpace can be NULL, this is a search for the default namespace.
1518 * return values: the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001519 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001520xmlNsPtr
1521xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001522 xmlNsPtr cur;
1523
1524 while (node != NULL) {
1525 cur = node->nsDef;
1526 while (cur != NULL) {
1527 if ((cur->prefix == NULL) && (nameSpace == NULL))
1528 return(cur);
1529 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1530 (!xmlStrcmp(cur->prefix, nameSpace)))
1531 return(cur);
1532 cur = cur->next;
1533 }
1534 node = node->parent;
1535 }
1536 if (doc != NULL) {
1537 cur = doc->oldNs;
1538 while (cur != NULL) {
1539 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1540 (!xmlStrcmp(cur->prefix, nameSpace)))
1541 return(cur);
1542 cur = cur->next;
1543 }
1544 }
1545 return(NULL);
1546}
1547
Daniel Veillard97b58771998-10-20 06:14:16 +00001548/**
1549 * xmlSearchNsByHref:
1550 * @doc: the document
1551 * @node: the current node
1552 * @href: the namespace value
1553 *
1554 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1555 * the defined namespace or return NULL otherwise.
1556 * return values: the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001557 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001558xmlNsPtr
1559xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001560 xmlNsPtr cur;
1561
1562 while (node != NULL) {
1563 cur = node->nsDef;
1564 while (cur != NULL) {
1565 if ((cur->href != NULL) && (href != NULL) &&
1566 (!xmlStrcmp(cur->href, href)))
1567 return(cur);
1568 cur = cur->next;
1569 }
1570 node = node->parent;
1571 }
1572 if (doc != NULL) {
1573 cur = doc->oldNs;
1574 while (cur != NULL) {
1575 if ((cur->href != NULL) && (href != NULL) &&
1576 (!xmlStrcmp(cur->href, href)))
1577 return(cur);
1578 cur = cur->next;
1579 }
1580 }
1581 return(NULL);
1582}
1583
Daniel Veillard97b58771998-10-20 06:14:16 +00001584/**
1585 * xmlGetProp:
1586 * @node: the node
1587 * @name: the attribute name
1588 *
1589 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00001590 * This does the entity substitution.
Daniel Veillard97b58771998-10-20 06:14:16 +00001591 * return values: the attribute value or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001592 */
1593const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
1594 xmlAttrPtr prop = node->properties;
1595
1596 while (prop != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001597 if (!xmlStrcmp(prop->name, name))
1598 return(xmlNodeListGetString(node->doc, prop->val, 1));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001599 prop = prop->next;
1600 }
1601 return(NULL);
1602}
1603
Daniel Veillard97b58771998-10-20 06:14:16 +00001604/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001605 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00001606 * @node: the node
1607 * @name: the attribute name
1608 * @value: the attribute value
1609 *
1610 * Set (or reset) an attribute carried by a node.
1611 * return values: the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001612 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001613xmlAttrPtr
1614xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001615 xmlAttrPtr prop = node->properties;
1616
1617 while (prop != NULL) {
1618 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001619 if (prop->val != NULL)
1620 xmlFreeNode(prop->val);
1621 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001622 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001623 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001624 return(prop);
1625 }
1626 prop = prop->next;
1627 }
1628 prop = xmlNewProp(node, name, value);
1629 return(prop);
1630}
1631
Daniel Veillard97b58771998-10-20 06:14:16 +00001632/**
1633 * xmlNodeIsText:
1634 * @node: the node
1635 *
1636 * Is this node a Text node ?
1637 * return values: 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00001638 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001639int
1640xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001641 if (node == NULL) return(0);
1642
Daniel Veillard0bef1311998-10-14 02:36:47 +00001643 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001644 return(0);
1645}
1646
Daniel Veillard97b58771998-10-20 06:14:16 +00001647/**
1648 * xmlNodeIsText:
1649 * @node: the node
1650 * @content: the content
1651 * @len: @content lenght
1652 *
1653 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00001654 */
Daniel Veillard97b58771998-10-20 06:14:16 +00001655
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001656void
1657xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001658 if (node == NULL) return;
1659
Daniel Veillard0bef1311998-10-14 02:36:47 +00001660 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001661 fprintf(stderr, "xmlTextConcat: node is not text\n");
1662 return;
1663 }
1664 node->content = xmlStrncat(node->content, content, len);
1665}
1666
1667/************************************************************************
1668 * *
1669 * Output : to a FILE or in memory *
1670 * *
1671 ************************************************************************/
1672
Daniel Veillard260a68f1998-08-13 03:39:55 +00001673static CHAR *buffer = NULL;
1674static int buffer_index = 0;
1675static int buffer_size = 0;
1676
Daniel Veillard97b58771998-10-20 06:14:16 +00001677/**
1678 * xmlBufferWriteCHAR:
1679 * @string: the string to add
1680 *
1681 * routine which manage and grows an output buffer. This one add
1682 * CHARs at the end of the array.
1683 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001684void
1685xmlBufferWriteCHAR(const CHAR *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001686 const CHAR *cur;
1687
1688 if (buffer == NULL) {
1689 buffer_size = 50000;
1690 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
1691 if (buffer == NULL) {
1692 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
1693 exit(1);
1694 }
1695 }
1696
1697 if (string == NULL) return;
1698 for (cur = string;*cur != 0;cur++) {
1699 if (buffer_index + 10 >= buffer_size) {
1700 buffer_size *= 2;
1701 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
1702 if (buffer == NULL) {
1703 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
1704 exit(1);
1705 }
1706 }
1707 buffer[buffer_index++] = *cur;
1708 }
1709 buffer[buffer_index] = 0;
1710}
1711
Daniel Veillard97b58771998-10-20 06:14:16 +00001712/**
1713 * xmlBufferWriteChar:
1714 * @string: the string to add
1715 *
1716 * routine which manage and grows an output buffer. This one add
1717 * C chars at the end of the array.
1718 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001719void
1720xmlBufferWriteChar(const char *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001721 const char *cur;
1722
1723 if (buffer == NULL) {
1724 buffer_size = 50000;
1725 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
1726 if (buffer == NULL) {
1727 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
1728 exit(1);
1729 }
1730 }
1731
1732 if (string == NULL) return;
1733 for (cur = string;*cur != 0;cur++) {
1734 if (buffer_index + 10 >= buffer_size) {
1735 buffer_size *= 2;
1736 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
1737 if (buffer == NULL) {
1738 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
1739 exit(1);
1740 }
1741 }
1742 buffer[buffer_index++] = *cur;
1743 }
1744 buffer[buffer_index] = 0;
1745}
1746
Daniel Veillard97b58771998-10-20 06:14:16 +00001747/**
1748 * xmlGlobalNsDump:
1749 * @cur: a namespace
1750 *
1751 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001752 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001753static void
1754xmlGlobalNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001755 if (cur == NULL) {
1756 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
1757 return;
1758 }
1759 if (cur->type == XML_GLOBAL_NAMESPACE) {
1760 xmlBufferWriteChar("<?namespace");
1761 if (cur->href != NULL) {
1762 xmlBufferWriteChar(" href=\"");
1763 xmlBufferWriteCHAR(cur->href);
1764 xmlBufferWriteChar("\"");
1765 }
1766 if (cur->prefix != NULL) {
1767 xmlBufferWriteChar(" AS=\"");
1768 xmlBufferWriteCHAR(cur->prefix);
1769 xmlBufferWriteChar("\"");
1770 }
1771 xmlBufferWriteChar("?>\n");
1772 }
1773}
1774
Daniel Veillard97b58771998-10-20 06:14:16 +00001775/**
1776 * xmlGlobalNsListDump:
1777 * @cur: the first namespace
1778 *
1779 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001780 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001781static void
1782xmlGlobalNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001783 while (cur != NULL) {
1784 xmlGlobalNsDump(cur);
1785 cur = cur->next;
1786 }
1787}
1788
Daniel Veillard97b58771998-10-20 06:14:16 +00001789/**
1790 * xmlNsDump:
1791 * @cur: a namespace
1792 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001793 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00001794 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001795 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001796static void
1797xmlNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001798 if (cur == NULL) {
1799 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
1800 return;
1801 }
1802 if (cur->type == XML_LOCAL_NAMESPACE) {
1803 /* Within the context of an element attributes */
1804 if (cur->prefix != NULL) {
1805 xmlBufferWriteChar(" xmlns:");
1806 xmlBufferWriteCHAR(cur->prefix);
1807 } else
1808 xmlBufferWriteChar(" xmlns");
1809 xmlBufferWriteChar("=\"");
1810 xmlBufferWriteCHAR(cur->href);
1811 xmlBufferWriteChar("\"");
1812 }
1813}
1814
Daniel Veillard97b58771998-10-20 06:14:16 +00001815/**
1816 * xmlNsListDump:
1817 * @cur: the first namespace
1818 *
1819 * Dump a list of local Namespace definitions.
1820 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001821 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001822static void
1823xmlNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001824 while (cur != NULL) {
1825 xmlNsDump(cur);
1826 cur = cur->next;
1827 }
1828}
1829
Daniel Veillard97b58771998-10-20 06:14:16 +00001830/**
1831 * xmlDtdDump:
1832 * @doc: the document
1833 *
1834 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001835 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001836static void
1837xmlDtdDump(xmlDocPtr doc) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001838 xmlDtdPtr cur = doc->dtd;
1839
1840 if (cur == NULL) {
1841 fprintf(stderr, "xmlDtdDump : DTD == NULL\n");
1842 return;
1843 }
1844 xmlBufferWriteChar("<!DOCTYPE ");
1845 xmlBufferWriteCHAR(cur->name);
1846 if (cur->ExternalID != NULL) {
1847 xmlBufferWriteChar(" PUBLIC \"");
1848 xmlBufferWriteCHAR(cur->ExternalID);
1849 xmlBufferWriteChar("\" \"");
1850 xmlBufferWriteCHAR(cur->SystemID);
1851 xmlBufferWriteChar("\"");
1852 } else if (cur->SystemID != NULL) {
1853 xmlBufferWriteChar(" SYSTEM \"");
1854 xmlBufferWriteCHAR(cur->SystemID);
1855 xmlBufferWriteChar("\"");
1856 }
1857 if ((cur->entities == NULL) && (doc->entities == NULL)) {
1858 xmlBufferWriteChar(">\n");
1859 return;
1860 }
1861 xmlBufferWriteChar(" [\n");
1862 if (cur->entities != NULL)
1863 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1864 if (doc->entities != NULL)
1865 xmlDumpEntitiesTable((xmlEntitiesTablePtr) doc->entities);
1866 xmlBufferWriteChar("]");
1867
1868 /* TODO !!! a lot more things to dump ... */
1869 xmlBufferWriteChar(">\n");
1870}
1871
Daniel Veillard97b58771998-10-20 06:14:16 +00001872/**
1873 * xmlAttrDump:
1874 * @doc: the document
1875 * @cur: the attribute pointer
1876 *
1877 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00001878 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001879static void
1880xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001881 CHAR *value;
1882
Daniel Veillard260a68f1998-08-13 03:39:55 +00001883 if (cur == NULL) {
1884 fprintf(stderr, "xmlAttrDump : property == NULL\n");
1885 return;
1886 }
1887 xmlBufferWriteChar(" ");
1888 xmlBufferWriteCHAR(cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00001889 value = xmlNodeListGetString(doc, cur->val, 0);
1890 if (value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001891 xmlBufferWriteChar("=\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00001892 xmlBufferWriteCHAR(value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001893 xmlBufferWriteChar("\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00001894 free(value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001895 }
1896}
1897
Daniel Veillard97b58771998-10-20 06:14:16 +00001898/**
1899 * xmlAttrListDump:
1900 * @doc: the document
1901 * @cur: the first attribute pointer
1902 *
1903 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00001904 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001905static void
1906xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001907 if (cur == NULL) {
1908 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
1909 return;
1910 }
1911 while (cur != NULL) {
1912 xmlAttrDump(doc, cur);
1913 cur = cur->next;
1914 }
1915}
1916
Daniel Veillard260a68f1998-08-13 03:39:55 +00001917
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001918static void
1919xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00001920/**
1921 * xmlNodeListDump:
1922 * @doc: the document
1923 * @cur: the first node
1924 * @level: the imbrication level for indenting
1925 *
1926 * Dump an XML node list, recursive behaviour,children are printed too.
1927 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001928static void
1929xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001930 int needIndent = 0, i;
1931
Daniel Veillard260a68f1998-08-13 03:39:55 +00001932 if (cur == NULL) {
1933 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
1934 return;
1935 }
1936 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001937 if ((cur->type != XML_TEXT_NODE) &&
1938 (cur->type != XML_ENTITY_REF_NODE)) {
1939 if (!needIndent) {
1940 needIndent = 1;
1941 xmlBufferWriteChar("\n");
1942 }
1943 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001944 xmlNodeDump(doc, cur, level);
1945 cur = cur->next;
1946 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001947 if ((xmlIndentTreeOutput) && (needIndent))
1948 for (i = 1;i < level;i++)
1949 xmlBufferWriteChar(" ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001950}
1951
Daniel Veillard97b58771998-10-20 06:14:16 +00001952/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001953 * xmlNodeDump:
Daniel Veillard97b58771998-10-20 06:14:16 +00001954 * @doc: the document
1955 * @cur: the current node
1956 * @level: the imbrication level for indenting
1957 *
1958 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001959 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001960static void
1961xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001962 int i;
1963
1964 if (cur == NULL) {
1965 fprintf(stderr, "xmlNodeDump : node == NULL\n");
1966 return;
1967 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001968 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001969 if (cur->content != NULL)
1970 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1971 return;
1972 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001973 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001974 if (cur->content != NULL) {
1975 xmlBufferWriteChar("<!--");
1976 xmlBufferWriteCHAR(cur->content);
1977 xmlBufferWriteChar("-->");
1978 }
1979 return;
1980 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001981 if (cur->type == XML_ENTITY_REF_NODE) {
1982 xmlBufferWriteChar("&");
1983 xmlBufferWriteCHAR(cur->name);
1984 xmlBufferWriteChar(";");
1985 return;
1986 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001987 if (xmlIndentTreeOutput)
1988 for (i = 0;i < level;i++)
1989 xmlBufferWriteChar(" ");
1990
1991 xmlBufferWriteChar("<");
1992 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1993 xmlBufferWriteCHAR(cur->ns->prefix);
1994 xmlBufferWriteChar(":");
1995 }
1996
1997 xmlBufferWriteCHAR(cur->name);
1998 if (cur->nsDef)
1999 xmlNsListDump(cur->nsDef);
2000 if (cur->properties != NULL)
2001 xmlAttrListDump(doc, cur->properties);
2002
2003 if ((cur->content == NULL) && (cur->childs == NULL)) {
2004 xmlBufferWriteChar("/>\n");
2005 return;
2006 }
2007 xmlBufferWriteChar(">");
2008 if (cur->content != NULL)
2009 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2010 if (cur->childs != NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002011 xmlNodeListDump(doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002012 }
2013 xmlBufferWriteChar("</");
2014 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2015 xmlBufferWriteCHAR(cur->ns->prefix);
2016 xmlBufferWriteChar(":");
2017 }
2018
2019 xmlBufferWriteCHAR(cur->name);
2020 xmlBufferWriteChar(">\n");
2021}
2022
Daniel Veillard97b58771998-10-20 06:14:16 +00002023/**
2024 * xmlDocContentDump:
2025 * @cur: the document
2026 *
2027 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002028 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002029static void
2030xmlDocContentDump(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002031 if (oldXMLWDcompatibility)
2032 xmlBufferWriteChar("<?XML version=\"");
2033 else
2034 xmlBufferWriteChar("<?xml version=\"");
2035 xmlBufferWriteCHAR(cur->version);
2036 xmlBufferWriteChar("\"");
2037 if (cur->encoding != NULL) {
2038 xmlBufferWriteChar(" encoding=\"");
2039 xmlBufferWriteCHAR(cur->encoding);
2040 xmlBufferWriteChar("\"");
2041 }
2042 switch (cur->standalone) {
2043 case 0:
2044 xmlBufferWriteChar(" standalone=\"no\"");
2045 break;
2046 case 1:
2047 xmlBufferWriteChar(" standalone=\"yes\"");
2048 break;
2049 }
2050 xmlBufferWriteChar("?>\n");
2051 if ((cur->dtd != NULL) || (cur->entities != NULL))
2052 xmlDtdDump(cur);
2053 if (cur->root != NULL) {
2054 /* global namespace definitions, the old way */
2055 if (oldXMLWDcompatibility)
2056 xmlGlobalNsListDump(cur->oldNs);
2057 else
2058 xmlUpgradeOldNs(cur);
2059 xmlNodeDump(cur, cur->root, 0);
2060 }
2061}
2062
Daniel Veillard97b58771998-10-20 06:14:16 +00002063/**
2064 * xmlDocDumpMemory:
2065 * @cur: the document
2066 * @mem: OUT: the memory pointer
2067 * @size: OUT: the memory lenght
2068 *
2069 * Dump an XML document in memory and return the CHAR * and it's size.
2070 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002071 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002072void
2073xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002074 if (cur == NULL) {
2075 fprintf(stderr, "xmlDocDump : document == NULL\n");
2076 *mem = NULL;
2077 *size = 0;
2078 return;
2079 }
2080 buffer_index = 0;
2081 xmlDocContentDump(cur);
2082
2083 *mem = buffer;
2084 *size = buffer_index;
2085}
2086
Daniel Veillard97b58771998-10-20 06:14:16 +00002087/**
2088 * xmlGetDocCompressMode:
2089 * @doc: the document
2090 *
2091 * get the compression ratio for a document, ZLIB based
2092 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002093 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002094int
2095 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002096 if (doc == NULL) return(-1);
2097 return(doc->compression);
2098}
2099
Daniel Veillard97b58771998-10-20 06:14:16 +00002100/**
2101 * xmlSetDocCompressMode:
2102 * @doc: the document
2103 * @mode: the compression ratio
2104 *
2105 * set the compression ratio for a document, ZLIB based
2106 * Correct values: 0 (uncompressed) to 9 (max compression)
2107 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002108void
2109xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002110 if (doc == NULL) return;
2111 if (mode < 0) doc->compression = 0;
2112 else if (mode > 9) doc->compression = 9;
2113 else doc->compression = mode;
2114}
2115
Daniel Veillard97b58771998-10-20 06:14:16 +00002116/**
2117 * xmlGetCompressMode:
2118 *
2119 * get the default compression mode used, ZLIB based.
2120 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002121 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002122int
2123 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002124 return(xmlCompressMode);
2125}
Daniel Veillard97b58771998-10-20 06:14:16 +00002126
2127/**
2128 * xmlSetCompressMode:
2129 * @mode: the compression ratio
2130 *
2131 * set the default compression mode used, ZLIB based
2132 * Correct values: 0 (uncompressed) to 9 (max compression)
2133 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002134void
2135xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002136 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002137 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002138 else xmlCompressMode = mode;
2139}
2140
Daniel Veillard97b58771998-10-20 06:14:16 +00002141/**
2142 * xmlDocDump:
2143 * @f: the FILE*
2144 * @cur: the document
2145 *
2146 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002147 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002148void
2149xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002150 if (cur == NULL) {
2151 fprintf(stderr, "xmlDocDump : document == NULL\n");
2152 return;
2153 }
2154 buffer_index = 0;
2155 xmlDocContentDump(cur);
2156
2157 fwrite(buffer, sizeof(CHAR), buffer_index, f);
2158}
2159
Daniel Veillard97b58771998-10-20 06:14:16 +00002160/**
2161 * xmlSaveFile:
2162 * @filename: the filename
2163 * @cur: the document
2164 *
2165 * Dump an XML document to a file. Will use compression if
2166 * compiled in and enabled.
2167 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002168 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002169int
2170xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002171#ifdef HAVE_ZLIB_H
2172 gzFile zoutput = NULL;
2173 char mode[15];
2174#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002175 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002176 int ret;
2177
2178#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002179 if ((cur->compression > 0) && (cur->compression <= 9)) {
2180 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002181 zoutput = gzopen(filename, mode);
2182 }
2183 if (zoutput == NULL) {
2184#endif
2185 output = fopen(filename, "w");
2186 if (output == NULL) return(-1);
2187#ifdef HAVE_ZLIB_H
2188 }
2189#endif
2190
2191 /*
2192 * save the content to a temp buffer.
2193 */
2194 buffer_index = 0;
2195 xmlDocContentDump(cur);
2196
2197#ifdef HAVE_ZLIB_H
2198 if (zoutput != NULL) {
2199 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
2200 gzclose(zoutput);
2201 return(ret);
2202 }
2203#endif
2204 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
2205 fclose(output);
2206 return(ret * sizeof(CHAR));
2207}
2208