blob: 9e71b4df79bb41d800d06c5e863bb360fbf3eb13 [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);
Daniel Veillard242590e1998-11-13 18:04:35 +0000430 if (node == NULL) {
431 if (val != NULL) free(val);
432 return(ret);
433 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000434 if (last == NULL)
435 last = ret = node;
436 else {
437 last->next = node;
438 node->prev = last;
439 last = node;
440 }
Daniel Veillard16253641998-10-28 22:58:05 +0000441 }
442 free(val);
443 }
444 cur++;
445 q = cur;
446 } else
447 cur++;
448 }
449 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000450 /*
451 * Handle the last piece of text.
452 */
453 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
454 xmlNodeAddContentLen(last, q, cur - q);
455 } else {
456 node = xmlNewDocTextLen(doc, q, cur - q);
457 if (node == NULL) return(ret);
458 if (last == NULL)
459 last = ret = node;
460 else {
461 last->next = node;
462 node->prev = last;
463 last = node;
464 }
Daniel Veillard16253641998-10-28 22:58:05 +0000465 }
466 }
467 return(ret);
468}
469
470/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000471 * xmlStringGetNodeList:
472 * @doc: the document
473 * @value: the value of the attribute
474 *
475 * Parse the value string and build the node list associated. Should
476 * produce a flat tree with only TEXTs and ENTITY_REFs.
477 * return values: a pointer to the first child
478 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000479xmlNodePtr
480xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000481 xmlNodePtr ret = NULL, last = NULL;
482 xmlNodePtr node;
483 CHAR *val;
484 const CHAR *cur = value;
485 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000486 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000487
488 if (value == NULL) return(NULL);
489
490 q = cur;
491 while (*cur != 0) {
492 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000493 /*
494 * Save the current text.
495 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000496 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000497 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
498 xmlNodeAddContentLen(last, q, cur - q);
499 } else {
500 node = xmlNewDocTextLen(doc, q, cur - q);
501 if (node == NULL) return(ret);
502 if (last == NULL)
503 last = ret = node;
504 else {
505 last->next = node;
506 node->prev = last;
507 last = node;
508 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000509 }
510 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000511 /*
512 * Read the entity string
513 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000514 cur++;
515 q = cur;
516 while ((*cur != 0) && (*cur != ';')) cur++;
517 if (*cur == 0) {
518 fprintf(stderr,
519 "xmlStringGetNodeList: unterminated entity %30s\n", q);
520 return(ret);
521 }
522 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000523 /*
524 * Predefined entities don't generate nodes
525 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000526 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000527 ent = xmlGetDocEntity(doc, val);
528 if ((ent != NULL) &&
529 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
530 if (last == NULL) {
531 node = xmlNewDocText(doc, ent->content);
532 last = ret = node;
533 } else
534 xmlNodeAddContent(last, ent->content);
535
536 } else {
537 /*
538 * Create a new REFERENCE_REF node
539 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000540 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000541 if (node == NULL) {
542 if (val != NULL) free(val);
543 return(ret);
544 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000545 if (last == NULL)
546 last = ret = node;
547 else {
548 last->next = node;
549 node->prev = last;
550 last = node;
551 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000552 }
553 free(val);
554 }
555 cur++;
556 q = cur;
557 } else
558 cur++;
559 }
560 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000561 /*
562 * Handle the last piece of text.
563 */
564 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
565 xmlNodeAddContentLen(last, q, cur - q);
566 } else {
567 node = xmlNewDocTextLen(doc, q, cur - q);
568 if (node == NULL) return(ret);
569 if (last == NULL)
570 last = ret = node;
571 else {
572 last->next = node;
573 node->prev = last;
574 last = node;
575 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000576 }
577 }
578 return(ret);
579}
580
581/**
582 * xmlNodeListGetString:
583 * @doc: the document
584 * @list: a Node list
585 * @inLine: should we replace entity contents or show their external form
586 *
587 * Returns the string equivalent to the text contained in the Node list
588 * made of TEXTs and ENTITY_REFs
589 * return values: a pointer to the string copy, the calller must free it.
590 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000591CHAR *
592xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000593 xmlNodePtr node = list;
594 CHAR *ret = NULL;
595 xmlEntityPtr ent;
596
597 if (list == NULL) return(NULL);
598
599 while (node != NULL) {
600 if (node->type == XML_TEXT_NODE) {
601 if (inLine)
602 ret = xmlStrcat(ret, node->content);
603 else
604 ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
605 } else if (node->type == XML_ENTITY_REF_NODE) {
606 if (inLine) {
607 ent = xmlGetDocEntity(doc, node->name);
608 if (ent != NULL)
609 ret = xmlStrcat(ret, ent->content);
610 else
611 ret = xmlStrcat(ret, node->content);
612 } else {
613 CHAR buf[2];
614 buf[0] = '&'; buf[1] = 0;
615 ret = xmlStrncat(ret, buf, 1);
616 ret = xmlStrcat(ret, node->name);
617 buf[0] = ';'; buf[1] = 0;
618 ret = xmlStrncat(ret, buf, 1);
619 }
620 }
621#if 0
622 else {
623 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
624 node->type);
625 }
626#endif
627 node = node->next;
628 }
629 return(ret);
630}
631
632/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000633 * xmlNewProp:
634 * @node: the holding node
635 * @name: the name of the attribute
636 * @value: the value of the attribute
637 *
638 * Create a new property carried by a node.
639 * return values: a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000640 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000641xmlAttrPtr
642xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000643 xmlAttrPtr cur;
644
645 if (name == NULL) {
646 fprintf(stderr, "xmlNewProp : name == NULL\n");
647 return(NULL);
648 }
649
650 /*
651 * Allocate a new property and fill the fields.
652 */
653 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
654 if (cur == NULL) {
655 fprintf(stderr, "xmlNewProp : malloc failed\n");
656 return(NULL);
657 }
658
Daniel Veillard33942841998-10-18 19:12:41 +0000659 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000660 cur->node = node;
661 cur->name = xmlStrdup(name);
662 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +0000663 cur->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000664 else
Daniel Veillardccb09631998-10-27 06:21:04 +0000665 cur->val = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000666#ifndef WITHOUT_CORBA
667 cur->_private = NULL;
668 cur->vepv = NULL;
669#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000670
671 /*
672 * Add it at the end to preserve parsing order ...
673 */
674 cur->next = NULL;
675 if (node != NULL) {
676 if (node->properties == NULL) {
677 node->properties = cur;
678 } else {
679 xmlAttrPtr prev = node->properties;
680
681 while (prev->next != NULL) prev = prev->next;
682 prev->next = cur;
683 }
684 }
685 return(cur);
686}
687
Daniel Veillard97b58771998-10-20 06:14:16 +0000688/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000689 * xmlNewDocProp:
690 * @doc: the document
691 * @name: the name of the attribute
692 * @value: the value of the attribute
693 *
694 * Create a new property carried by a document.
695 * return values: a pointer to the attribute
696 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000697xmlAttrPtr
698xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000699 xmlAttrPtr cur;
700
701 if (name == NULL) {
702 fprintf(stderr, "xmlNewProp : name == NULL\n");
703 return(NULL);
704 }
705
706 /*
707 * Allocate a new property and fill the fields.
708 */
709 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
710 if (cur == NULL) {
711 fprintf(stderr, "xmlNewProp : malloc failed\n");
712 return(NULL);
713 }
714
715 cur->type = XML_ATTRIBUTE_NODE;
716 cur->node = NULL;
717 cur->name = xmlStrdup(name);
718 if (value != NULL)
719 cur->val = xmlStringGetNodeList(doc, value);
720 else
721 cur->val = NULL;
722#ifndef WITHOUT_CORBA
723 cur->_private = NULL;
724 cur->vepv = NULL;
725#endif
726
727 cur->next = NULL;
728 return(cur);
729}
730
731/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000732 * xmlFreePropList:
733 * @cur: the first property in the list
734 *
735 * Free a property and all its siblings, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000736 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000737void
738xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000739 xmlAttrPtr next;
740 if (cur == NULL) {
741 fprintf(stderr, "xmlFreePropList : property == NULL\n");
742 return;
743 }
744 while (cur != NULL) {
745 next = cur->next;
746 xmlFreeProp(cur);
747 cur = next;
748 }
749}
750
Daniel Veillard97b58771998-10-20 06:14:16 +0000751/**
752 * xmlFreeProp:
753 * @cur: the first property in the list
754 *
755 * Free one property, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000756 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000757void
758xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000759 if (cur == NULL) {
760 fprintf(stderr, "xmlFreeProp : property == NULL\n");
761 return;
762 }
763 if (cur->name != NULL) free((char *) cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +0000764 if (cur->val != NULL) xmlFreeNodeList(cur->val);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000765 memset(cur, -1, sizeof(xmlAttr));
766 free(cur);
767}
768
Daniel Veillard97b58771998-10-20 06:14:16 +0000769/**
770 * xmlNewNode:
771 * @ns: namespace if any
772 * @name: the node name
773 * @content: the text content if any
774 *
775 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +0000776 * If content is non NULL, a child list containing the TEXTs and
777 * ENTITY_REFs node will be created.
Daniel Veillard97b58771998-10-20 06:14:16 +0000778 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000779 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000780xmlNodePtr
781xmlNewNode(xmlNsPtr ns, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000782 xmlNodePtr cur;
783
784 if (name == NULL) {
785 fprintf(stderr, "xmlNewNode : name == NULL\n");
786 return(NULL);
787 }
788
789 /*
790 * Allocate a new node and fill the fields.
791 */
792 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
793 if (cur == NULL) {
794 fprintf(stderr, "xmlNewNode : malloc failed\n");
795 return(NULL);
796 }
797
Daniel Veillard33942841998-10-18 19:12:41 +0000798 cur->type = XML_ELEMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000799 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000800 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000801 cur->next = NULL;
802 cur->prev = NULL;
803 cur->childs = NULL;
804 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000805 cur->name = xmlStrdup(name);
806 cur->ns = ns;
807 cur->nsDef = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000808 cur->content = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000809#ifndef WITHOUT_CORBA
810 cur->_private = NULL;
811 cur->vepv = NULL;
812#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000813 return(cur);
814}
815
Daniel Veillard97b58771998-10-20 06:14:16 +0000816/**
817 * xmlNewDocNode:
818 * @doc: the document
819 * @ns: namespace if any
820 * @name: the node name
821 * @content: the text content if any
822 *
823 * Creation of a new node element within a document. @ns and @content
824 * are optionnal (NULL).
825 * return values: a pointer to the new node object.
826 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000827xmlNodePtr
828xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard0bef1311998-10-14 02:36:47 +0000829 const CHAR *name, CHAR *content) {
830 xmlNodePtr cur;
831
Daniel Veillardccb09631998-10-27 06:21:04 +0000832 cur = xmlNewNode(ns, name);
833 if (cur != NULL) {
834 cur->doc = doc;
835 if (content != NULL)
836 cur->childs = xmlStringGetNodeList(doc, content);
837 }
Daniel Veillard0bef1311998-10-14 02:36:47 +0000838 return(cur);
839}
840
841
Daniel Veillard97b58771998-10-20 06:14:16 +0000842/**
843 * xmlNewText:
844 * @content: the text content
845 *
846 * Creation of a new text node.
847 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000848 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000849xmlNodePtr
850xmlNewText(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000851 xmlNodePtr cur;
852
853 /*
854 * Allocate a new node and fill the fields.
855 */
856 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
857 if (cur == NULL) {
858 fprintf(stderr, "xmlNewText : malloc failed\n");
859 return(NULL);
860 }
861
Daniel Veillard33942841998-10-18 19:12:41 +0000862 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000863 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000864 cur->parent = NULL;
865 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000866 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000867 cur->childs = NULL;
868 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000869 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000870 cur->name = xmlStrdup(xmlStringText);
871 cur->ns = NULL;
872 cur->nsDef = NULL;
873 if (content != NULL)
874 cur->content = xmlStrdup(content);
875 else
876 cur->content = NULL;
877 return(cur);
878}
879
Daniel Veillard97b58771998-10-20 06:14:16 +0000880/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000881 * xmlNewReference:
882 * @doc: the document
883 * @name: the reference name, or the reference string with & and ;
884 *
885 * Creation of a new reference node.
886 * return values: a pointer to the new node object.
887 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000888xmlNodePtr
889xmlNewReference(xmlDocPtr doc, const CHAR *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000890 xmlNodePtr cur;
891 xmlEntityPtr ent;
892
893 /*
894 * Allocate a new node and fill the fields.
895 */
896 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
897 if (cur == NULL) {
898 fprintf(stderr, "xmlNewText : malloc failed\n");
899 return(NULL);
900 }
901
902 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillard10c6a8f1998-10-28 01:00:12 +0000903 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +0000904 cur->parent = NULL;
905 cur->next = NULL;
906 cur->prev = NULL;
907 cur->childs = NULL;
908 cur->properties = NULL;
909 if (name[0] == '&') {
910 int len;
911 name++;
912 len = xmlStrlen(name);
913 if (name[len - 1] == ';')
914 cur->name = xmlStrndup(name, len - 1);
915 else
916 cur->name = xmlStrndup(name, len);
917 } else
918 cur->name = xmlStrdup(name);
919 cur->ns = NULL;
920 cur->nsDef = NULL;
921
922 ent = xmlGetDocEntity(doc, cur->name);
923 if (ent != NULL)
924 cur->content = ent->content;
925 else
926 cur->content = NULL;
927 return(cur);
928}
929
930/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000931 * xmlNewDocText:
932 * @doc: the document
933 * @content: the text content
934 *
935 * Creation of a new text node within a document.
936 * return values: a pointer to the new node object.
937 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000938xmlNodePtr
939xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +0000940 xmlNodePtr cur;
941
942 cur = xmlNewText(content);
943 if (cur != NULL) cur->doc = doc;
944 return(cur);
945}
946
Daniel Veillard97b58771998-10-20 06:14:16 +0000947/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000948 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +0000949 * @content: the text content
950 * @len: the text len.
951 *
952 * Creation of a new text node with an extra parameter for the content's lenght
953 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000954 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000955xmlNodePtr
956xmlNewTextLen(const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000957 xmlNodePtr cur;
958
959 /*
960 * Allocate a new node and fill the fields.
961 */
962 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
963 if (cur == NULL) {
964 fprintf(stderr, "xmlNewText : malloc failed\n");
965 return(NULL);
966 }
967
Daniel Veillard33942841998-10-18 19:12:41 +0000968 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000969 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000970 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000971 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000972 cur->next = NULL;
973 cur->childs = NULL;
974 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000975 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000976 cur->name = xmlStrdup(xmlStringText);
977 cur->ns = NULL;
978 cur->nsDef = NULL;
979 if (content != NULL)
980 cur->content = xmlStrndup(content, len);
981 else
982 cur->content = NULL;
983 return(cur);
984}
985
Daniel Veillard97b58771998-10-20 06:14:16 +0000986/**
987 * xmlNewDocTextLen:
988 * @doc: the document
989 * @content: the text content
990 * @len: the text len.
991 *
992 * Creation of a new text node with an extra content lenght parameter. The
993 * text node pertain to a given document.
994 * return values: a pointer to the new node object.
995 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000996xmlNodePtr
997xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +0000998 xmlNodePtr cur;
999
1000 cur = xmlNewTextLen(content, len);
1001 if (cur != NULL) cur->doc = doc;
1002 return(cur);
1003}
1004
Daniel Veillard97b58771998-10-20 06:14:16 +00001005/**
1006 * xmlNewComment:
1007 * @content: the comment content
1008 *
1009 * Creation of a new node containing a comment.
1010 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001011 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001012xmlNodePtr
1013xmlNewComment(CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001014 xmlNodePtr cur;
1015
1016 /*
1017 * Allocate a new node and fill the fields.
1018 */
1019 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1020 if (cur == NULL) {
1021 fprintf(stderr, "xmlNewComment : malloc failed\n");
1022 return(NULL);
1023 }
1024
Daniel Veillard33942841998-10-18 19:12:41 +00001025 cur->type = XML_COMMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001026 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001027 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001028 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001029 cur->next = NULL;
1030 cur->childs = NULL;
1031 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001032 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001033 cur->name = xmlStrdup(xmlStringText);
1034 cur->ns = NULL;
1035 cur->nsDef = NULL;
1036 if (content != NULL)
1037 cur->content = xmlStrdup(content);
1038 else
1039 cur->content = NULL;
1040 return(cur);
1041}
1042
Daniel Veillard97b58771998-10-20 06:14:16 +00001043/**
1044 * xmlNewComment:
1045 * @doc: the document
1046 * @content: the comment content
1047 *
1048 * Creation of a new node containing a commentwithin a document.
1049 * return values: a pointer to the new node object.
1050 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001051xmlNodePtr
1052xmlNewDocComment(xmlDocPtr doc, CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001053 xmlNodePtr cur;
1054
1055 cur = xmlNewComment(content);
1056 if (cur != NULL) cur->doc = doc;
1057 return(cur);
1058}
1059
Daniel Veillard97b58771998-10-20 06:14:16 +00001060/**
1061 * xmlNewChild:
1062 * @parent: the parent node
1063 * @ns: a namespace if any
1064 * @name: the name of the child
1065 * @content: the content of the child if any.
1066 *
1067 *
1068 * Creation of a new child element, added at the end of @parent childs list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001069 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1070 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard97b58771998-10-20 06:14:16 +00001071 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001072 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001073xmlNodePtr
1074xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001075 const CHAR *name, CHAR *content) {
1076 xmlNodePtr cur, prev;
1077
1078 if (parent == NULL) {
1079 fprintf(stderr, "xmlNewChild : parent == NULL\n");
1080 return(NULL);
1081 }
1082
1083 if (name == NULL) {
1084 fprintf(stderr, "xmlNewChild : name == NULL\n");
1085 return(NULL);
1086 }
1087
1088 /*
1089 * Allocate a new node
1090 */
1091 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001092 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001093 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001094 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001095 if (cur == NULL) return(NULL);
1096
1097 /*
1098 * add the new element at the end of the childs list.
1099 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001100 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001101 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001102 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001103 if (parent->childs == NULL) {
1104 parent->childs = cur;
1105 } else {
1106 prev = parent->childs;
1107 while (prev->next != NULL) prev = prev->next;
1108 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001109 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001110 }
1111
1112 return(cur);
1113}
1114
Daniel Veillard97b58771998-10-20 06:14:16 +00001115/**
1116 * xmlAddChild:
1117 * @parent: the parent node
1118 * @cur: the child node
1119 *
1120 * Add a new child element, to @parent, at the end of the child list.
1121 * return values: the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001122 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001123xmlNodePtr
1124xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001125 xmlNodePtr prev;
1126
1127 if (parent == NULL) {
1128 fprintf(stderr, "xmladdChild : parent == NULL\n");
1129 return(NULL);
1130 }
1131
1132 if (cur == NULL) {
1133 fprintf(stderr, "xmladdChild : child == NULL\n");
1134 return(NULL);
1135 }
1136
Daniel Veillard0bef1311998-10-14 02:36:47 +00001137 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1138 (cur->doc != parent->doc)) {
1139 fprintf(stderr, "Elements moved to a different document\n");
1140 }
1141
Daniel Veillard260a68f1998-08-13 03:39:55 +00001142 /*
1143 * add the new element at the end of the childs list.
1144 */
1145 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001146 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillardccb09631998-10-27 06:21:04 +00001147 /*
1148 * Handle the case where parent->content != NULL, in that case it will
1149 * create a intermediate TEXT node.
1150 */
1151 if (parent->content != NULL) {
1152 xmlNodePtr text;
1153
1154 text = xmlNewDocText(parent->doc, parent->content);
1155 if (text != NULL) {
1156 text->next = parent->childs;
1157 if (text->next != NULL)
1158 text->next->prev = text;
1159 parent->childs = text;
1160 free(parent->content);
1161 parent->content = NULL;
1162 }
1163 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001164 if (parent->childs == NULL) {
1165 parent->childs = cur;
1166 } else {
1167 prev = parent->childs;
1168 while (prev->next != NULL) prev = prev->next;
1169 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001170 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001171 }
1172
1173 return(cur);
1174}
1175
Daniel Veillard97b58771998-10-20 06:14:16 +00001176/**
1177 * xmlGetLastChild:
1178 * @parent: the parent node
1179 *
1180 * Search the last child of a node.
1181 * return values: the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001182 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001183xmlNodePtr
1184xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001185 xmlNodePtr last;
1186
1187 if (parent == NULL) {
1188 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1189 return(NULL);
1190 }
1191
1192 /*
1193 * add the new element at the end of the childs list.
1194 */
1195 if (parent->childs == NULL) {
1196 return(NULL);
1197 } else {
1198 last = parent->childs;
1199 while (last->next != NULL) last = last->next;
1200 }
1201 return(last);
1202}
1203
Daniel Veillard97b58771998-10-20 06:14:16 +00001204/**
1205 * xmlFreeNodeList:
1206 * @cur: the first node in the list
1207 *
1208 * Free a node and all its siblings, this is a recursive behaviour, all
1209 * the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001210 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001211void
1212xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001213 xmlNodePtr next;
1214 if (cur == NULL) {
1215 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1216 return;
1217 }
1218 while (cur != NULL) {
1219 next = cur->next;
1220 xmlFreeNode(cur);
1221 cur = next;
1222 }
1223}
1224
Daniel Veillard97b58771998-10-20 06:14:16 +00001225/**
1226 * xmlFreeNode:
1227 * @cur: the node
1228 *
1229 * Free a node, this is a recursive behaviour, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001230 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001231void
1232xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001233 if (cur == NULL) {
1234 fprintf(stderr, "xmlFreeNode : node == NULL\n");
1235 return;
1236 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001237 cur->doc = NULL;
1238 cur->parent = NULL;
1239 cur->next = NULL;
1240 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001241 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
Daniel Veillardccb09631998-10-27 06:21:04 +00001242 if (cur->properties != NULL) xmlFreePropList(cur->properties);
1243 if (cur->type != XML_ENTITY_REF_NODE)
1244 if (cur->content != NULL) free(cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001245 if (cur->name != NULL) free((char *) cur->name);
1246 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1247 memset(cur, -1, sizeof(xmlNode));
1248 free(cur);
1249}
1250
Daniel Veillard16253641998-10-28 22:58:05 +00001251/**
1252 * xmlUnlinkNode:
1253 * @cur: the node
1254 *
1255 * Unlink a node from it's current context, the node is not freed
1256 */
1257void
1258xmlUnlinkNode(xmlNodePtr cur) {
1259 if (cur == NULL) {
1260 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1261 return;
1262 }
1263 if ((cur->parent != NULL) && (cur->parent->childs == cur))
1264 cur->parent->childs = cur->next;
1265 if (cur->next != NULL)
1266 cur->next->prev = cur->prev;
1267 if (cur->prev != NULL)
1268 cur->prev->next = cur->next;
1269 cur->next = cur->prev = NULL;
1270 cur->parent = NULL;
1271}
1272
Daniel Veillard260a68f1998-08-13 03:39:55 +00001273/************************************************************************
1274 * *
1275 * Content access functions *
1276 * *
1277 ************************************************************************/
1278
Daniel Veillard97b58771998-10-20 06:14:16 +00001279/**
Daniel Veillard16253641998-10-28 22:58:05 +00001280 * xmlNodeGetContent:
1281 * @cur: the node being read
1282 *
1283 * Read the value of a node, this can be either the text carried
1284 * directly by this node if it's a TEXT node or the aggregate string
1285 * of the values carried by this node child's (TEXT and ENTITY_REF).
1286 * Entity references are substitued.
1287 * Return value: a new CHAR * or NULL if no content is available.
1288 */
1289CHAR *
1290xmlNodeGetContent(xmlNodePtr cur) {
1291 if (cur == NULL) return(NULL);
1292 switch (cur->type) {
1293 case XML_DOCUMENT_FRAG_NODE:
1294 case XML_ELEMENT_NODE:
1295 return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1296 break;
1297 case XML_ATTRIBUTE_NODE:
1298 case XML_CDATA_SECTION_NODE:
1299 case XML_ENTITY_REF_NODE:
1300 case XML_ENTITY_NODE:
1301 case XML_PI_NODE:
1302 case XML_COMMENT_NODE:
1303 case XML_DOCUMENT_NODE:
1304 case XML_DOCUMENT_TYPE_NODE:
1305 case XML_NOTATION_NODE:
1306 return(NULL);
1307 case XML_TEXT_NODE:
1308 if (cur->content != NULL)
1309 return(xmlStrdup(cur->content));
1310 return(NULL);
1311 }
1312 return(NULL);
1313}
1314
1315/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001316 * xmlNodeSetContent:
1317 * @cur: the node being modified
1318 * @content: the new value of the content
1319 *
1320 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001321 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001322void
1323xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001324 if (cur == NULL) {
1325 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1326 return;
1327 }
Daniel Veillard16253641998-10-28 22:58:05 +00001328 switch (cur->type) {
1329 case XML_DOCUMENT_FRAG_NODE:
1330 case XML_ELEMENT_NODE:
1331 if (cur->content != NULL) {
1332 free(cur->content);
1333 cur->content = NULL;
1334 }
1335 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1336 cur->childs = xmlStringGetNodeList(cur->doc, content);
1337 break;
1338 case XML_ATTRIBUTE_NODE:
1339 break;
1340 case XML_TEXT_NODE:
1341 case XML_CDATA_SECTION_NODE:
1342 case XML_ENTITY_REF_NODE:
1343 case XML_ENTITY_NODE:
1344 case XML_PI_NODE:
1345 case XML_COMMENT_NODE:
1346 if (cur->content != NULL) free(cur->content);
1347 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1348 if (content != NULL)
1349 cur->content = xmlStrdup(content);
1350 else
1351 cur->content = NULL;
1352 case XML_DOCUMENT_NODE:
1353 case XML_DOCUMENT_TYPE_NODE:
1354 break;
1355 case XML_NOTATION_NODE:
1356 break;
1357 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001358}
1359
Daniel Veillard97b58771998-10-20 06:14:16 +00001360/**
1361 * xmlNodeSetContentLen:
1362 * @cur: the node being modified
1363 * @content: the new value of the content
1364 * @len: the size of @content
1365 *
1366 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001367 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001368void
1369xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001370 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001371 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001372 return;
1373 }
Daniel Veillard16253641998-10-28 22:58:05 +00001374 switch (cur->type) {
1375 case XML_DOCUMENT_FRAG_NODE:
1376 case XML_ELEMENT_NODE:
1377 if (cur->content != NULL) {
1378 free(cur->content);
1379 cur->content = NULL;
1380 }
1381 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1382 cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
1383 break;
1384 case XML_ATTRIBUTE_NODE:
1385 break;
1386 case XML_TEXT_NODE:
1387 case XML_CDATA_SECTION_NODE:
1388 case XML_ENTITY_REF_NODE:
1389 case XML_ENTITY_NODE:
1390 case XML_PI_NODE:
1391 case XML_COMMENT_NODE:
1392 if (cur->content != NULL) free(cur->content);
1393 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1394 if (content != NULL)
1395 cur->content = xmlStrndup(content, len);
1396 else
1397 cur->content = NULL;
1398 case XML_DOCUMENT_NODE:
1399 case XML_DOCUMENT_TYPE_NODE:
1400 break;
1401 case XML_NOTATION_NODE:
1402 if (cur->content != NULL) free(cur->content);
1403 if (content != NULL)
1404 cur->content = xmlStrndup(content, len);
1405 else
1406 cur->content = NULL;
1407 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001408 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001409}
1410
Daniel Veillard97b58771998-10-20 06:14:16 +00001411/**
1412 * xmlNodeAddContentLen:
1413 * @cur: the node being modified
1414 * @content: extra content
1415 * @len: the size of @content
1416 *
1417 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001418 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001419void
1420xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001421 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001422 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1423 return;
1424 }
1425 if (len <= 0) return;
1426 switch (cur->type) {
1427 case XML_DOCUMENT_FRAG_NODE:
1428 case XML_ELEMENT_NODE: {
1429 xmlNodePtr last = NULL, new;
1430
1431 if (cur->childs != NULL) {
1432 last = cur->childs;
1433 while (last->next != NULL) last = last->next;
1434 } else {
1435 if (cur->content != NULL) {
1436 cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
1437 free(cur->content);
1438 cur->content = NULL;
1439 if (cur->childs != NULL) {
1440 last = cur->childs;
1441 while (last->next != NULL) last = last->next;
1442 }
1443 }
1444 }
1445 new = xmlStringLenGetNodeList(cur->doc, content, len);
1446 if (new != NULL) {
1447 xmlAddChild(cur, new);
1448 if ((last != NULL) && (last->next == new))
1449 xmlTextMerge(last, new);
1450 }
1451 break;
1452 }
1453 case XML_ATTRIBUTE_NODE:
1454 break;
1455 case XML_TEXT_NODE:
1456 case XML_CDATA_SECTION_NODE:
1457 case XML_ENTITY_REF_NODE:
1458 case XML_ENTITY_NODE:
1459 case XML_PI_NODE:
1460 case XML_COMMENT_NODE:
1461 if (content != NULL)
1462 cur->content = xmlStrncat(cur->content, content, len);
1463 case XML_DOCUMENT_NODE:
1464 case XML_DOCUMENT_TYPE_NODE:
1465 break;
1466 case XML_NOTATION_NODE:
1467 if (content != NULL)
1468 cur->content = xmlStrncat(cur->content, content, len);
1469 break;
1470 }
1471}
1472
1473/**
1474 * xmlNodeAddContent:
1475 * @cur: the node being modified
1476 * @content: extra content
1477 *
1478 * Append the extra substring to the node content.
1479 */
1480void
1481xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1482 int len;
1483
1484 if (cur == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001485 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1486 return;
1487 }
Daniel Veillard16253641998-10-28 22:58:05 +00001488 if (content == NULL) return;
1489 len = xmlStrlen(content);
1490 xmlNodeAddContentLen(cur, content, len);
1491}
1492
1493/**
1494 * xmlTextMerge:
1495 * @first: the first text node
1496 * @second: the second text node being merged
1497 *
1498 * Merge two text nodes into one
1499 * Return values: the first text node augmented
1500 */
1501xmlNodePtr
1502xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1503 if (first == NULL) return(second);
1504 if (second == NULL) return(first);
1505 if (first->type != XML_TEXT_NODE) return(first);
1506 if (second->type != XML_TEXT_NODE) return(first);
1507 xmlNodeAddContent(first, second->content);
1508 xmlUnlinkNode(second);
1509 xmlFreeNode(second);
1510 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001511}
1512
Daniel Veillard97b58771998-10-20 06:14:16 +00001513/**
1514 * xmlSearchNs:
1515 * @doc: the document
1516 * @node: the current node
1517 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00001518 *
Daniel Veillard97b58771998-10-20 06:14:16 +00001519 * Search a Ns registered under a given name space for a document.
1520 * recurse on the parents until it finds the defined namespace
1521 * or return NULL otherwise.
1522 * @nameSpace can be NULL, this is a search for the default namespace.
1523 * return values: the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001524 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001525xmlNsPtr
1526xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001527 xmlNsPtr cur;
1528
1529 while (node != NULL) {
1530 cur = node->nsDef;
1531 while (cur != NULL) {
1532 if ((cur->prefix == NULL) && (nameSpace == NULL))
1533 return(cur);
1534 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1535 (!xmlStrcmp(cur->prefix, nameSpace)))
1536 return(cur);
1537 cur = cur->next;
1538 }
1539 node = node->parent;
1540 }
1541 if (doc != NULL) {
1542 cur = doc->oldNs;
1543 while (cur != NULL) {
1544 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1545 (!xmlStrcmp(cur->prefix, nameSpace)))
1546 return(cur);
1547 cur = cur->next;
1548 }
1549 }
1550 return(NULL);
1551}
1552
Daniel Veillard97b58771998-10-20 06:14:16 +00001553/**
1554 * xmlSearchNsByHref:
1555 * @doc: the document
1556 * @node: the current node
1557 * @href: the namespace value
1558 *
1559 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1560 * the defined namespace or return NULL otherwise.
1561 * return values: the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001562 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001563xmlNsPtr
1564xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001565 xmlNsPtr cur;
1566
1567 while (node != NULL) {
1568 cur = node->nsDef;
1569 while (cur != NULL) {
1570 if ((cur->href != NULL) && (href != NULL) &&
1571 (!xmlStrcmp(cur->href, href)))
1572 return(cur);
1573 cur = cur->next;
1574 }
1575 node = node->parent;
1576 }
1577 if (doc != NULL) {
1578 cur = doc->oldNs;
1579 while (cur != NULL) {
1580 if ((cur->href != NULL) && (href != NULL) &&
1581 (!xmlStrcmp(cur->href, href)))
1582 return(cur);
1583 cur = cur->next;
1584 }
1585 }
1586 return(NULL);
1587}
1588
Daniel Veillard97b58771998-10-20 06:14:16 +00001589/**
1590 * xmlGetProp:
1591 * @node: the node
1592 * @name: the attribute name
1593 *
1594 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00001595 * This does the entity substitution.
Daniel Veillard97b58771998-10-20 06:14:16 +00001596 * return values: the attribute value or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001597 */
1598const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
1599 xmlAttrPtr prop = node->properties;
1600
1601 while (prop != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001602 if (!xmlStrcmp(prop->name, name))
1603 return(xmlNodeListGetString(node->doc, prop->val, 1));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001604 prop = prop->next;
1605 }
1606 return(NULL);
1607}
1608
Daniel Veillard97b58771998-10-20 06:14:16 +00001609/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001610 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00001611 * @node: the node
1612 * @name: the attribute name
1613 * @value: the attribute value
1614 *
1615 * Set (or reset) an attribute carried by a node.
1616 * return values: the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001617 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001618xmlAttrPtr
1619xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001620 xmlAttrPtr prop = node->properties;
1621
1622 while (prop != NULL) {
1623 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001624 if (prop->val != NULL)
1625 xmlFreeNode(prop->val);
1626 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001627 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001628 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001629 return(prop);
1630 }
1631 prop = prop->next;
1632 }
1633 prop = xmlNewProp(node, name, value);
1634 return(prop);
1635}
1636
Daniel Veillard97b58771998-10-20 06:14:16 +00001637/**
1638 * xmlNodeIsText:
1639 * @node: the node
1640 *
1641 * Is this node a Text node ?
1642 * return values: 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00001643 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001644int
1645xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001646 if (node == NULL) return(0);
1647
Daniel Veillard0bef1311998-10-14 02:36:47 +00001648 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001649 return(0);
1650}
1651
Daniel Veillard97b58771998-10-20 06:14:16 +00001652/**
1653 * xmlNodeIsText:
1654 * @node: the node
1655 * @content: the content
1656 * @len: @content lenght
1657 *
1658 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00001659 */
Daniel Veillard97b58771998-10-20 06:14:16 +00001660
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001661void
1662xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001663 if (node == NULL) return;
1664
Daniel Veillard0bef1311998-10-14 02:36:47 +00001665 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001666 fprintf(stderr, "xmlTextConcat: node is not text\n");
1667 return;
1668 }
1669 node->content = xmlStrncat(node->content, content, len);
1670}
1671
1672/************************************************************************
1673 * *
1674 * Output : to a FILE or in memory *
1675 * *
1676 ************************************************************************/
1677
Daniel Veillard260a68f1998-08-13 03:39:55 +00001678static CHAR *buffer = NULL;
1679static int buffer_index = 0;
1680static int buffer_size = 0;
1681
Daniel Veillard97b58771998-10-20 06:14:16 +00001682/**
1683 * xmlBufferWriteCHAR:
1684 * @string: the string to add
1685 *
1686 * routine which manage and grows an output buffer. This one add
1687 * CHARs at the end of the array.
1688 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001689void
1690xmlBufferWriteCHAR(const CHAR *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001691 const CHAR *cur;
1692
1693 if (buffer == NULL) {
1694 buffer_size = 50000;
1695 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
1696 if (buffer == NULL) {
1697 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
1698 exit(1);
1699 }
1700 }
1701
1702 if (string == NULL) return;
1703 for (cur = string;*cur != 0;cur++) {
1704 if (buffer_index + 10 >= buffer_size) {
1705 buffer_size *= 2;
1706 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
1707 if (buffer == NULL) {
1708 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
1709 exit(1);
1710 }
1711 }
1712 buffer[buffer_index++] = *cur;
1713 }
1714 buffer[buffer_index] = 0;
1715}
1716
Daniel Veillard97b58771998-10-20 06:14:16 +00001717/**
1718 * xmlBufferWriteChar:
1719 * @string: the string to add
1720 *
1721 * routine which manage and grows an output buffer. This one add
1722 * C chars at the end of the array.
1723 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001724void
1725xmlBufferWriteChar(const char *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001726 const char *cur;
1727
1728 if (buffer == NULL) {
1729 buffer_size = 50000;
1730 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
1731 if (buffer == NULL) {
1732 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
1733 exit(1);
1734 }
1735 }
1736
1737 if (string == NULL) return;
1738 for (cur = string;*cur != 0;cur++) {
1739 if (buffer_index + 10 >= buffer_size) {
1740 buffer_size *= 2;
1741 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
1742 if (buffer == NULL) {
1743 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
1744 exit(1);
1745 }
1746 }
1747 buffer[buffer_index++] = *cur;
1748 }
1749 buffer[buffer_index] = 0;
1750}
1751
Daniel Veillard97b58771998-10-20 06:14:16 +00001752/**
1753 * xmlGlobalNsDump:
1754 * @cur: a namespace
1755 *
1756 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001757 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001758static void
1759xmlGlobalNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001760 if (cur == NULL) {
1761 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
1762 return;
1763 }
1764 if (cur->type == XML_GLOBAL_NAMESPACE) {
1765 xmlBufferWriteChar("<?namespace");
1766 if (cur->href != NULL) {
1767 xmlBufferWriteChar(" href=\"");
1768 xmlBufferWriteCHAR(cur->href);
1769 xmlBufferWriteChar("\"");
1770 }
1771 if (cur->prefix != NULL) {
1772 xmlBufferWriteChar(" AS=\"");
1773 xmlBufferWriteCHAR(cur->prefix);
1774 xmlBufferWriteChar("\"");
1775 }
1776 xmlBufferWriteChar("?>\n");
1777 }
1778}
1779
Daniel Veillard97b58771998-10-20 06:14:16 +00001780/**
1781 * xmlGlobalNsListDump:
1782 * @cur: the first namespace
1783 *
1784 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001785 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001786static void
1787xmlGlobalNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001788 while (cur != NULL) {
1789 xmlGlobalNsDump(cur);
1790 cur = cur->next;
1791 }
1792}
1793
Daniel Veillard97b58771998-10-20 06:14:16 +00001794/**
1795 * xmlNsDump:
1796 * @cur: a namespace
1797 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001798 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00001799 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001800 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001801static void
1802xmlNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001803 if (cur == NULL) {
1804 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
1805 return;
1806 }
1807 if (cur->type == XML_LOCAL_NAMESPACE) {
1808 /* Within the context of an element attributes */
1809 if (cur->prefix != NULL) {
1810 xmlBufferWriteChar(" xmlns:");
1811 xmlBufferWriteCHAR(cur->prefix);
1812 } else
1813 xmlBufferWriteChar(" xmlns");
1814 xmlBufferWriteChar("=\"");
1815 xmlBufferWriteCHAR(cur->href);
1816 xmlBufferWriteChar("\"");
1817 }
1818}
1819
Daniel Veillard97b58771998-10-20 06:14:16 +00001820/**
1821 * xmlNsListDump:
1822 * @cur: the first namespace
1823 *
1824 * Dump a list of local Namespace definitions.
1825 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001826 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001827static void
1828xmlNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001829 while (cur != NULL) {
1830 xmlNsDump(cur);
1831 cur = cur->next;
1832 }
1833}
1834
Daniel Veillard97b58771998-10-20 06:14:16 +00001835/**
1836 * xmlDtdDump:
1837 * @doc: the document
1838 *
1839 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001840 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001841static void
1842xmlDtdDump(xmlDocPtr doc) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001843 xmlDtdPtr cur = doc->dtd;
1844
1845 if (cur == NULL) {
1846 fprintf(stderr, "xmlDtdDump : DTD == NULL\n");
1847 return;
1848 }
1849 xmlBufferWriteChar("<!DOCTYPE ");
1850 xmlBufferWriteCHAR(cur->name);
1851 if (cur->ExternalID != NULL) {
1852 xmlBufferWriteChar(" PUBLIC \"");
1853 xmlBufferWriteCHAR(cur->ExternalID);
1854 xmlBufferWriteChar("\" \"");
1855 xmlBufferWriteCHAR(cur->SystemID);
1856 xmlBufferWriteChar("\"");
1857 } else if (cur->SystemID != NULL) {
1858 xmlBufferWriteChar(" SYSTEM \"");
1859 xmlBufferWriteCHAR(cur->SystemID);
1860 xmlBufferWriteChar("\"");
1861 }
1862 if ((cur->entities == NULL) && (doc->entities == NULL)) {
1863 xmlBufferWriteChar(">\n");
1864 return;
1865 }
1866 xmlBufferWriteChar(" [\n");
1867 if (cur->entities != NULL)
1868 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1869 if (doc->entities != NULL)
1870 xmlDumpEntitiesTable((xmlEntitiesTablePtr) doc->entities);
1871 xmlBufferWriteChar("]");
1872
1873 /* TODO !!! a lot more things to dump ... */
1874 xmlBufferWriteChar(">\n");
1875}
1876
Daniel Veillard97b58771998-10-20 06:14:16 +00001877/**
1878 * xmlAttrDump:
1879 * @doc: the document
1880 * @cur: the attribute pointer
1881 *
1882 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00001883 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001884static void
1885xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001886 CHAR *value;
1887
Daniel Veillard260a68f1998-08-13 03:39:55 +00001888 if (cur == NULL) {
1889 fprintf(stderr, "xmlAttrDump : property == NULL\n");
1890 return;
1891 }
1892 xmlBufferWriteChar(" ");
1893 xmlBufferWriteCHAR(cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00001894 value = xmlNodeListGetString(doc, cur->val, 0);
1895 if (value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001896 xmlBufferWriteChar("=\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00001897 xmlBufferWriteCHAR(value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001898 xmlBufferWriteChar("\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00001899 free(value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001900 }
1901}
1902
Daniel Veillard97b58771998-10-20 06:14:16 +00001903/**
1904 * xmlAttrListDump:
1905 * @doc: the document
1906 * @cur: the first attribute pointer
1907 *
1908 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00001909 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001910static void
1911xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001912 if (cur == NULL) {
1913 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
1914 return;
1915 }
1916 while (cur != NULL) {
1917 xmlAttrDump(doc, cur);
1918 cur = cur->next;
1919 }
1920}
1921
Daniel Veillard260a68f1998-08-13 03:39:55 +00001922
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001923static void
1924xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00001925/**
1926 * xmlNodeListDump:
1927 * @doc: the document
1928 * @cur: the first node
1929 * @level: the imbrication level for indenting
1930 *
1931 * Dump an XML node list, recursive behaviour,children are printed too.
1932 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001933static void
1934xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001935 int needIndent = 0, i;
1936
Daniel Veillard260a68f1998-08-13 03:39:55 +00001937 if (cur == NULL) {
1938 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
1939 return;
1940 }
1941 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001942 if ((cur->type != XML_TEXT_NODE) &&
1943 (cur->type != XML_ENTITY_REF_NODE)) {
1944 if (!needIndent) {
1945 needIndent = 1;
1946 xmlBufferWriteChar("\n");
1947 }
1948 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001949 xmlNodeDump(doc, cur, level);
1950 cur = cur->next;
1951 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001952 if ((xmlIndentTreeOutput) && (needIndent))
1953 for (i = 1;i < level;i++)
1954 xmlBufferWriteChar(" ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001955}
1956
Daniel Veillard97b58771998-10-20 06:14:16 +00001957/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001958 * xmlNodeDump:
Daniel Veillard97b58771998-10-20 06:14:16 +00001959 * @doc: the document
1960 * @cur: the current node
1961 * @level: the imbrication level for indenting
1962 *
1963 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001964 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001965static void
1966xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001967 int i;
1968
1969 if (cur == NULL) {
1970 fprintf(stderr, "xmlNodeDump : node == NULL\n");
1971 return;
1972 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001973 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001974 if (cur->content != NULL)
1975 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
1976 return;
1977 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001978 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001979 if (cur->content != NULL) {
1980 xmlBufferWriteChar("<!--");
1981 xmlBufferWriteCHAR(cur->content);
1982 xmlBufferWriteChar("-->");
1983 }
1984 return;
1985 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001986 if (cur->type == XML_ENTITY_REF_NODE) {
1987 xmlBufferWriteChar("&");
1988 xmlBufferWriteCHAR(cur->name);
1989 xmlBufferWriteChar(";");
1990 return;
1991 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001992 if (xmlIndentTreeOutput)
1993 for (i = 0;i < level;i++)
1994 xmlBufferWriteChar(" ");
1995
1996 xmlBufferWriteChar("<");
1997 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1998 xmlBufferWriteCHAR(cur->ns->prefix);
1999 xmlBufferWriteChar(":");
2000 }
2001
2002 xmlBufferWriteCHAR(cur->name);
2003 if (cur->nsDef)
2004 xmlNsListDump(cur->nsDef);
2005 if (cur->properties != NULL)
2006 xmlAttrListDump(doc, cur->properties);
2007
2008 if ((cur->content == NULL) && (cur->childs == NULL)) {
2009 xmlBufferWriteChar("/>\n");
2010 return;
2011 }
2012 xmlBufferWriteChar(">");
2013 if (cur->content != NULL)
2014 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2015 if (cur->childs != NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002016 xmlNodeListDump(doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002017 }
2018 xmlBufferWriteChar("</");
2019 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2020 xmlBufferWriteCHAR(cur->ns->prefix);
2021 xmlBufferWriteChar(":");
2022 }
2023
2024 xmlBufferWriteCHAR(cur->name);
2025 xmlBufferWriteChar(">\n");
2026}
2027
Daniel Veillard97b58771998-10-20 06:14:16 +00002028/**
2029 * xmlDocContentDump:
2030 * @cur: the document
2031 *
2032 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002033 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002034static void
2035xmlDocContentDump(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002036 if (oldXMLWDcompatibility)
2037 xmlBufferWriteChar("<?XML version=\"");
2038 else
2039 xmlBufferWriteChar("<?xml version=\"");
2040 xmlBufferWriteCHAR(cur->version);
2041 xmlBufferWriteChar("\"");
2042 if (cur->encoding != NULL) {
2043 xmlBufferWriteChar(" encoding=\"");
2044 xmlBufferWriteCHAR(cur->encoding);
2045 xmlBufferWriteChar("\"");
2046 }
2047 switch (cur->standalone) {
2048 case 0:
2049 xmlBufferWriteChar(" standalone=\"no\"");
2050 break;
2051 case 1:
2052 xmlBufferWriteChar(" standalone=\"yes\"");
2053 break;
2054 }
2055 xmlBufferWriteChar("?>\n");
2056 if ((cur->dtd != NULL) || (cur->entities != NULL))
2057 xmlDtdDump(cur);
2058 if (cur->root != NULL) {
2059 /* global namespace definitions, the old way */
2060 if (oldXMLWDcompatibility)
2061 xmlGlobalNsListDump(cur->oldNs);
2062 else
2063 xmlUpgradeOldNs(cur);
2064 xmlNodeDump(cur, cur->root, 0);
2065 }
2066}
2067
Daniel Veillard97b58771998-10-20 06:14:16 +00002068/**
2069 * xmlDocDumpMemory:
2070 * @cur: the document
2071 * @mem: OUT: the memory pointer
2072 * @size: OUT: the memory lenght
2073 *
2074 * Dump an XML document in memory and return the CHAR * and it's size.
2075 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002076 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002077void
2078xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002079 if (cur == NULL) {
2080 fprintf(stderr, "xmlDocDump : document == NULL\n");
2081 *mem = NULL;
2082 *size = 0;
2083 return;
2084 }
2085 buffer_index = 0;
2086 xmlDocContentDump(cur);
2087
2088 *mem = buffer;
2089 *size = buffer_index;
2090}
2091
Daniel Veillard97b58771998-10-20 06:14:16 +00002092/**
2093 * xmlGetDocCompressMode:
2094 * @doc: the document
2095 *
2096 * get the compression ratio for a document, ZLIB based
2097 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002098 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002099int
2100 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002101 if (doc == NULL) return(-1);
2102 return(doc->compression);
2103}
2104
Daniel Veillard97b58771998-10-20 06:14:16 +00002105/**
2106 * xmlSetDocCompressMode:
2107 * @doc: the document
2108 * @mode: the compression ratio
2109 *
2110 * set the compression ratio for a document, ZLIB based
2111 * Correct values: 0 (uncompressed) to 9 (max compression)
2112 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002113void
2114xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002115 if (doc == NULL) return;
2116 if (mode < 0) doc->compression = 0;
2117 else if (mode > 9) doc->compression = 9;
2118 else doc->compression = mode;
2119}
2120
Daniel Veillard97b58771998-10-20 06:14:16 +00002121/**
2122 * xmlGetCompressMode:
2123 *
2124 * get the default compression mode used, ZLIB based.
2125 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002126 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002127int
2128 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002129 return(xmlCompressMode);
2130}
Daniel Veillard97b58771998-10-20 06:14:16 +00002131
2132/**
2133 * xmlSetCompressMode:
2134 * @mode: the compression ratio
2135 *
2136 * set the default compression mode used, ZLIB based
2137 * Correct values: 0 (uncompressed) to 9 (max compression)
2138 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002139void
2140xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002141 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002142 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002143 else xmlCompressMode = mode;
2144}
2145
Daniel Veillard97b58771998-10-20 06:14:16 +00002146/**
2147 * xmlDocDump:
2148 * @f: the FILE*
2149 * @cur: the document
2150 *
2151 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002152 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002153void
2154xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002155 if (cur == NULL) {
2156 fprintf(stderr, "xmlDocDump : document == NULL\n");
2157 return;
2158 }
2159 buffer_index = 0;
2160 xmlDocContentDump(cur);
2161
2162 fwrite(buffer, sizeof(CHAR), buffer_index, f);
2163}
2164
Daniel Veillard97b58771998-10-20 06:14:16 +00002165/**
2166 * xmlSaveFile:
2167 * @filename: the filename
2168 * @cur: the document
2169 *
2170 * Dump an XML document to a file. Will use compression if
2171 * compiled in and enabled.
2172 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002173 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002174int
2175xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002176#ifdef HAVE_ZLIB_H
2177 gzFile zoutput = NULL;
2178 char mode[15];
2179#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002180 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002181 int ret;
2182
2183#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002184 if ((cur->compression > 0) && (cur->compression <= 9)) {
2185 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002186 zoutput = gzopen(filename, mode);
2187 }
2188 if (zoutput == NULL) {
2189#endif
2190 output = fopen(filename, "w");
2191 if (output == NULL) return(-1);
2192#ifdef HAVE_ZLIB_H
2193 }
2194#endif
2195
2196 /*
2197 * save the content to a temp buffer.
2198 */
2199 buffer_index = 0;
2200 xmlDocContentDump(cur);
2201
2202#ifdef HAVE_ZLIB_H
2203 if (zoutput != NULL) {
2204 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
2205 gzclose(zoutput);
2206 return(ret);
2207 }
2208#endif
2209 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
2210 fclose(output);
2211 return(ret * sizeof(CHAR));
2212}
2213