blob: d963d2d57183d4aedb1bfd739df784c8b9480ccf [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 Veillard68178931999-02-08 18:34:36 +00002012 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillard6800ef31999-02-08 18:33:22 +00002013 CHAR *ret;
2014
2015 ret = xmlNodeListGetString(node->doc, prop->val, 1);
2016 if (ret == NULL) return(xmlStrdup(""));
2017 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00002018 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002019 prop = prop->next;
2020 }
2021 return(NULL);
2022}
2023
Daniel Veillard97b58771998-10-20 06:14:16 +00002024/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002025 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00002026 * @node: the node
2027 * @name: the attribute name
2028 * @value: the attribute value
2029 *
2030 * Set (or reset) an attribute carried by a node.
2031 * return values: the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002032 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002033xmlAttrPtr
2034xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002035 xmlAttrPtr prop = node->properties;
2036
2037 while (prop != NULL) {
2038 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002039 if (prop->val != NULL)
2040 xmlFreeNode(prop->val);
2041 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002042 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00002043 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002044 return(prop);
2045 }
2046 prop = prop->next;
2047 }
2048 prop = xmlNewProp(node, name, value);
2049 return(prop);
2050}
2051
Daniel Veillard97b58771998-10-20 06:14:16 +00002052/**
2053 * xmlNodeIsText:
2054 * @node: the node
2055 *
2056 * Is this node a Text node ?
2057 * return values: 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00002058 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002059int
2060xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002061 if (node == NULL) return(0);
2062
Daniel Veillard0bef1311998-10-14 02:36:47 +00002063 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002064 return(0);
2065}
2066
Daniel Veillard97b58771998-10-20 06:14:16 +00002067/**
2068 * xmlNodeIsText:
2069 * @node: the node
2070 * @content: the content
2071 * @len: @content lenght
2072 *
2073 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00002074 */
Daniel Veillard97b58771998-10-20 06:14:16 +00002075
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002076void
2077xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002078 if (node == NULL) return;
2079
Daniel Veillard0bef1311998-10-14 02:36:47 +00002080 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002081 fprintf(stderr, "xmlTextConcat: node is not text\n");
2082 return;
2083 }
2084 node->content = xmlStrncat(node->content, content, len);
2085}
2086
2087/************************************************************************
2088 * *
2089 * Output : to a FILE or in memory *
2090 * *
2091 ************************************************************************/
2092
Daniel Veillard260a68f1998-08-13 03:39:55 +00002093static CHAR *buffer = NULL;
2094static int buffer_index = 0;
2095static int buffer_size = 0;
2096
Daniel Veillard97b58771998-10-20 06:14:16 +00002097/**
2098 * xmlBufferWriteCHAR:
2099 * @string: the string to add
2100 *
2101 * routine which manage and grows an output buffer. This one add
2102 * CHARs at the end of the array.
2103 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002104void
2105xmlBufferWriteCHAR(const CHAR *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002106 const CHAR *cur;
2107
2108 if (buffer == NULL) {
2109 buffer_size = 50000;
2110 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2111 if (buffer == NULL) {
2112 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2113 exit(1);
2114 }
2115 }
2116
2117 if (string == NULL) return;
2118 for (cur = string;*cur != 0;cur++) {
2119 if (buffer_index + 10 >= buffer_size) {
2120 buffer_size *= 2;
2121 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2122 if (buffer == NULL) {
2123 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2124 exit(1);
2125 }
2126 }
2127 buffer[buffer_index++] = *cur;
2128 }
2129 buffer[buffer_index] = 0;
2130}
2131
Daniel Veillard97b58771998-10-20 06:14:16 +00002132/**
2133 * xmlBufferWriteChar:
2134 * @string: the string to add
2135 *
2136 * routine which manage and grows an output buffer. This one add
2137 * C chars at the end of the array.
2138 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002139void
2140xmlBufferWriteChar(const char *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002141 const char *cur;
2142
2143 if (buffer == NULL) {
2144 buffer_size = 50000;
2145 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2146 if (buffer == NULL) {
2147 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2148 exit(1);
2149 }
2150 }
2151
2152 if (string == NULL) return;
2153 for (cur = string;*cur != 0;cur++) {
2154 if (buffer_index + 10 >= buffer_size) {
2155 buffer_size *= 2;
2156 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2157 if (buffer == NULL) {
2158 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2159 exit(1);
2160 }
2161 }
2162 buffer[buffer_index++] = *cur;
2163 }
2164 buffer[buffer_index] = 0;
2165}
2166
Daniel Veillard97b58771998-10-20 06:14:16 +00002167/**
2168 * xmlGlobalNsDump:
2169 * @cur: a namespace
2170 *
2171 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002172 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002173static void
2174xmlGlobalNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002175 if (cur == NULL) {
2176 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
2177 return;
2178 }
2179 if (cur->type == XML_GLOBAL_NAMESPACE) {
2180 xmlBufferWriteChar("<?namespace");
2181 if (cur->href != NULL) {
2182 xmlBufferWriteChar(" href=\"");
2183 xmlBufferWriteCHAR(cur->href);
2184 xmlBufferWriteChar("\"");
2185 }
2186 if (cur->prefix != NULL) {
2187 xmlBufferWriteChar(" AS=\"");
2188 xmlBufferWriteCHAR(cur->prefix);
2189 xmlBufferWriteChar("\"");
2190 }
2191 xmlBufferWriteChar("?>\n");
2192 }
2193}
2194
Daniel Veillard97b58771998-10-20 06:14:16 +00002195/**
2196 * xmlGlobalNsListDump:
2197 * @cur: the first namespace
2198 *
2199 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002200 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002201static void
2202xmlGlobalNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002203 while (cur != NULL) {
2204 xmlGlobalNsDump(cur);
2205 cur = cur->next;
2206 }
2207}
2208
Daniel Veillard97b58771998-10-20 06:14:16 +00002209/**
2210 * xmlNsDump:
2211 * @cur: a namespace
2212 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002213 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00002214 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002215 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002216static void
2217xmlNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002218 if (cur == NULL) {
2219 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
2220 return;
2221 }
2222 if (cur->type == XML_LOCAL_NAMESPACE) {
2223 /* Within the context of an element attributes */
2224 if (cur->prefix != NULL) {
2225 xmlBufferWriteChar(" xmlns:");
2226 xmlBufferWriteCHAR(cur->prefix);
2227 } else
2228 xmlBufferWriteChar(" xmlns");
2229 xmlBufferWriteChar("=\"");
2230 xmlBufferWriteCHAR(cur->href);
2231 xmlBufferWriteChar("\"");
2232 }
2233}
2234
Daniel Veillard97b58771998-10-20 06:14:16 +00002235/**
2236 * xmlNsListDump:
2237 * @cur: the first namespace
2238 *
2239 * Dump a list of local Namespace definitions.
2240 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002241 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002242static void
2243xmlNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002244 while (cur != NULL) {
2245 xmlNsDump(cur);
2246 cur = cur->next;
2247 }
2248}
2249
Daniel Veillard97b58771998-10-20 06:14:16 +00002250/**
2251 * xmlDtdDump:
2252 * @doc: the document
2253 *
2254 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002255 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002256static void
2257xmlDtdDump(xmlDocPtr doc) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002258 xmlDtdPtr cur = doc->intSubset;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002259
2260 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002261 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002262 return;
2263 }
2264 xmlBufferWriteChar("<!DOCTYPE ");
2265 xmlBufferWriteCHAR(cur->name);
2266 if (cur->ExternalID != NULL) {
2267 xmlBufferWriteChar(" PUBLIC \"");
2268 xmlBufferWriteCHAR(cur->ExternalID);
2269 xmlBufferWriteChar("\" \"");
2270 xmlBufferWriteCHAR(cur->SystemID);
2271 xmlBufferWriteChar("\"");
2272 } else if (cur->SystemID != NULL) {
2273 xmlBufferWriteChar(" SYSTEM \"");
2274 xmlBufferWriteCHAR(cur->SystemID);
2275 xmlBufferWriteChar("\"");
2276 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00002277 if ((cur->entities == NULL) && (cur->elements == NULL)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002278 xmlBufferWriteChar(">\n");
2279 return;
2280 }
2281 xmlBufferWriteChar(" [\n");
2282 if (cur->entities != NULL)
2283 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002284 if (cur->elements != NULL)
2285 xmlDumpElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002286 xmlBufferWriteChar("]");
2287
2288 /* TODO !!! a lot more things to dump ... */
2289 xmlBufferWriteChar(">\n");
2290}
2291
Daniel Veillard97b58771998-10-20 06:14:16 +00002292/**
2293 * xmlAttrDump:
2294 * @doc: the document
2295 * @cur: the attribute pointer
2296 *
2297 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00002298 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002299static void
2300xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002301 CHAR *value;
2302
Daniel Veillard260a68f1998-08-13 03:39:55 +00002303 if (cur == NULL) {
2304 fprintf(stderr, "xmlAttrDump : property == NULL\n");
2305 return;
2306 }
2307 xmlBufferWriteChar(" ");
2308 xmlBufferWriteCHAR(cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002309 value = xmlNodeListGetString(doc, cur->val, 0);
2310 if (value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002311 xmlBufferWriteChar("=\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00002312 xmlBufferWriteCHAR(value);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002313 xmlBufferWriteChar("\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00002314 free(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00002315 } else {
2316 xmlBufferWriteChar("=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002317 }
2318}
2319
Daniel Veillard97b58771998-10-20 06:14:16 +00002320/**
2321 * xmlAttrListDump:
2322 * @doc: the document
2323 * @cur: the first attribute pointer
2324 *
2325 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00002326 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002327static void
2328xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002329 if (cur == NULL) {
2330 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
2331 return;
2332 }
2333 while (cur != NULL) {
2334 xmlAttrDump(doc, cur);
2335 cur = cur->next;
2336 }
2337}
2338
Daniel Veillard260a68f1998-08-13 03:39:55 +00002339
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002340static void
2341xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00002342/**
2343 * xmlNodeListDump:
2344 * @doc: the document
2345 * @cur: the first node
2346 * @level: the imbrication level for indenting
2347 *
2348 * Dump an XML node list, recursive behaviour,children are printed too.
2349 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002350static void
2351xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002352 int needIndent = 0, i;
2353
Daniel Veillard260a68f1998-08-13 03:39:55 +00002354 if (cur == NULL) {
2355 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
2356 return;
2357 }
2358 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002359 if ((cur->type != XML_TEXT_NODE) &&
2360 (cur->type != XML_ENTITY_REF_NODE)) {
2361 if (!needIndent) {
2362 needIndent = 1;
2363 xmlBufferWriteChar("\n");
2364 }
2365 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002366 xmlNodeDump(doc, cur, level);
2367 cur = cur->next;
2368 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002369 if ((xmlIndentTreeOutput) && (needIndent))
2370 for (i = 1;i < level;i++)
2371 xmlBufferWriteChar(" ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002372}
2373
Daniel Veillard97b58771998-10-20 06:14:16 +00002374/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002375 * xmlNodeDump:
Daniel Veillard97b58771998-10-20 06:14:16 +00002376 * @doc: the document
2377 * @cur: the current node
2378 * @level: the imbrication level for indenting
2379 *
2380 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002381 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002382static void
2383xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002384 int i;
2385
2386 if (cur == NULL) {
2387 fprintf(stderr, "xmlNodeDump : node == NULL\n");
2388 return;
2389 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002390 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002391 if (cur->content != NULL)
2392 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2393 return;
2394 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002395 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002396 if (cur->content != NULL) {
2397 xmlBufferWriteChar("<!--");
2398 xmlBufferWriteCHAR(cur->content);
2399 xmlBufferWriteChar("-->");
2400 }
2401 return;
2402 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002403 if (cur->type == XML_ENTITY_REF_NODE) {
2404 xmlBufferWriteChar("&");
2405 xmlBufferWriteCHAR(cur->name);
2406 xmlBufferWriteChar(";");
2407 return;
2408 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002409 if (xmlIndentTreeOutput)
2410 for (i = 0;i < level;i++)
2411 xmlBufferWriteChar(" ");
2412
2413 xmlBufferWriteChar("<");
2414 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2415 xmlBufferWriteCHAR(cur->ns->prefix);
2416 xmlBufferWriteChar(":");
2417 }
2418
2419 xmlBufferWriteCHAR(cur->name);
2420 if (cur->nsDef)
2421 xmlNsListDump(cur->nsDef);
2422 if (cur->properties != NULL)
2423 xmlAttrListDump(doc, cur->properties);
2424
2425 if ((cur->content == NULL) && (cur->childs == NULL)) {
2426 xmlBufferWriteChar("/>\n");
2427 return;
2428 }
2429 xmlBufferWriteChar(">");
2430 if (cur->content != NULL)
2431 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2432 if (cur->childs != NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002433 xmlNodeListDump(doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002434 }
2435 xmlBufferWriteChar("</");
2436 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2437 xmlBufferWriteCHAR(cur->ns->prefix);
2438 xmlBufferWriteChar(":");
2439 }
2440
2441 xmlBufferWriteCHAR(cur->name);
2442 xmlBufferWriteChar(">\n");
2443}
2444
Daniel Veillard97b58771998-10-20 06:14:16 +00002445/**
2446 * xmlDocContentDump:
2447 * @cur: the document
2448 *
2449 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002450 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002451static void
2452xmlDocContentDump(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002453 if (oldXMLWDcompatibility)
2454 xmlBufferWriteChar("<?XML version=\"");
2455 else
2456 xmlBufferWriteChar("<?xml version=\"");
2457 xmlBufferWriteCHAR(cur->version);
2458 xmlBufferWriteChar("\"");
2459 if (cur->encoding != NULL) {
2460 xmlBufferWriteChar(" encoding=\"");
2461 xmlBufferWriteCHAR(cur->encoding);
2462 xmlBufferWriteChar("\"");
2463 }
2464 switch (cur->standalone) {
2465 case 0:
2466 xmlBufferWriteChar(" standalone=\"no\"");
2467 break;
2468 case 1:
2469 xmlBufferWriteChar(" standalone=\"yes\"");
2470 break;
2471 }
2472 xmlBufferWriteChar("?>\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002473 if (cur->intSubset != NULL)
Daniel Veillard260a68f1998-08-13 03:39:55 +00002474 xmlDtdDump(cur);
2475 if (cur->root != NULL) {
2476 /* global namespace definitions, the old way */
2477 if (oldXMLWDcompatibility)
2478 xmlGlobalNsListDump(cur->oldNs);
2479 else
2480 xmlUpgradeOldNs(cur);
2481 xmlNodeDump(cur, cur->root, 0);
2482 }
2483}
2484
Daniel Veillard97b58771998-10-20 06:14:16 +00002485/**
2486 * xmlDocDumpMemory:
2487 * @cur: the document
2488 * @mem: OUT: the memory pointer
2489 * @size: OUT: the memory lenght
2490 *
2491 * Dump an XML document in memory and return the CHAR * and it's size.
2492 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002493 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002494void
2495xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002496 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002497#ifdef DEBUG_TREE
2498 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
2499#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002500 *mem = NULL;
2501 *size = 0;
2502 return;
2503 }
2504 buffer_index = 0;
2505 xmlDocContentDump(cur);
2506
2507 *mem = buffer;
2508 *size = buffer_index;
2509}
2510
Daniel Veillard97b58771998-10-20 06:14:16 +00002511/**
2512 * xmlGetDocCompressMode:
2513 * @doc: the document
2514 *
2515 * get the compression ratio for a document, ZLIB based
2516 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002517 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002518int
2519 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002520 if (doc == NULL) return(-1);
2521 return(doc->compression);
2522}
2523
Daniel Veillard97b58771998-10-20 06:14:16 +00002524/**
2525 * xmlSetDocCompressMode:
2526 * @doc: the document
2527 * @mode: the compression ratio
2528 *
2529 * set the compression ratio for a document, ZLIB based
2530 * Correct values: 0 (uncompressed) to 9 (max compression)
2531 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002532void
2533xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002534 if (doc == NULL) return;
2535 if (mode < 0) doc->compression = 0;
2536 else if (mode > 9) doc->compression = 9;
2537 else doc->compression = mode;
2538}
2539
Daniel Veillard97b58771998-10-20 06:14:16 +00002540/**
2541 * xmlGetCompressMode:
2542 *
2543 * get the default compression mode used, ZLIB based.
2544 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002545 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002546int
2547 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002548 return(xmlCompressMode);
2549}
Daniel Veillard97b58771998-10-20 06:14:16 +00002550
2551/**
2552 * xmlSetCompressMode:
2553 * @mode: the compression ratio
2554 *
2555 * set the default compression mode used, ZLIB based
2556 * Correct values: 0 (uncompressed) to 9 (max compression)
2557 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002558void
2559xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002560 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002561 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002562 else xmlCompressMode = mode;
2563}
2564
Daniel Veillard97b58771998-10-20 06:14:16 +00002565/**
2566 * xmlDocDump:
2567 * @f: the FILE*
2568 * @cur: the document
2569 *
2570 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002571 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002572void
2573xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002574 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002575#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002576 fprintf(stderr, "xmlDocDump : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002577#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002578 return;
2579 }
2580 buffer_index = 0;
2581 xmlDocContentDump(cur);
2582
2583 fwrite(buffer, sizeof(CHAR), buffer_index, f);
2584}
2585
Daniel Veillard97b58771998-10-20 06:14:16 +00002586/**
2587 * xmlSaveFile:
2588 * @filename: the filename
2589 * @cur: the document
2590 *
2591 * Dump an XML document to a file. Will use compression if
2592 * compiled in and enabled.
2593 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002594 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002595int
2596xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002597#ifdef HAVE_ZLIB_H
2598 gzFile zoutput = NULL;
2599 char mode[15];
2600#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002601 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002602 int ret;
2603
2604#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002605 if ((cur->compression > 0) && (cur->compression <= 9)) {
2606 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002607 zoutput = gzopen(filename, mode);
2608 }
2609 if (zoutput == NULL) {
2610#endif
2611 output = fopen(filename, "w");
2612 if (output == NULL) return(-1);
2613#ifdef HAVE_ZLIB_H
2614 }
2615#endif
2616
2617 /*
2618 * save the content to a temp buffer.
2619 */
2620 buffer_index = 0;
2621 xmlDocContentDump(cur);
2622
2623#ifdef HAVE_ZLIB_H
2624 if (zoutput != NULL) {
2625 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
2626 gzclose(zoutput);
2627 return(ret);
2628 }
2629#endif
2630 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
2631 fclose(output);
2632 return(ret * sizeof(CHAR));
2633}
2634