blob: 5892a4e9e5b9f0781174f3980f2ced4a2be3969d [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 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00006 * TODO Cleanup the Dump mechanism.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00007 *
8 * Daniel.Veillard@w3.org
Daniel Veillard260a68f1998-08-13 03:39:55 +00009 */
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"
Daniel Veillard3b9def11999-01-31 22:15:06 +000023#include "valid.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000024
25static CHAR xmlStringText[] = { 't', 'e', 'x', 't', 0 };
26int oldXMLWDcompatibility = 0;
27int xmlIndentTreeOutput = 1;
28
Daniel Veillard15a8df41998-09-24 19:15:06 +000029static int xmlCompressMode = 0;
30
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000031#define UPDATE_LAST_CHILD(n) if ((n) != NULL) { \
32 xmlNodePtr ulccur = (n)->childs; \
33 if (ulccur == NULL) { \
34 (n)->last = NULL; \
35 } else { \
36 while (ulccur->next != NULL) ulccur = ulccur->next; \
37 (n)->last = ulccur; \
38} }
39
Daniel Veillard260a68f1998-08-13 03:39:55 +000040/************************************************************************
41 * *
42 * Allocation and deallocation of basic structures *
43 * *
44 ************************************************************************/
45
Daniel Veillard97b58771998-10-20 06:14:16 +000046/**
47 * xmlUpgradeOldNs:
48 * @doc: a document pointer
49 *
50 * Upgrade old style Namespaces (PI) and move them to the root of the document.
Daniel Veillard260a68f1998-08-13 03:39:55 +000051 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000052void
53xmlUpgradeOldNs(xmlDocPtr doc) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000054 xmlNsPtr cur;
55
56 if ((doc == NULL) || (doc->oldNs == NULL)) return;
57 if (doc->root == NULL) {
58 fprintf(stderr, "xmlUpgradeOldNs: failed no root !\n");
59 return;
60 }
61
62 cur = doc->oldNs;
63 while (cur->next != NULL) {
64 cur->type = XML_LOCAL_NAMESPACE;
65 cur = cur->next;
66 }
67 cur->type = XML_LOCAL_NAMESPACE;
68 cur->next = doc->root->nsDef;
69 doc->root->nsDef = doc->oldNs;
70 doc->oldNs = NULL;
71}
72
Daniel Veillard97b58771998-10-20 06:14:16 +000073/**
74 * xmlNewNs:
75 * @node: the element carrying the namespace
76 * @href: the URI associated
77 * @prefix: the prefix for the namespace
78 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000079 * Creation of a new Namespace.
Daniel Veillard97b58771998-10-20 06:14:16 +000080 * return values: returns a new namespace pointer
Daniel Veillard260a68f1998-08-13 03:39:55 +000081 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000082xmlNsPtr
83xmlNewNs(xmlNodePtr node, const CHAR *href, const CHAR *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000084 xmlNsPtr cur;
85
86 if (href == NULL) {
87 fprintf(stderr, "xmlNewNs: href == NULL !\n");
88 return(NULL);
89 }
90
91 /*
92 * Allocate a new DTD and fill the fields.
93 */
94 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
95 if (cur == NULL) {
96 fprintf(stderr, "xmlNewNs : malloc failed\n");
97 return(NULL);
98 }
99
100 cur->type = XML_LOCAL_NAMESPACE;
101 if (href != NULL)
102 cur->href = xmlStrdup(href);
103 else
104 cur->href = NULL;
105 if (prefix != NULL)
106 cur->prefix = xmlStrdup(prefix);
107 else
108 cur->prefix = NULL;
109
110 /*
111 * Add it at the end to preserve parsing order ...
112 */
113 cur->next = NULL;
114 if (node != NULL) {
115 if (node->nsDef == NULL) {
116 node->nsDef = cur;
117 } else {
118 xmlNsPtr prev = node->nsDef;
119
120 while (prev->next != NULL) prev = prev->next;
121 prev->next = cur;
122 }
123 }
124
125 return(cur);
126}
127
Daniel Veillard97b58771998-10-20 06:14:16 +0000128/**
129 * xmlNewGlobalNs:
130 * @doc: the document carrying the namespace
131 * @href: the URI associated
132 * @prefix: the prefix for the namespace
133 *
134 * Creation of a Namespace, the old way using PI and without scoping, to AVOID.
135 * return values: returns a new namespace pointer
Daniel Veillard260a68f1998-08-13 03:39:55 +0000136 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000137xmlNsPtr
138xmlNewGlobalNs(xmlDocPtr doc, const CHAR *href, const CHAR *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000139 xmlNsPtr cur;
140
141 /*
142 * Allocate a new DTD and fill the fields.
143 */
144 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
145 if (cur == NULL) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000146 fprintf(stderr, "xmlNewGlobalNs : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000147 return(NULL);
148 }
149
150 cur->type = XML_GLOBAL_NAMESPACE;
151 if (href != NULL)
152 cur->href = xmlStrdup(href);
153 else
154 cur->href = NULL;
155 if (prefix != NULL)
156 cur->prefix = xmlStrdup(prefix);
157 else
158 cur->prefix = NULL;
159
160 /*
161 * Add it at the end to preserve parsing order ...
162 */
163 cur->next = NULL;
164 if (doc != NULL) {
165 if (doc->oldNs == NULL) {
166 doc->oldNs = cur;
167 } else {
168 xmlNsPtr prev = doc->oldNs;
169
170 while (prev->next != NULL) prev = prev->next;
171 prev->next = cur;
172 }
173 }
174
175 return(cur);
176}
177
Daniel Veillard97b58771998-10-20 06:14:16 +0000178/**
179 * xmlSetNs:
180 * @node: a node in the document
181 * @ns: a namespace pointer
182 *
183 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000184 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000185void
186xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000187 if (node == NULL) {
188 fprintf(stderr, "xmlSetNs: node == NULL\n");
189 return;
190 }
191 node->ns = ns;
192}
193
Daniel Veillard97b58771998-10-20 06:14:16 +0000194/**
195 * xmlFreeNs:
196 * @cur: the namespace pointer
197 *
198 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000199 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000200void
201xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000202 if (cur == NULL) {
203 fprintf(stderr, "xmlFreeNs : ns == NULL\n");
204 return;
205 }
206 if (cur->href != NULL) free((char *) cur->href);
207 if (cur->prefix != NULL) free((char *) cur->prefix);
208 memset(cur, -1, sizeof(xmlNs));
209 free(cur);
210}
211
Daniel Veillard97b58771998-10-20 06:14:16 +0000212/**
213 * xmlFreeNsList:
214 * @cur: the first namespace pointer
215 *
216 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000217 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000218void
219xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000220 xmlNsPtr next;
221 if (cur == NULL) {
222 fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
223 return;
224 }
225 while (cur != NULL) {
226 next = cur->next;
227 xmlFreeNs(cur);
228 cur = next;
229 }
230}
231
Daniel Veillard97b58771998-10-20 06:14:16 +0000232/**
233 * xmlNewDtd:
234 * @doc: the document pointer
235 * @name: the DTD name
236 * @ExternalID: the external ID
237 * @SystemID: the system ID
238 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000239 * Creation of a new DTD.
Daniel Veillard97b58771998-10-20 06:14:16 +0000240 * return values: a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000241 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000242xmlDtdPtr
243xmlNewDtd(xmlDocPtr doc, const CHAR *name,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000244 const CHAR *ExternalID, const CHAR *SystemID) {
245 xmlDtdPtr cur;
246
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000247 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000248 fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000249 /* !!! */ (char *) name, doc->name,
250 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000251 }
252
253 /*
254 * Allocate a new DTD and fill the fields.
255 */
256 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
257 if (cur == NULL) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000258 fprintf(stderr, "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000259 return(NULL);
260 }
261
262 if (name != NULL)
263 cur->name = xmlStrdup(name);
264 else
265 cur->name = NULL;
266 if (ExternalID != NULL)
267 cur->ExternalID = xmlStrdup(ExternalID);
268 else
269 cur->ExternalID = NULL;
270 if (SystemID != NULL)
271 cur->SystemID = xmlStrdup(SystemID);
272 else
273 cur->SystemID = NULL;
274 cur->elements = NULL;
275 cur->entities = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000276 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000277 doc->extSubset = cur;
278
279 return(cur);
280}
281
282/**
283 * xmlCreateIntSubset:
284 * @doc: the document pointer
285 * @name: the DTD name
286 * @ExternalID: the external ID
287 * @SystemID: the system ID
288 *
289 * Creatte the internal subset of a document
290 * return values: a pointer to the new DTD structure
291 */
292xmlDtdPtr
293xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
294 const CHAR *ExternalID, const CHAR *SystemID) {
295 xmlDtdPtr cur;
296
297 if ((doc != NULL) && (doc->intSubset != NULL)) {
298 fprintf(stderr,
299 "xmlCreateIntSubset(): document %s already have an internal subset\n",
300 doc->name);
301 return(NULL);
302 }
303
304 /*
305 * Allocate a new DTD and fill the fields.
306 */
307 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
308 if (cur == NULL) {
309 fprintf(stderr, "xmlNewDtd : malloc failed\n");
310 return(NULL);
311 }
312
313 if (name != NULL)
314 cur->name = xmlStrdup(name);
315 else
316 cur->name = NULL;
317 if (ExternalID != NULL)
318 cur->ExternalID = xmlStrdup(ExternalID);
319 else
320 cur->ExternalID = NULL;
321 if (SystemID != NULL)
322 cur->SystemID = xmlStrdup(SystemID);
323 else
324 cur->SystemID = NULL;
325 cur->elements = NULL;
326 cur->entities = NULL;
327 if (doc != NULL)
328 doc->intSubset = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000329
330 return(cur);
331}
332
Daniel Veillard97b58771998-10-20 06:14:16 +0000333/**
334 * xmlFreeDtd:
335 * @cur: the DTD structure to free up
336 *
337 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000338 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000339void
340xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000341 if (cur == NULL) {
342 fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
343 return;
344 }
345 if (cur->name != NULL) free((char *) cur->name);
346 if (cur->SystemID != NULL) free((char *) cur->SystemID);
347 if (cur->ExternalID != NULL) free((char *) cur->ExternalID);
348 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000349 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000350 if (cur->entities != NULL)
351 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
352 memset(cur, -1, sizeof(xmlDtd));
353 free(cur);
354}
355
Daniel Veillard97b58771998-10-20 06:14:16 +0000356/**
357 * xmlNewDoc:
358 * @version: CHAR string giving the version of XML "1.0"
359 *
360 * Create a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000361 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000362xmlDocPtr
363xmlNewDoc(const CHAR *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000364 xmlDocPtr cur;
365
366 if (version == NULL) {
367 fprintf(stderr, "xmlNewDoc : version == NULL\n");
368 return(NULL);
369 }
370
371 /*
372 * Allocate a new document and fill the fields.
373 */
374 cur = (xmlDocPtr) malloc(sizeof(xmlDoc));
375 if (cur == NULL) {
376 fprintf(stderr, "xmlNewDoc : malloc failed\n");
377 return(NULL);
378 }
379
Daniel Veillard33942841998-10-18 19:12:41 +0000380 cur->type = XML_DOCUMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000381 cur->version = xmlStrdup(version);
382 cur->name = NULL;
383 cur->root = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000384 cur->intSubset = NULL;
385 cur->extSubset = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000386 cur->oldNs = NULL;
387 cur->encoding = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000388 cur->standalone = -1;
Daniel Veillard15a8df41998-09-24 19:15:06 +0000389 cur->compression = xmlCompressMode;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000390#ifndef WITHOUT_CORBA
391 cur->_private = NULL;
392 cur->vepv = NULL;
393#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000394 return(cur);
395}
396
Daniel Veillard97b58771998-10-20 06:14:16 +0000397/**
398 * xmlFreeDoc:
399 * @cur: pointer to the document
400 * @:
401 *
402 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000403 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000404void
405xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000406 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000407#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000408 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000409#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000410 return;
411 }
412 free((char *) cur->version);
413 if (cur->name != NULL) free((char *) cur->name);
414 if (cur->encoding != NULL) free((char *) cur->encoding);
415 if (cur->root != NULL) xmlFreeNode(cur->root);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000416 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
417 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000418 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000419 memset(cur, -1, sizeof(xmlDoc));
420 free(cur);
421}
422
Daniel Veillard97b58771998-10-20 06:14:16 +0000423/**
Daniel Veillard16253641998-10-28 22:58:05 +0000424 * xmlStringLenGetNodeList:
425 * @doc: the document
426 * @value: the value of the text
427 * @int len: the length of the string value
428 *
429 * Parse the value string and build the node list associated. Should
430 * produce a flat tree with only TEXTs and ENTITY_REFs.
431 * return values: a pointer to the first child
432 */
433xmlNodePtr
434xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
435 xmlNodePtr ret = NULL, last = NULL;
436 xmlNodePtr node;
437 CHAR *val;
438 const CHAR *cur = value;
439 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000440 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000441
442 if (value == NULL) return(NULL);
443
444 q = cur;
445 while ((*cur != 0) && (cur - value < len)) {
446 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000447 /*
448 * Save the current text.
449 */
Daniel Veillard16253641998-10-28 22:58:05 +0000450 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000451 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
452 xmlNodeAddContentLen(last, q, cur - q);
453 } else {
454 node = xmlNewDocTextLen(doc, q, cur - q);
455 if (node == NULL) return(ret);
456 if (last == NULL)
457 last = ret = node;
458 else {
459 last->next = node;
460 node->prev = last;
461 last = node;
462 }
Daniel Veillard16253641998-10-28 22:58:05 +0000463 }
464 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000465 /*
466 * Read the entity string
467 */
Daniel Veillard16253641998-10-28 22:58:05 +0000468 cur++;
469 q = cur;
470 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
471 if ((*cur == 0) || (cur - value >= len)) {
472 fprintf(stderr,
473 "xmlStringGetNodeList: unterminated entity %30s\n", q);
474 return(ret);
475 }
476 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000477 /*
478 * Predefined entities don't generate nodes
479 */
Daniel Veillard16253641998-10-28 22:58:05 +0000480 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000481 ent = xmlGetDocEntity(doc, val);
482 if ((ent != NULL) &&
483 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
484 if (last == NULL) {
485 node = xmlNewDocText(doc, ent->content);
486 last = ret = node;
487 } else
488 xmlNodeAddContent(last, ent->content);
489
490 } else {
491 /*
492 * Create a new REFERENCE_REF node
493 */
494 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000495 if (node == NULL) {
496 if (val != NULL) free(val);
497 return(ret);
498 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000499 if (last == NULL)
500 last = ret = node;
501 else {
502 last->next = node;
503 node->prev = last;
504 last = node;
505 }
Daniel Veillard16253641998-10-28 22:58:05 +0000506 }
507 free(val);
508 }
509 cur++;
510 q = cur;
511 } else
512 cur++;
513 }
514 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000515 /*
516 * Handle the last piece of text.
517 */
518 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
519 xmlNodeAddContentLen(last, q, cur - q);
520 } else {
521 node = xmlNewDocTextLen(doc, q, cur - q);
522 if (node == NULL) return(ret);
523 if (last == NULL)
524 last = ret = node;
525 else {
526 last->next = node;
527 node->prev = last;
528 last = node;
529 }
Daniel Veillard16253641998-10-28 22:58:05 +0000530 }
531 }
532 return(ret);
533}
534
535/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000536 * xmlStringGetNodeList:
537 * @doc: the document
538 * @value: the value of the attribute
539 *
540 * Parse the value string and build the node list associated. Should
541 * produce a flat tree with only TEXTs and ENTITY_REFs.
542 * return values: a pointer to the first child
543 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000544xmlNodePtr
545xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000546 xmlNodePtr ret = NULL, last = NULL;
547 xmlNodePtr node;
548 CHAR *val;
549 const CHAR *cur = value;
550 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000551 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000552
553 if (value == NULL) return(NULL);
554
555 q = cur;
556 while (*cur != 0) {
557 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000558 /*
559 * Save the current text.
560 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000561 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000562 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
563 xmlNodeAddContentLen(last, q, cur - q);
564 } else {
565 node = xmlNewDocTextLen(doc, q, cur - q);
566 if (node == NULL) return(ret);
567 if (last == NULL)
568 last = ret = node;
569 else {
570 last->next = node;
571 node->prev = last;
572 last = node;
573 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000574 }
575 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000576 /*
577 * Read the entity string
578 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000579 cur++;
580 q = cur;
581 while ((*cur != 0) && (*cur != ';')) cur++;
582 if (*cur == 0) {
583 fprintf(stderr,
584 "xmlStringGetNodeList: unterminated entity %30s\n", q);
585 return(ret);
586 }
587 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000588 /*
589 * Predefined entities don't generate nodes
590 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000591 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000592 ent = xmlGetDocEntity(doc, val);
593 if ((ent != NULL) &&
594 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
595 if (last == NULL) {
596 node = xmlNewDocText(doc, ent->content);
597 last = ret = node;
598 } else
599 xmlNodeAddContent(last, ent->content);
600
601 } else {
602 /*
603 * Create a new REFERENCE_REF node
604 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000605 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000606 if (node == NULL) {
607 if (val != NULL) free(val);
608 return(ret);
609 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000610 if (last == NULL)
611 last = ret = node;
612 else {
613 last->next = node;
614 node->prev = last;
615 last = node;
616 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000617 }
618 free(val);
619 }
620 cur++;
621 q = cur;
622 } else
623 cur++;
624 }
625 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000626 /*
627 * Handle the last piece of text.
628 */
629 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
630 xmlNodeAddContentLen(last, q, cur - q);
631 } else {
632 node = xmlNewDocTextLen(doc, q, cur - q);
633 if (node == NULL) return(ret);
634 if (last == NULL)
635 last = ret = node;
636 else {
637 last->next = node;
638 node->prev = last;
639 last = node;
640 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000641 }
642 }
643 return(ret);
644}
645
646/**
647 * xmlNodeListGetString:
648 * @doc: the document
649 * @list: a Node list
650 * @inLine: should we replace entity contents or show their external form
651 *
652 * Returns the string equivalent to the text contained in the Node list
653 * made of TEXTs and ENTITY_REFs
654 * return values: a pointer to the string copy, the calller must free it.
655 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000656CHAR *
657xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000658 xmlNodePtr node = list;
659 CHAR *ret = NULL;
660 xmlEntityPtr ent;
661
662 if (list == NULL) return(NULL);
663
664 while (node != NULL) {
665 if (node->type == XML_TEXT_NODE) {
666 if (inLine)
667 ret = xmlStrcat(ret, node->content);
668 else
669 ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
670 } else if (node->type == XML_ENTITY_REF_NODE) {
671 if (inLine) {
672 ent = xmlGetDocEntity(doc, node->name);
673 if (ent != NULL)
674 ret = xmlStrcat(ret, ent->content);
675 else
676 ret = xmlStrcat(ret, node->content);
677 } else {
678 CHAR buf[2];
679 buf[0] = '&'; buf[1] = 0;
680 ret = xmlStrncat(ret, buf, 1);
681 ret = xmlStrcat(ret, node->name);
682 buf[0] = ';'; buf[1] = 0;
683 ret = xmlStrncat(ret, buf, 1);
684 }
685 }
686#if 0
687 else {
688 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
689 node->type);
690 }
691#endif
692 node = node->next;
693 }
694 return(ret);
695}
696
697/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000698 * xmlNewProp:
699 * @node: the holding node
700 * @name: the name of the attribute
701 * @value: the value of the attribute
702 *
703 * Create a new property carried by a node.
704 * return values: a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000705 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000706xmlAttrPtr
707xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000708 xmlAttrPtr cur;
709
710 if (name == NULL) {
711 fprintf(stderr, "xmlNewProp : name == NULL\n");
712 return(NULL);
713 }
714
715 /*
716 * Allocate a new property and fill the fields.
717 */
718 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
719 if (cur == NULL) {
720 fprintf(stderr, "xmlNewProp : malloc failed\n");
721 return(NULL);
722 }
723
Daniel Veillard33942841998-10-18 19:12:41 +0000724 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000725 cur->node = node;
726 cur->name = xmlStrdup(name);
727 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +0000728 cur->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000729 else
Daniel Veillardccb09631998-10-27 06:21:04 +0000730 cur->val = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000731#ifndef WITHOUT_CORBA
732 cur->_private = NULL;
733 cur->vepv = NULL;
734#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000735
736 /*
737 * Add it at the end to preserve parsing order ...
738 */
739 cur->next = NULL;
740 if (node != NULL) {
741 if (node->properties == NULL) {
742 node->properties = cur;
743 } else {
744 xmlAttrPtr prev = node->properties;
745
746 while (prev->next != NULL) prev = prev->next;
747 prev->next = cur;
748 }
749 }
750 return(cur);
751}
752
Daniel Veillard97b58771998-10-20 06:14:16 +0000753/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000754 * xmlNewDocProp:
755 * @doc: the document
756 * @name: the name of the attribute
757 * @value: the value of the attribute
758 *
759 * Create a new property carried by a document.
760 * return values: a pointer to the attribute
761 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000762xmlAttrPtr
763xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000764 xmlAttrPtr cur;
765
766 if (name == NULL) {
767 fprintf(stderr, "xmlNewProp : name == NULL\n");
768 return(NULL);
769 }
770
771 /*
772 * Allocate a new property and fill the fields.
773 */
774 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
775 if (cur == NULL) {
776 fprintf(stderr, "xmlNewProp : malloc failed\n");
777 return(NULL);
778 }
779
780 cur->type = XML_ATTRIBUTE_NODE;
781 cur->node = NULL;
782 cur->name = xmlStrdup(name);
783 if (value != NULL)
784 cur->val = xmlStringGetNodeList(doc, value);
785 else
786 cur->val = NULL;
787#ifndef WITHOUT_CORBA
788 cur->_private = NULL;
789 cur->vepv = NULL;
790#endif
791
792 cur->next = NULL;
793 return(cur);
794}
795
796/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000797 * xmlFreePropList:
798 * @cur: the first property in the list
799 *
800 * Free a property and all its siblings, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000801 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000802void
803xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000804 xmlAttrPtr next;
805 if (cur == NULL) {
806 fprintf(stderr, "xmlFreePropList : property == NULL\n");
807 return;
808 }
809 while (cur != NULL) {
810 next = cur->next;
811 xmlFreeProp(cur);
812 cur = next;
813 }
814}
815
Daniel Veillard97b58771998-10-20 06:14:16 +0000816/**
817 * xmlFreeProp:
818 * @cur: the first property in the list
819 *
820 * Free one property, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000821 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000822void
823xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000824 if (cur == NULL) {
825 fprintf(stderr, "xmlFreeProp : property == NULL\n");
826 return;
827 }
828 if (cur->name != NULL) free((char *) cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +0000829 if (cur->val != NULL) xmlFreeNodeList(cur->val);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000830 memset(cur, -1, sizeof(xmlAttr));
831 free(cur);
832}
833
Daniel Veillard97b58771998-10-20 06:14:16 +0000834/**
835 * xmlNewNode:
836 * @ns: namespace if any
837 * @name: the node name
838 * @content: the text content if any
839 *
840 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +0000841 * If content is non NULL, a child list containing the TEXTs and
842 * ENTITY_REFs node will be created.
Daniel Veillard97b58771998-10-20 06:14:16 +0000843 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000844 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000845xmlNodePtr
846xmlNewNode(xmlNsPtr ns, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000847 xmlNodePtr cur;
848
849 if (name == NULL) {
850 fprintf(stderr, "xmlNewNode : name == NULL\n");
851 return(NULL);
852 }
853
854 /*
855 * Allocate a new node and fill the fields.
856 */
857 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
858 if (cur == NULL) {
859 fprintf(stderr, "xmlNewNode : malloc failed\n");
860 return(NULL);
861 }
862
Daniel Veillard33942841998-10-18 19:12:41 +0000863 cur->type = XML_ELEMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000864 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000865 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000866 cur->next = NULL;
867 cur->prev = NULL;
868 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000869 cur->last = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000870 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000871 cur->name = xmlStrdup(name);
872 cur->ns = ns;
873 cur->nsDef = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000874 cur->content = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000875#ifndef WITHOUT_CORBA
876 cur->_private = NULL;
877 cur->vepv = NULL;
878#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000879 return(cur);
880}
881
Daniel Veillard97b58771998-10-20 06:14:16 +0000882/**
883 * xmlNewDocNode:
884 * @doc: the document
885 * @ns: namespace if any
886 * @name: the node name
887 * @content: the text content if any
888 *
889 * Creation of a new node element within a document. @ns and @content
890 * are optionnal (NULL).
891 * return values: a pointer to the new node object.
892 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000893xmlNodePtr
894xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard0bef1311998-10-14 02:36:47 +0000895 const CHAR *name, CHAR *content) {
896 xmlNodePtr cur;
897
Daniel Veillardccb09631998-10-27 06:21:04 +0000898 cur = xmlNewNode(ns, name);
899 if (cur != NULL) {
900 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000901 if (content != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000902 cur->childs = xmlStringGetNodeList(doc, content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000903 UPDATE_LAST_CHILD(cur);
904 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000905 }
Daniel Veillard0bef1311998-10-14 02:36:47 +0000906 return(cur);
907}
908
909
Daniel Veillard97b58771998-10-20 06:14:16 +0000910/**
911 * xmlNewText:
912 * @content: the text content
913 *
914 * Creation of a new text node.
915 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000916 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000917xmlNodePtr
918xmlNewText(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000919 xmlNodePtr cur;
920
921 /*
922 * Allocate a new node and fill the fields.
923 */
924 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
925 if (cur == NULL) {
926 fprintf(stderr, "xmlNewText : malloc failed\n");
927 return(NULL);
928 }
929
Daniel Veillard33942841998-10-18 19:12:41 +0000930 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000931 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000932 cur->parent = NULL;
933 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000934 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000935 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000936 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000937 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000938 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000939 cur->name = xmlStrdup(xmlStringText);
940 cur->ns = NULL;
941 cur->nsDef = NULL;
942 if (content != NULL)
943 cur->content = xmlStrdup(content);
944 else
945 cur->content = NULL;
946 return(cur);
947}
948
Daniel Veillard97b58771998-10-20 06:14:16 +0000949/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000950 * xmlNewReference:
951 * @doc: the document
952 * @name: the reference name, or the reference string with & and ;
953 *
954 * Creation of a new reference node.
955 * return values: a pointer to the new node object.
956 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000957xmlNodePtr
958xmlNewReference(xmlDocPtr doc, const CHAR *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000959 xmlNodePtr cur;
960 xmlEntityPtr ent;
961
962 /*
963 * Allocate a new node and fill the fields.
964 */
965 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
966 if (cur == NULL) {
967 fprintf(stderr, "xmlNewText : malloc failed\n");
968 return(NULL);
969 }
970
971 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillard10c6a8f1998-10-28 01:00:12 +0000972 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +0000973 cur->parent = NULL;
974 cur->next = NULL;
975 cur->prev = NULL;
976 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000977 cur->last = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000978 cur->properties = NULL;
979 if (name[0] == '&') {
980 int len;
981 name++;
982 len = xmlStrlen(name);
983 if (name[len - 1] == ';')
984 cur->name = xmlStrndup(name, len - 1);
985 else
986 cur->name = xmlStrndup(name, len);
987 } else
988 cur->name = xmlStrdup(name);
989 cur->ns = NULL;
990 cur->nsDef = NULL;
991
992 ent = xmlGetDocEntity(doc, cur->name);
993 if (ent != NULL)
994 cur->content = ent->content;
995 else
996 cur->content = NULL;
997 return(cur);
998}
999
1000/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001001 * xmlNewDocText:
1002 * @doc: the document
1003 * @content: the text content
1004 *
1005 * Creation of a new text node within a document.
1006 * return values: a pointer to the new node object.
1007 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001008xmlNodePtr
1009xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001010 xmlNodePtr cur;
1011
1012 cur = xmlNewText(content);
1013 if (cur != NULL) cur->doc = doc;
1014 return(cur);
1015}
1016
Daniel Veillard97b58771998-10-20 06:14:16 +00001017/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001018 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001019 * @content: the text content
1020 * @len: the text len.
1021 *
1022 * Creation of a new text node with an extra parameter for the content's lenght
1023 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001024 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001025xmlNodePtr
1026xmlNewTextLen(const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001027 xmlNodePtr cur;
1028
1029 /*
1030 * Allocate a new node and fill the fields.
1031 */
1032 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1033 if (cur == NULL) {
1034 fprintf(stderr, "xmlNewText : malloc failed\n");
1035 return(NULL);
1036 }
1037
Daniel Veillard33942841998-10-18 19:12:41 +00001038 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001039 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001040 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001041 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001042 cur->next = NULL;
1043 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001044 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001045 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001046 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001047 cur->name = xmlStrdup(xmlStringText);
1048 cur->ns = NULL;
1049 cur->nsDef = NULL;
1050 if (content != NULL)
1051 cur->content = xmlStrndup(content, len);
1052 else
1053 cur->content = NULL;
1054 return(cur);
1055}
1056
Daniel Veillard97b58771998-10-20 06:14:16 +00001057/**
1058 * xmlNewDocTextLen:
1059 * @doc: the document
1060 * @content: the text content
1061 * @len: the text len.
1062 *
1063 * Creation of a new text node with an extra content lenght parameter. The
1064 * text node pertain to a given document.
1065 * return values: a pointer to the new node object.
1066 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001067xmlNodePtr
1068xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001069 xmlNodePtr cur;
1070
1071 cur = xmlNewTextLen(content, len);
1072 if (cur != NULL) cur->doc = doc;
1073 return(cur);
1074}
1075
Daniel Veillard97b58771998-10-20 06:14:16 +00001076/**
1077 * xmlNewComment:
1078 * @content: the comment content
1079 *
1080 * Creation of a new node containing a comment.
1081 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001082 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001083xmlNodePtr
1084xmlNewComment(CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001085 xmlNodePtr cur;
1086
1087 /*
1088 * Allocate a new node and fill the fields.
1089 */
1090 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1091 if (cur == NULL) {
1092 fprintf(stderr, "xmlNewComment : malloc failed\n");
1093 return(NULL);
1094 }
1095
Daniel Veillard33942841998-10-18 19:12:41 +00001096 cur->type = XML_COMMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001097 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001098 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001099 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001100 cur->next = NULL;
1101 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001102 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001103 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001104 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001105 cur->name = xmlStrdup(xmlStringText);
1106 cur->ns = NULL;
1107 cur->nsDef = NULL;
1108 if (content != NULL)
1109 cur->content = xmlStrdup(content);
1110 else
1111 cur->content = NULL;
1112 return(cur);
1113}
1114
Daniel Veillard97b58771998-10-20 06:14:16 +00001115/**
1116 * xmlNewComment:
1117 * @doc: the document
1118 * @content: the comment content
1119 *
1120 * Creation of a new node containing a commentwithin a document.
1121 * return values: a pointer to the new node object.
1122 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001123xmlNodePtr
1124xmlNewDocComment(xmlDocPtr doc, CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001125 xmlNodePtr cur;
1126
1127 cur = xmlNewComment(content);
1128 if (cur != NULL) cur->doc = doc;
1129 return(cur);
1130}
1131
Daniel Veillard97b58771998-10-20 06:14:16 +00001132/**
1133 * xmlNewChild:
1134 * @parent: the parent node
1135 * @ns: a namespace if any
1136 * @name: the name of the child
1137 * @content: the content of the child if any.
1138 *
1139 *
1140 * Creation of a new child element, added at the end of @parent childs list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001141 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1142 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard97b58771998-10-20 06:14:16 +00001143 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001144 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001145xmlNodePtr
1146xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001147 const CHAR *name, CHAR *content) {
1148 xmlNodePtr cur, prev;
1149
1150 if (parent == NULL) {
1151 fprintf(stderr, "xmlNewChild : parent == NULL\n");
1152 return(NULL);
1153 }
1154
1155 if (name == NULL) {
1156 fprintf(stderr, "xmlNewChild : name == NULL\n");
1157 return(NULL);
1158 }
1159
1160 /*
1161 * Allocate a new node
1162 */
1163 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001164 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001165 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001166 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001167 if (cur == NULL) return(NULL);
1168
1169 /*
1170 * add the new element at the end of the childs list.
1171 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001172 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001173 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001174 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001175 if (parent->childs == NULL) {
1176 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001177 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001178 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001179 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001180 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001181 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001182 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001183 }
1184
1185 return(cur);
1186}
1187
Daniel Veillard97b58771998-10-20 06:14:16 +00001188/**
1189 * xmlAddChild:
1190 * @parent: the parent node
1191 * @cur: the child node
1192 *
1193 * Add a new child element, to @parent, at the end of the child list.
1194 * return values: the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001195 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001196xmlNodePtr
1197xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001198 xmlNodePtr prev;
1199
1200 if (parent == NULL) {
1201 fprintf(stderr, "xmladdChild : parent == NULL\n");
1202 return(NULL);
1203 }
1204
1205 if (cur == NULL) {
1206 fprintf(stderr, "xmladdChild : child == NULL\n");
1207 return(NULL);
1208 }
1209
Daniel Veillard0bef1311998-10-14 02:36:47 +00001210 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1211 (cur->doc != parent->doc)) {
1212 fprintf(stderr, "Elements moved to a different document\n");
1213 }
1214
Daniel Veillard260a68f1998-08-13 03:39:55 +00001215 /*
1216 * add the new element at the end of the childs list.
1217 */
1218 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001219 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001220
Daniel Veillardccb09631998-10-27 06:21:04 +00001221 /*
1222 * Handle the case where parent->content != NULL, in that case it will
1223 * create a intermediate TEXT node.
1224 */
1225 if (parent->content != NULL) {
1226 xmlNodePtr text;
1227
1228 text = xmlNewDocText(parent->doc, parent->content);
1229 if (text != NULL) {
1230 text->next = parent->childs;
1231 if (text->next != NULL)
1232 text->next->prev = text;
1233 parent->childs = text;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001234 UPDATE_LAST_CHILD(parent);
Daniel Veillardccb09631998-10-27 06:21:04 +00001235 free(parent->content);
1236 parent->content = NULL;
1237 }
1238 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001239 if (parent->childs == NULL) {
1240 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001241 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001242 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001243 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001244 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001245 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001246 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001247 }
1248
1249 return(cur);
1250}
1251
Daniel Veillard97b58771998-10-20 06:14:16 +00001252/**
1253 * xmlGetLastChild:
1254 * @parent: the parent node
1255 *
1256 * Search the last child of a node.
1257 * return values: the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001258 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001259xmlNodePtr
1260xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001261 if (parent == NULL) {
1262 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1263 return(NULL);
1264 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001265 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001266}
1267
Daniel Veillard97b58771998-10-20 06:14:16 +00001268/**
1269 * xmlFreeNodeList:
1270 * @cur: the first node in the list
1271 *
1272 * Free a node and all its siblings, this is a recursive behaviour, all
1273 * the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001274 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001275void
1276xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001277 xmlNodePtr next;
1278 if (cur == NULL) {
1279 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1280 return;
1281 }
1282 while (cur != NULL) {
1283 next = cur->next;
1284 xmlFreeNode(cur);
1285 cur = next;
1286 }
1287}
1288
Daniel Veillard97b58771998-10-20 06:14:16 +00001289/**
1290 * xmlFreeNode:
1291 * @cur: the node
1292 *
1293 * Free a node, this is a recursive behaviour, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001294 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001295void
1296xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001297 if (cur == NULL) {
1298 fprintf(stderr, "xmlFreeNode : node == NULL\n");
1299 return;
1300 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001301 cur->doc = NULL;
1302 cur->parent = NULL;
1303 cur->next = NULL;
1304 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001305 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
Daniel Veillardccb09631998-10-27 06:21:04 +00001306 if (cur->properties != NULL) xmlFreePropList(cur->properties);
1307 if (cur->type != XML_ENTITY_REF_NODE)
1308 if (cur->content != NULL) free(cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001309 if (cur->name != NULL) free((char *) cur->name);
1310 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1311 memset(cur, -1, sizeof(xmlNode));
1312 free(cur);
1313}
1314
Daniel Veillard16253641998-10-28 22:58:05 +00001315/**
1316 * xmlUnlinkNode:
1317 * @cur: the node
1318 *
1319 * Unlink a node from it's current context, the node is not freed
1320 */
1321void
1322xmlUnlinkNode(xmlNodePtr cur) {
1323 if (cur == NULL) {
1324 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1325 return;
1326 }
1327 if ((cur->parent != NULL) && (cur->parent->childs == cur))
1328 cur->parent->childs = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001329 if ((cur->parent != NULL) && (cur->parent->last == cur))
1330 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00001331 if (cur->next != NULL)
1332 cur->next->prev = cur->prev;
1333 if (cur->prev != NULL)
1334 cur->prev->next = cur->next;
1335 cur->next = cur->prev = NULL;
1336 cur->parent = NULL;
1337}
1338
Daniel Veillard260a68f1998-08-13 03:39:55 +00001339/************************************************************************
1340 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001341 * Copy operations *
1342 * *
1343 ************************************************************************/
1344
1345/**
1346 * xmlCopyNamespace:
1347 * @cur: the namespace
1348 *
1349 * Do a copy of the namespace.
1350 *
1351 * Returns: a new xmlNsPtr, or NULL in case of error.
1352 */
1353xmlNsPtr
1354xmlCopyNamespace(xmlNsPtr cur) {
1355 xmlNsPtr ret;
1356
1357 if (cur == NULL) return(NULL);
1358 switch (cur->type) {
1359 case XML_GLOBAL_NAMESPACE:
1360 ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
1361 break;
1362 case XML_LOCAL_NAMESPACE:
1363 ret = xmlNewNs(NULL, cur->href, cur->prefix);
1364 break;
1365 default:
1366 fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
1367 return(NULL);
1368 }
1369 return(ret);
1370}
1371
1372/**
1373 * xmlCopyNamespaceList:
1374 * @cur: the first namespace
1375 *
1376 * Do a copy of an namespace list.
1377 *
1378 * Returns: a new xmlNsPtr, or NULL in case of error.
1379 */
1380xmlNsPtr
1381xmlCopyNamespaceList(xmlNsPtr cur) {
1382 xmlNsPtr ret = NULL;
1383 xmlNsPtr p = NULL,q;
1384
1385 while (cur != NULL) {
1386 q = xmlCopyNamespace(cur);
1387 if (p == NULL) {
1388 ret = p = q;
1389 } else {
1390 p->next = q;
1391 p = q;
1392 }
1393 cur = cur->next;
1394 }
1395 return(ret);
1396}
1397
1398/**
1399 * xmlCopyProp:
1400 * @cur: the attribute
1401 *
1402 * Do a copy of the attribute.
1403 *
1404 * Returns: a new xmlAttrPtr, or NULL in case of error.
1405 */
1406xmlAttrPtr
1407xmlCopyProp(xmlAttrPtr cur) {
1408 xmlAttrPtr ret;
1409
1410 if (cur == NULL) return(NULL);
1411 if (cur->val != NULL)
1412 ret = xmlNewDocProp(cur->val->doc, cur->name, NULL);
1413 else
1414 ret = xmlNewDocProp(NULL, cur->name, NULL);
1415 if (ret == NULL) return(NULL);
1416 if (cur->val != NULL)
1417 ret->val = xmlCopyNodeList(cur->val);
1418 return(ret);
1419}
1420
1421/**
1422 * xmlCopyPropList:
1423 * @cur: the first attribute
1424 *
1425 * Do a copy of an attribute list.
1426 *
1427 * Returns: a new xmlAttrPtr, or NULL in case of error.
1428 */
1429xmlAttrPtr
1430xmlCopyPropList(xmlAttrPtr cur) {
1431 xmlAttrPtr ret = NULL;
1432 xmlAttrPtr p = NULL,q;
1433
1434 while (cur != NULL) {
1435 q = xmlCopyProp(cur);
1436 if (p == NULL) {
1437 ret = p = q;
1438 } else {
1439 p->next = q;
1440 p = q;
1441 }
1442 cur = cur->next;
1443 }
1444 return(ret);
1445}
1446
1447/*
1448 * NOTE about the CopyNode operations !
1449 *
1450 * They are splitted into external and internal parts for one
1451 * tricky reason: namespaces. Doing a direct copy of a node
1452 * say RPM:Copyright without changing the namespace pointer to
1453 * something else can produce stale links. One way to do it is
1454 * to keep a reference counter but this doesn't work as soon
1455 * as one move the element or the subtree out of the scope of
1456 * the existing namespace. The actual solution seems to add
1457 * a copy of the namespace at the top of the copied tree if
1458 * not available in the subtree.
1459 * Hence two functions, the public front-end call the inner ones
1460 */
1461
1462static xmlNodePtr
1463xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
1464
1465static xmlNodePtr
1466xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
1467 int recursive) {
1468 xmlNodePtr ret;
1469
1470 if (node == NULL) return(NULL);
1471 /*
1472 * Allocate a new node and fill the fields.
1473 */
1474 ret = (xmlNodePtr) malloc(sizeof(xmlNode));
1475 if (ret == NULL) {
1476 fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
1477 return(NULL);
1478 }
1479
1480 ret->type = node->type;
1481 ret->doc = doc;
1482 ret->parent = parent;
1483 ret->next = NULL;
1484 ret->prev = NULL;
1485 ret->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001486 ret->last = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001487 ret->properties = NULL;
1488 if (node->name != NULL)
1489 ret->name = xmlStrdup(node->name);
1490 else
1491 ret->name = NULL;
1492 ret->ns = NULL;
1493 ret->nsDef = NULL;
1494 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE))
1495 ret->content = xmlStrdup(node->content);
1496 else
1497 ret->content = NULL;
1498#ifndef WITHOUT_CORBA
1499 ret->_private = NULL;
1500 ret->vepv = NULL;
1501#endif
1502 if (parent != NULL)
1503 xmlAddChild(parent, ret);
1504
1505 if (!recursive) return(ret);
1506 if (node->properties != NULL)
1507 ret->properties = xmlCopyPropList(node->properties);
1508 if (node->nsDef != NULL)
1509 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
1510
1511 if (node->ns != NULL) {
1512 xmlNsPtr ns;
1513
1514 ns = xmlSearchNs(doc, ret, node->ns->prefix);
1515 if (ns == NULL) {
1516 /*
1517 * Humm, we are copying an element whose namespace is defined
1518 * out of the new tree scope. Search it in the original tree
1519 * and add it at the top of the new tree
1520 */
1521 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
1522 if (ns != NULL) {
1523 xmlNodePtr root = ret;
1524
1525 while (root->parent != NULL) root = root->parent;
1526 xmlNewNs(root, ns->href, ns->prefix);
1527 }
1528 } else {
1529 /*
1530 * reference the existing namespace definition in our own tree.
1531 */
1532 ret->ns = ns;
1533 }
1534 }
1535 if (node->childs != NULL)
1536 ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001537 UPDATE_LAST_CHILD(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001538 return(ret);
1539}
1540
1541static xmlNodePtr
1542xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
1543 xmlNodePtr ret = NULL;
1544 xmlNodePtr p = NULL,q;
1545
1546 while (node != NULL) {
1547 q = xmlStaticCopyNode(node, doc, parent, 1);
1548 if (parent == NULL) {
1549 if (ret == NULL) ret = q;
1550 } else {
1551 if (ret == NULL) {
1552 q->prev = NULL;
1553 ret = p = q;
1554 } else {
1555 p->next = q;
1556 q->prev = p;
1557 p = q;
1558 }
1559 }
1560 node = node->next;
1561 }
1562 return(ret);
1563}
1564
1565/**
1566 * xmlCopyNode:
1567 * @node: the node
1568 * @recursive: if 1 do a recursive copy.
1569 *
1570 * Do a copy of the node.
1571 *
1572 * Returns: a new xmlNodePtr, or NULL in case of error.
1573 */
1574xmlNodePtr
1575xmlCopyNode(xmlNodePtr node, int recursive) {
1576 xmlNodePtr ret;
1577
1578 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
1579 return(ret);
1580}
1581
1582/**
1583 * xmlCopyNodeList:
1584 * @node: the first node in the list.
1585 *
1586 * Do a recursive copy of the node list.
1587 *
1588 * Returns: a new xmlNodePtr, or NULL in case of error.
1589 */
1590xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
1591 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
1592 return(ret);
1593}
1594
1595/**
1596 * xmlCopyElement:
1597 * @elem: the element
1598 *
1599 * Do a copy of the element definition.
1600 *
1601 * Returns: a new xmlElementPtr, or NULL in case of error.
1602xmlElementPtr
1603xmlCopyElement(xmlElementPtr elem) {
1604 xmlElementPtr ret;
1605
1606 if (elem == NULL) return(NULL);
1607 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
1608 if (ret == NULL) return(NULL);
1609 if (!recursive) return(ret);
1610 if (elem->properties != NULL)
1611 ret->properties = xmlCopyPropList(elem->properties);
1612
1613 if (elem->nsDef != NULL)
1614 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
1615 if (elem->childs != NULL)
1616 ret->childs = xmlCopyElementList(elem->childs);
1617 return(ret);
1618}
1619 */
1620
1621/**
1622 * xmlCopyDtd:
1623 * @dtd: the dtd
1624 *
1625 * Do a copy of the dtd.
1626 *
1627 * Returns: a new xmlDtdPtr, or NULL in case of error.
1628 */
1629xmlDtdPtr
1630xmlCopyDtd(xmlDtdPtr dtd) {
1631 xmlDtdPtr ret;
1632
1633 if (dtd == NULL) return(NULL);
1634 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
1635 if (ret == NULL) return(NULL);
1636 if (dtd->entities != NULL)
1637 ret->entities = (void *) xmlCopyEntitiesTable(
1638 (xmlEntitiesTablePtr) dtd->entities);
1639 /*
1640 * TODO: support for Element definitions.
1641 */
1642 return(ret);
1643}
1644
1645/**
1646 * xmlCopyDoc:
1647 * @doc: the document
1648 * @recursive: if 1 do a recursive copy.
1649 *
1650 * Do a copy of the document info. If recursive, the content tree will
1651 * be copied too as well as Dtd, namespaces and entities.
1652 *
1653 * Returns: a new xmlDocPtr, or NULL in case of error.
1654 */
1655xmlDocPtr
1656xmlCopyDoc(xmlDocPtr doc, int recursive) {
1657 xmlDocPtr ret;
1658
1659 if (doc == NULL) return(NULL);
1660 ret = xmlNewDoc(doc->version);
1661 if (ret == NULL) return(NULL);
1662 if (doc->name != NULL)
1663 ret->name = strdup(doc->name);
1664 if (doc->encoding != NULL)
1665 ret->encoding = xmlStrdup(doc->encoding);
1666 ret->compression = doc->compression;
1667 ret->standalone = doc->standalone;
1668 if (!recursive) return(ret);
1669
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001670 if (doc->intSubset != NULL)
1671 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001672 if (doc->oldNs != NULL)
1673 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
1674 if (doc->root != NULL)
1675 ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL);
1676 return(ret);
1677}
1678
1679/************************************************************************
1680 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001681 * Content access functions *
1682 * *
1683 ************************************************************************/
1684
Daniel Veillard97b58771998-10-20 06:14:16 +00001685/**
Daniel Veillard16253641998-10-28 22:58:05 +00001686 * xmlNodeGetContent:
1687 * @cur: the node being read
1688 *
1689 * Read the value of a node, this can be either the text carried
1690 * directly by this node if it's a TEXT node or the aggregate string
1691 * of the values carried by this node child's (TEXT and ENTITY_REF).
1692 * Entity references are substitued.
1693 * Return value: a new CHAR * or NULL if no content is available.
1694 */
1695CHAR *
1696xmlNodeGetContent(xmlNodePtr cur) {
1697 if (cur == NULL) return(NULL);
1698 switch (cur->type) {
1699 case XML_DOCUMENT_FRAG_NODE:
1700 case XML_ELEMENT_NODE:
1701 return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1702 break;
1703 case XML_ATTRIBUTE_NODE:
1704 case XML_CDATA_SECTION_NODE:
1705 case XML_ENTITY_REF_NODE:
1706 case XML_ENTITY_NODE:
1707 case XML_PI_NODE:
1708 case XML_COMMENT_NODE:
1709 case XML_DOCUMENT_NODE:
1710 case XML_DOCUMENT_TYPE_NODE:
1711 case XML_NOTATION_NODE:
1712 return(NULL);
1713 case XML_TEXT_NODE:
1714 if (cur->content != NULL)
1715 return(xmlStrdup(cur->content));
1716 return(NULL);
1717 }
1718 return(NULL);
1719}
1720
1721/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001722 * xmlNodeSetContent:
1723 * @cur: the node being modified
1724 * @content: the new value of the content
1725 *
1726 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001727 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001728void
1729xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001730 if (cur == NULL) {
1731 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1732 return;
1733 }
Daniel Veillard16253641998-10-28 22:58:05 +00001734 switch (cur->type) {
1735 case XML_DOCUMENT_FRAG_NODE:
1736 case XML_ELEMENT_NODE:
1737 if (cur->content != NULL) {
1738 free(cur->content);
1739 cur->content = NULL;
1740 }
1741 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1742 cur->childs = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001743 UPDATE_LAST_CHILD(cur);
Daniel Veillard16253641998-10-28 22:58:05 +00001744 break;
1745 case XML_ATTRIBUTE_NODE:
1746 break;
1747 case XML_TEXT_NODE:
1748 case XML_CDATA_SECTION_NODE:
1749 case XML_ENTITY_REF_NODE:
1750 case XML_ENTITY_NODE:
1751 case XML_PI_NODE:
1752 case XML_COMMENT_NODE:
1753 if (cur->content != NULL) free(cur->content);
1754 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001755 cur->last = cur->childs = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001756 if (content != NULL)
1757 cur->content = xmlStrdup(content);
1758 else
1759 cur->content = NULL;
1760 case XML_DOCUMENT_NODE:
1761 case XML_DOCUMENT_TYPE_NODE:
1762 break;
1763 case XML_NOTATION_NODE:
1764 break;
1765 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001766}
1767
Daniel Veillard97b58771998-10-20 06:14:16 +00001768/**
1769 * xmlNodeSetContentLen:
1770 * @cur: the node being modified
1771 * @content: the new value of the content
1772 * @len: the size of @content
1773 *
1774 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001775 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001776void
1777xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001778 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001779 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001780 return;
1781 }
Daniel Veillard16253641998-10-28 22:58:05 +00001782 switch (cur->type) {
1783 case XML_DOCUMENT_FRAG_NODE:
1784 case XML_ELEMENT_NODE:
1785 if (cur->content != NULL) {
1786 free(cur->content);
1787 cur->content = NULL;
1788 }
1789 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1790 cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001791 UPDATE_LAST_CHILD(cur);
Daniel Veillard16253641998-10-28 22:58:05 +00001792 break;
1793 case XML_ATTRIBUTE_NODE:
1794 break;
1795 case XML_TEXT_NODE:
1796 case XML_CDATA_SECTION_NODE:
1797 case XML_ENTITY_REF_NODE:
1798 case XML_ENTITY_NODE:
1799 case XML_PI_NODE:
1800 case XML_COMMENT_NODE:
1801 if (cur->content != NULL) free(cur->content);
1802 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001803 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001804 if (content != NULL)
1805 cur->content = xmlStrndup(content, len);
1806 else
1807 cur->content = NULL;
1808 case XML_DOCUMENT_NODE:
1809 case XML_DOCUMENT_TYPE_NODE:
1810 break;
1811 case XML_NOTATION_NODE:
1812 if (cur->content != NULL) free(cur->content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001813 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1814 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001815 if (content != NULL)
1816 cur->content = xmlStrndup(content, len);
1817 else
1818 cur->content = NULL;
1819 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001820 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001821}
1822
Daniel Veillard97b58771998-10-20 06:14:16 +00001823/**
1824 * xmlNodeAddContentLen:
1825 * @cur: the node being modified
1826 * @content: extra content
1827 * @len: the size of @content
1828 *
1829 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001830 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001831void
1832xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001833 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001834 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1835 return;
1836 }
1837 if (len <= 0) return;
1838 switch (cur->type) {
1839 case XML_DOCUMENT_FRAG_NODE:
1840 case XML_ELEMENT_NODE: {
1841 xmlNodePtr last = NULL, new;
1842
1843 if (cur->childs != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001844 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001845 } else {
1846 if (cur->content != NULL) {
1847 cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001848 UPDATE_LAST_CHILD(cur);
Daniel Veillard16253641998-10-28 22:58:05 +00001849 free(cur->content);
1850 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001851 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001852 }
1853 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001854 new = xmlNewTextLen(content, len);
Daniel Veillard16253641998-10-28 22:58:05 +00001855 if (new != NULL) {
1856 xmlAddChild(cur, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001857 if ((last != NULL) && (last->next == new)) {
Daniel Veillard16253641998-10-28 22:58:05 +00001858 xmlTextMerge(last, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001859 }
Daniel Veillard16253641998-10-28 22:58:05 +00001860 }
1861 break;
1862 }
1863 case XML_ATTRIBUTE_NODE:
1864 break;
1865 case XML_TEXT_NODE:
1866 case XML_CDATA_SECTION_NODE:
1867 case XML_ENTITY_REF_NODE:
1868 case XML_ENTITY_NODE:
1869 case XML_PI_NODE:
1870 case XML_COMMENT_NODE:
1871 if (content != NULL)
1872 cur->content = xmlStrncat(cur->content, content, len);
1873 case XML_DOCUMENT_NODE:
1874 case XML_DOCUMENT_TYPE_NODE:
1875 break;
1876 case XML_NOTATION_NODE:
1877 if (content != NULL)
1878 cur->content = xmlStrncat(cur->content, content, len);
1879 break;
1880 }
1881}
1882
1883/**
1884 * xmlNodeAddContent:
1885 * @cur: the node being modified
1886 * @content: extra content
1887 *
1888 * Append the extra substring to the node content.
1889 */
1890void
1891xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1892 int len;
1893
1894 if (cur == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001895 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1896 return;
1897 }
Daniel Veillard16253641998-10-28 22:58:05 +00001898 if (content == NULL) return;
1899 len = xmlStrlen(content);
1900 xmlNodeAddContentLen(cur, content, len);
1901}
1902
1903/**
1904 * xmlTextMerge:
1905 * @first: the first text node
1906 * @second: the second text node being merged
1907 *
1908 * Merge two text nodes into one
1909 * Return values: the first text node augmented
1910 */
1911xmlNodePtr
1912xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1913 if (first == NULL) return(second);
1914 if (second == NULL) return(first);
1915 if (first->type != XML_TEXT_NODE) return(first);
1916 if (second->type != XML_TEXT_NODE) return(first);
1917 xmlNodeAddContent(first, second->content);
1918 xmlUnlinkNode(second);
1919 xmlFreeNode(second);
1920 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001921}
1922
Daniel Veillard97b58771998-10-20 06:14:16 +00001923/**
1924 * xmlSearchNs:
1925 * @doc: the document
1926 * @node: the current node
1927 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00001928 *
Daniel Veillard97b58771998-10-20 06:14:16 +00001929 * Search a Ns registered under a given name space for a document.
1930 * recurse on the parents until it finds the defined namespace
1931 * or return NULL otherwise.
1932 * @nameSpace can be NULL, this is a search for the default namespace.
1933 * return values: the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001934 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001935xmlNsPtr
1936xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001937 xmlNsPtr cur;
1938
1939 while (node != NULL) {
1940 cur = node->nsDef;
1941 while (cur != NULL) {
1942 if ((cur->prefix == NULL) && (nameSpace == NULL))
1943 return(cur);
1944 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1945 (!xmlStrcmp(cur->prefix, nameSpace)))
1946 return(cur);
1947 cur = cur->next;
1948 }
1949 node = node->parent;
1950 }
1951 if (doc != NULL) {
1952 cur = doc->oldNs;
1953 while (cur != NULL) {
1954 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1955 (!xmlStrcmp(cur->prefix, nameSpace)))
1956 return(cur);
1957 cur = cur->next;
1958 }
1959 }
1960 return(NULL);
1961}
1962
Daniel Veillard97b58771998-10-20 06:14:16 +00001963/**
1964 * xmlSearchNsByHref:
1965 * @doc: the document
1966 * @node: the current node
1967 * @href: the namespace value
1968 *
1969 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1970 * the defined namespace or return NULL otherwise.
1971 * return values: the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001972 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001973xmlNsPtr
1974xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001975 xmlNsPtr cur;
1976
1977 while (node != NULL) {
1978 cur = node->nsDef;
1979 while (cur != NULL) {
1980 if ((cur->href != NULL) && (href != NULL) &&
1981 (!xmlStrcmp(cur->href, href)))
1982 return(cur);
1983 cur = cur->next;
1984 }
1985 node = node->parent;
1986 }
1987 if (doc != NULL) {
1988 cur = doc->oldNs;
1989 while (cur != NULL) {
1990 if ((cur->href != NULL) && (href != NULL) &&
1991 (!xmlStrcmp(cur->href, href)))
1992 return(cur);
1993 cur = cur->next;
1994 }
1995 }
1996 return(NULL);
1997}
1998
Daniel Veillard97b58771998-10-20 06:14:16 +00001999/**
2000 * xmlGetProp:
2001 * @node: the node
2002 * @name: the attribute name
2003 *
2004 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00002005 * This does the entity substitution.
Daniel Veillard97b58771998-10-20 06:14:16 +00002006 * return values: the attribute value or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002007 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002008CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002009 xmlAttrPtr prop = node->properties;
2010
2011 while (prop != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002012 if (!xmlStrcmp(prop->name, name))
2013 return(xmlNodeListGetString(node->doc, prop->val, 1));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002014 prop = prop->next;
2015 }
2016 return(NULL);
2017}
2018
Daniel Veillard97b58771998-10-20 06:14:16 +00002019/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002020 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00002021 * @node: the node
2022 * @name: the attribute name
2023 * @value: the attribute value
2024 *
2025 * Set (or reset) an attribute carried by a node.
2026 * return values: the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002027 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002028xmlAttrPtr
2029xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002030 xmlAttrPtr prop = node->properties;
2031
2032 while (prop != NULL) {
2033 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002034 if (prop->val != NULL)
2035 xmlFreeNode(prop->val);
2036 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002037 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00002038 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002039 return(prop);
2040 }
2041 prop = prop->next;
2042 }
2043 prop = xmlNewProp(node, name, value);
2044 return(prop);
2045}
2046
Daniel Veillard97b58771998-10-20 06:14:16 +00002047/**
2048 * xmlNodeIsText:
2049 * @node: the node
2050 *
2051 * Is this node a Text node ?
2052 * return values: 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00002053 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002054int
2055xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002056 if (node == NULL) return(0);
2057
Daniel Veillard0bef1311998-10-14 02:36:47 +00002058 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002059 return(0);
2060}
2061
Daniel Veillard97b58771998-10-20 06:14:16 +00002062/**
2063 * xmlNodeIsText:
2064 * @node: the node
2065 * @content: the content
2066 * @len: @content lenght
2067 *
2068 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00002069 */
Daniel Veillard97b58771998-10-20 06:14:16 +00002070
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002071void
2072xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002073 if (node == NULL) return;
2074
Daniel Veillard0bef1311998-10-14 02:36:47 +00002075 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002076 fprintf(stderr, "xmlTextConcat: node is not text\n");
2077 return;
2078 }
2079 node->content = xmlStrncat(node->content, content, len);
2080}
2081
2082/************************************************************************
2083 * *
2084 * Output : to a FILE or in memory *
2085 * *
2086 ************************************************************************/
2087
Daniel Veillard260a68f1998-08-13 03:39:55 +00002088static CHAR *buffer = NULL;
2089static int buffer_index = 0;
2090static int buffer_size = 0;
2091
Daniel Veillard97b58771998-10-20 06:14:16 +00002092/**
2093 * xmlBufferWriteCHAR:
2094 * @string: the string to add
2095 *
2096 * routine which manage and grows an output buffer. This one add
2097 * CHARs at the end of the array.
2098 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002099void
2100xmlBufferWriteCHAR(const CHAR *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002101 const CHAR *cur;
2102
2103 if (buffer == NULL) {
2104 buffer_size = 50000;
2105 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2106 if (buffer == NULL) {
2107 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2108 exit(1);
2109 }
2110 }
2111
2112 if (string == NULL) return;
2113 for (cur = string;*cur != 0;cur++) {
2114 if (buffer_index + 10 >= buffer_size) {
2115 buffer_size *= 2;
2116 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2117 if (buffer == NULL) {
2118 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2119 exit(1);
2120 }
2121 }
2122 buffer[buffer_index++] = *cur;
2123 }
2124 buffer[buffer_index] = 0;
2125}
2126
Daniel Veillard97b58771998-10-20 06:14:16 +00002127/**
2128 * xmlBufferWriteChar:
2129 * @string: the string to add
2130 *
2131 * routine which manage and grows an output buffer. This one add
2132 * C chars at the end of the array.
2133 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002134void
2135xmlBufferWriteChar(const char *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002136 const char *cur;
2137
2138 if (buffer == NULL) {
2139 buffer_size = 50000;
2140 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2141 if (buffer == NULL) {
2142 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2143 exit(1);
2144 }
2145 }
2146
2147 if (string == NULL) return;
2148 for (cur = string;*cur != 0;cur++) {
2149 if (buffer_index + 10 >= buffer_size) {
2150 buffer_size *= 2;
2151 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2152 if (buffer == NULL) {
2153 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2154 exit(1);
2155 }
2156 }
2157 buffer[buffer_index++] = *cur;
2158 }
2159 buffer[buffer_index] = 0;
2160}
2161
Daniel Veillard97b58771998-10-20 06:14:16 +00002162/**
2163 * xmlGlobalNsDump:
2164 * @cur: a namespace
2165 *
2166 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002167 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002168static void
2169xmlGlobalNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002170 if (cur == NULL) {
2171 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
2172 return;
2173 }
2174 if (cur->type == XML_GLOBAL_NAMESPACE) {
2175 xmlBufferWriteChar("<?namespace");
2176 if (cur->href != NULL) {
2177 xmlBufferWriteChar(" href=\"");
2178 xmlBufferWriteCHAR(cur->href);
2179 xmlBufferWriteChar("\"");
2180 }
2181 if (cur->prefix != NULL) {
2182 xmlBufferWriteChar(" AS=\"");
2183 xmlBufferWriteCHAR(cur->prefix);
2184 xmlBufferWriteChar("\"");
2185 }
2186 xmlBufferWriteChar("?>\n");
2187 }
2188}
2189
Daniel Veillard97b58771998-10-20 06:14:16 +00002190/**
2191 * xmlGlobalNsListDump:
2192 * @cur: the first namespace
2193 *
2194 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002195 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002196static void
2197xmlGlobalNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002198 while (cur != NULL) {
2199 xmlGlobalNsDump(cur);
2200 cur = cur->next;
2201 }
2202}
2203
Daniel Veillard97b58771998-10-20 06:14:16 +00002204/**
2205 * xmlNsDump:
2206 * @cur: a namespace
2207 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002208 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00002209 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002210 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002211static void
2212xmlNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002213 if (cur == NULL) {
2214 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
2215 return;
2216 }
2217 if (cur->type == XML_LOCAL_NAMESPACE) {
2218 /* Within the context of an element attributes */
2219 if (cur->prefix != NULL) {
2220 xmlBufferWriteChar(" xmlns:");
2221 xmlBufferWriteCHAR(cur->prefix);
2222 } else
2223 xmlBufferWriteChar(" xmlns");
2224 xmlBufferWriteChar("=\"");
2225 xmlBufferWriteCHAR(cur->href);
2226 xmlBufferWriteChar("\"");
2227 }
2228}
2229
Daniel Veillard97b58771998-10-20 06:14:16 +00002230/**
2231 * xmlNsListDump:
2232 * @cur: the first namespace
2233 *
2234 * Dump a list of local Namespace definitions.
2235 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002236 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002237static void
2238xmlNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002239 while (cur != NULL) {
2240 xmlNsDump(cur);
2241 cur = cur->next;
2242 }
2243}
2244
Daniel Veillard97b58771998-10-20 06:14:16 +00002245/**
2246 * xmlDtdDump:
2247 * @doc: the document
2248 *
2249 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002250 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002251static void
2252xmlDtdDump(xmlDocPtr doc) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002253 xmlDtdPtr cur = doc->intSubset;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002254
2255 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002256 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002257 return;
2258 }
2259 xmlBufferWriteChar("<!DOCTYPE ");
2260 xmlBufferWriteCHAR(cur->name);
2261 if (cur->ExternalID != NULL) {
2262 xmlBufferWriteChar(" PUBLIC \"");
2263 xmlBufferWriteCHAR(cur->ExternalID);
2264 xmlBufferWriteChar("\" \"");
2265 xmlBufferWriteCHAR(cur->SystemID);
2266 xmlBufferWriteChar("\"");
2267 } else if (cur->SystemID != NULL) {
2268 xmlBufferWriteChar(" SYSTEM \"");
2269 xmlBufferWriteCHAR(cur->SystemID);
2270 xmlBufferWriteChar("\"");
2271 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00002272 if ((cur->entities == NULL) && (cur->elements == NULL)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002273 xmlBufferWriteChar(">\n");
2274 return;
2275 }
2276 xmlBufferWriteChar(" [\n");
2277 if (cur->entities != NULL)
2278 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002279 if (cur->elements != NULL)
2280 xmlDumpElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002281 xmlBufferWriteChar("]");
2282
2283 /* TODO !!! a lot more things to dump ... */
2284 xmlBufferWriteChar(">\n");
2285}
2286
Daniel Veillard97b58771998-10-20 06:14:16 +00002287/**
2288 * xmlAttrDump:
2289 * @doc: the document
2290 * @cur: the attribute pointer
2291 *
2292 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00002293 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002294static void
2295xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002296 CHAR *value;
2297
Daniel Veillard260a68f1998-08-13 03:39:55 +00002298 if (cur == NULL) {
2299 fprintf(stderr, "xmlAttrDump : property == NULL\n");
2300 return;
2301 }
2302 xmlBufferWriteChar(" ");
2303 xmlBufferWriteCHAR(cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002304 value = xmlNodeListGetString(doc, cur->val, 0);
2305 if (value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002306 xmlBufferWriteChar("=\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00002307 xmlBufferWriteCHAR(value);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002308 xmlBufferWriteChar("\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00002309 free(value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002310 }
2311}
2312
Daniel Veillard97b58771998-10-20 06:14:16 +00002313/**
2314 * xmlAttrListDump:
2315 * @doc: the document
2316 * @cur: the first attribute pointer
2317 *
2318 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00002319 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002320static void
2321xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002322 if (cur == NULL) {
2323 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
2324 return;
2325 }
2326 while (cur != NULL) {
2327 xmlAttrDump(doc, cur);
2328 cur = cur->next;
2329 }
2330}
2331
Daniel Veillard260a68f1998-08-13 03:39:55 +00002332
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002333static void
2334xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00002335/**
2336 * xmlNodeListDump:
2337 * @doc: the document
2338 * @cur: the first node
2339 * @level: the imbrication level for indenting
2340 *
2341 * Dump an XML node list, recursive behaviour,children are printed too.
2342 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002343static void
2344xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002345 int needIndent = 0, i;
2346
Daniel Veillard260a68f1998-08-13 03:39:55 +00002347 if (cur == NULL) {
2348 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
2349 return;
2350 }
2351 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002352 if ((cur->type != XML_TEXT_NODE) &&
2353 (cur->type != XML_ENTITY_REF_NODE)) {
2354 if (!needIndent) {
2355 needIndent = 1;
2356 xmlBufferWriteChar("\n");
2357 }
2358 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002359 xmlNodeDump(doc, cur, level);
2360 cur = cur->next;
2361 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002362 if ((xmlIndentTreeOutput) && (needIndent))
2363 for (i = 1;i < level;i++)
2364 xmlBufferWriteChar(" ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002365}
2366
Daniel Veillard97b58771998-10-20 06:14:16 +00002367/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002368 * xmlNodeDump:
Daniel Veillard97b58771998-10-20 06:14:16 +00002369 * @doc: the document
2370 * @cur: the current node
2371 * @level: the imbrication level for indenting
2372 *
2373 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002374 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002375static void
2376xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002377 int i;
2378
2379 if (cur == NULL) {
2380 fprintf(stderr, "xmlNodeDump : node == NULL\n");
2381 return;
2382 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002383 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002384 if (cur->content != NULL)
2385 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2386 return;
2387 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002388 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002389 if (cur->content != NULL) {
2390 xmlBufferWriteChar("<!--");
2391 xmlBufferWriteCHAR(cur->content);
2392 xmlBufferWriteChar("-->");
2393 }
2394 return;
2395 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002396 if (cur->type == XML_ENTITY_REF_NODE) {
2397 xmlBufferWriteChar("&");
2398 xmlBufferWriteCHAR(cur->name);
2399 xmlBufferWriteChar(";");
2400 return;
2401 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002402 if (xmlIndentTreeOutput)
2403 for (i = 0;i < level;i++)
2404 xmlBufferWriteChar(" ");
2405
2406 xmlBufferWriteChar("<");
2407 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2408 xmlBufferWriteCHAR(cur->ns->prefix);
2409 xmlBufferWriteChar(":");
2410 }
2411
2412 xmlBufferWriteCHAR(cur->name);
2413 if (cur->nsDef)
2414 xmlNsListDump(cur->nsDef);
2415 if (cur->properties != NULL)
2416 xmlAttrListDump(doc, cur->properties);
2417
2418 if ((cur->content == NULL) && (cur->childs == NULL)) {
2419 xmlBufferWriteChar("/>\n");
2420 return;
2421 }
2422 xmlBufferWriteChar(">");
2423 if (cur->content != NULL)
2424 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2425 if (cur->childs != NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002426 xmlNodeListDump(doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002427 }
2428 xmlBufferWriteChar("</");
2429 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2430 xmlBufferWriteCHAR(cur->ns->prefix);
2431 xmlBufferWriteChar(":");
2432 }
2433
2434 xmlBufferWriteCHAR(cur->name);
2435 xmlBufferWriteChar(">\n");
2436}
2437
Daniel Veillard97b58771998-10-20 06:14:16 +00002438/**
2439 * xmlDocContentDump:
2440 * @cur: the document
2441 *
2442 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002443 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002444static void
2445xmlDocContentDump(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002446 if (oldXMLWDcompatibility)
2447 xmlBufferWriteChar("<?XML version=\"");
2448 else
2449 xmlBufferWriteChar("<?xml version=\"");
2450 xmlBufferWriteCHAR(cur->version);
2451 xmlBufferWriteChar("\"");
2452 if (cur->encoding != NULL) {
2453 xmlBufferWriteChar(" encoding=\"");
2454 xmlBufferWriteCHAR(cur->encoding);
2455 xmlBufferWriteChar("\"");
2456 }
2457 switch (cur->standalone) {
2458 case 0:
2459 xmlBufferWriteChar(" standalone=\"no\"");
2460 break;
2461 case 1:
2462 xmlBufferWriteChar(" standalone=\"yes\"");
2463 break;
2464 }
2465 xmlBufferWriteChar("?>\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002466 if (cur->intSubset != NULL)
Daniel Veillard260a68f1998-08-13 03:39:55 +00002467 xmlDtdDump(cur);
2468 if (cur->root != NULL) {
2469 /* global namespace definitions, the old way */
2470 if (oldXMLWDcompatibility)
2471 xmlGlobalNsListDump(cur->oldNs);
2472 else
2473 xmlUpgradeOldNs(cur);
2474 xmlNodeDump(cur, cur->root, 0);
2475 }
2476}
2477
Daniel Veillard97b58771998-10-20 06:14:16 +00002478/**
2479 * xmlDocDumpMemory:
2480 * @cur: the document
2481 * @mem: OUT: the memory pointer
2482 * @size: OUT: the memory lenght
2483 *
2484 * Dump an XML document in memory and return the CHAR * and it's size.
2485 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002486 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002487void
2488xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002489 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002490#ifdef DEBUG_TREE
2491 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
2492#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002493 *mem = NULL;
2494 *size = 0;
2495 return;
2496 }
2497 buffer_index = 0;
2498 xmlDocContentDump(cur);
2499
2500 *mem = buffer;
2501 *size = buffer_index;
2502}
2503
Daniel Veillard97b58771998-10-20 06:14:16 +00002504/**
2505 * xmlGetDocCompressMode:
2506 * @doc: the document
2507 *
2508 * get the compression ratio for a document, ZLIB based
2509 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002510 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002511int
2512 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002513 if (doc == NULL) return(-1);
2514 return(doc->compression);
2515}
2516
Daniel Veillard97b58771998-10-20 06:14:16 +00002517/**
2518 * xmlSetDocCompressMode:
2519 * @doc: the document
2520 * @mode: the compression ratio
2521 *
2522 * set the compression ratio for a document, ZLIB based
2523 * Correct values: 0 (uncompressed) to 9 (max compression)
2524 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002525void
2526xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002527 if (doc == NULL) return;
2528 if (mode < 0) doc->compression = 0;
2529 else if (mode > 9) doc->compression = 9;
2530 else doc->compression = mode;
2531}
2532
Daniel Veillard97b58771998-10-20 06:14:16 +00002533/**
2534 * xmlGetCompressMode:
2535 *
2536 * get the default compression mode used, ZLIB based.
2537 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002538 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002539int
2540 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002541 return(xmlCompressMode);
2542}
Daniel Veillard97b58771998-10-20 06:14:16 +00002543
2544/**
2545 * xmlSetCompressMode:
2546 * @mode: the compression ratio
2547 *
2548 * set the default compression mode used, ZLIB based
2549 * Correct values: 0 (uncompressed) to 9 (max compression)
2550 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002551void
2552xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002553 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002554 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002555 else xmlCompressMode = mode;
2556}
2557
Daniel Veillard97b58771998-10-20 06:14:16 +00002558/**
2559 * xmlDocDump:
2560 * @f: the FILE*
2561 * @cur: the document
2562 *
2563 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002564 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002565void
2566xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002567 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002568#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002569 fprintf(stderr, "xmlDocDump : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002570#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002571 return;
2572 }
2573 buffer_index = 0;
2574 xmlDocContentDump(cur);
2575
2576 fwrite(buffer, sizeof(CHAR), buffer_index, f);
2577}
2578
Daniel Veillard97b58771998-10-20 06:14:16 +00002579/**
2580 * xmlSaveFile:
2581 * @filename: the filename
2582 * @cur: the document
2583 *
2584 * Dump an XML document to a file. Will use compression if
2585 * compiled in and enabled.
2586 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002587 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002588int
2589xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002590#ifdef HAVE_ZLIB_H
2591 gzFile zoutput = NULL;
2592 char mode[15];
2593#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002594 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002595 int ret;
2596
2597#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002598 if ((cur->compression > 0) && (cur->compression <= 9)) {
2599 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002600 zoutput = gzopen(filename, mode);
2601 }
2602 if (zoutput == NULL) {
2603#endif
2604 output = fopen(filename, "w");
2605 if (output == NULL) return(-1);
2606#ifdef HAVE_ZLIB_H
2607 }
2608#endif
2609
2610 /*
2611 * save the content to a temp buffer.
2612 */
2613 buffer_index = 0;
2614 xmlDocContentDump(cur);
2615
2616#ifdef HAVE_ZLIB_H
2617 if (zoutput != NULL) {
2618 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
2619 gzclose(zoutput);
2620 return(ret);
2621 }
2622#endif
2623 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
2624 fclose(output);
2625 return(ret * sizeof(CHAR));
2626}
2627