blob: 4d643d85fcf4ecf25100ecf5f22e3740458d34d8 [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"
23
24static CHAR xmlStringText[] = { 't', 'e', 'x', 't', 0 };
25int oldXMLWDcompatibility = 0;
26int xmlIndentTreeOutput = 1;
27
Daniel Veillard15a8df41998-09-24 19:15:06 +000028static int xmlCompressMode = 0;
29
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000030#define UPDATE_LAST_CHILD(n) if ((n) != NULL) { \
31 xmlNodePtr ulccur = (n)->childs; \
32 if (ulccur == NULL) { \
33 (n)->last = NULL; \
34 } else { \
35 while (ulccur->next != NULL) ulccur = ulccur->next; \
36 (n)->last = ulccur; \
37} }
38
Daniel Veillard260a68f1998-08-13 03:39:55 +000039/************************************************************************
40 * *
41 * Allocation and deallocation of basic structures *
42 * *
43 ************************************************************************/
44
Daniel Veillard97b58771998-10-20 06:14:16 +000045/**
46 * xmlUpgradeOldNs:
47 * @doc: a document pointer
48 *
49 * Upgrade old style Namespaces (PI) and move them to the root of the document.
Daniel Veillard260a68f1998-08-13 03:39:55 +000050 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000051void
52xmlUpgradeOldNs(xmlDocPtr doc) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000053 xmlNsPtr cur;
54
55 if ((doc == NULL) || (doc->oldNs == NULL)) return;
56 if (doc->root == NULL) {
57 fprintf(stderr, "xmlUpgradeOldNs: failed no root !\n");
58 return;
59 }
60
61 cur = doc->oldNs;
62 while (cur->next != NULL) {
63 cur->type = XML_LOCAL_NAMESPACE;
64 cur = cur->next;
65 }
66 cur->type = XML_LOCAL_NAMESPACE;
67 cur->next = doc->root->nsDef;
68 doc->root->nsDef = doc->oldNs;
69 doc->oldNs = NULL;
70}
71
Daniel Veillard97b58771998-10-20 06:14:16 +000072/**
73 * xmlNewNs:
74 * @node: the element carrying the namespace
75 * @href: the URI associated
76 * @prefix: the prefix for the namespace
77 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000078 * Creation of a new Namespace.
Daniel Veillard97b58771998-10-20 06:14:16 +000079 * return values: returns a new namespace pointer
Daniel Veillard260a68f1998-08-13 03:39:55 +000080 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000081xmlNsPtr
82xmlNewNs(xmlNodePtr node, const CHAR *href, const CHAR *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000083 xmlNsPtr cur;
84
85 if (href == NULL) {
86 fprintf(stderr, "xmlNewNs: href == NULL !\n");
87 return(NULL);
88 }
89
90 /*
91 * Allocate a new DTD and fill the fields.
92 */
93 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
94 if (cur == NULL) {
95 fprintf(stderr, "xmlNewNs : malloc failed\n");
96 return(NULL);
97 }
98
99 cur->type = XML_LOCAL_NAMESPACE;
100 if (href != NULL)
101 cur->href = xmlStrdup(href);
102 else
103 cur->href = NULL;
104 if (prefix != NULL)
105 cur->prefix = xmlStrdup(prefix);
106 else
107 cur->prefix = NULL;
108
109 /*
110 * Add it at the end to preserve parsing order ...
111 */
112 cur->next = NULL;
113 if (node != NULL) {
114 if (node->nsDef == NULL) {
115 node->nsDef = cur;
116 } else {
117 xmlNsPtr prev = node->nsDef;
118
119 while (prev->next != NULL) prev = prev->next;
120 prev->next = cur;
121 }
122 }
123
124 return(cur);
125}
126
Daniel Veillard97b58771998-10-20 06:14:16 +0000127/**
128 * xmlNewGlobalNs:
129 * @doc: the document carrying the namespace
130 * @href: the URI associated
131 * @prefix: the prefix for the namespace
132 *
133 * Creation of a Namespace, the old way using PI and without scoping, to AVOID.
134 * return values: returns a new namespace pointer
Daniel Veillard260a68f1998-08-13 03:39:55 +0000135 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000136xmlNsPtr
137xmlNewGlobalNs(xmlDocPtr doc, const CHAR *href, const CHAR *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000138 xmlNsPtr cur;
139
140 /*
141 * Allocate a new DTD and fill the fields.
142 */
143 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
144 if (cur == NULL) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000145 fprintf(stderr, "xmlNewGlobalNs : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000146 return(NULL);
147 }
148
149 cur->type = XML_GLOBAL_NAMESPACE;
150 if (href != NULL)
151 cur->href = xmlStrdup(href);
152 else
153 cur->href = NULL;
154 if (prefix != NULL)
155 cur->prefix = xmlStrdup(prefix);
156 else
157 cur->prefix = NULL;
158
159 /*
160 * Add it at the end to preserve parsing order ...
161 */
162 cur->next = NULL;
163 if (doc != NULL) {
164 if (doc->oldNs == NULL) {
165 doc->oldNs = cur;
166 } else {
167 xmlNsPtr prev = doc->oldNs;
168
169 while (prev->next != NULL) prev = prev->next;
170 prev->next = cur;
171 }
172 }
173
174 return(cur);
175}
176
Daniel Veillard97b58771998-10-20 06:14:16 +0000177/**
178 * xmlSetNs:
179 * @node: a node in the document
180 * @ns: a namespace pointer
181 *
182 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000183 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000184void
185xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000186 if (node == NULL) {
187 fprintf(stderr, "xmlSetNs: node == NULL\n");
188 return;
189 }
190 node->ns = ns;
191}
192
Daniel Veillard97b58771998-10-20 06:14:16 +0000193/**
194 * xmlFreeNs:
195 * @cur: the namespace pointer
196 *
197 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000198 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000199void
200xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000201 if (cur == NULL) {
202 fprintf(stderr, "xmlFreeNs : ns == NULL\n");
203 return;
204 }
205 if (cur->href != NULL) free((char *) cur->href);
206 if (cur->prefix != NULL) free((char *) cur->prefix);
207 memset(cur, -1, sizeof(xmlNs));
208 free(cur);
209}
210
Daniel Veillard97b58771998-10-20 06:14:16 +0000211/**
212 * xmlFreeNsList:
213 * @cur: the first namespace pointer
214 *
215 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000216 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000217void
218xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000219 xmlNsPtr next;
220 if (cur == NULL) {
221 fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
222 return;
223 }
224 while (cur != NULL) {
225 next = cur->next;
226 xmlFreeNs(cur);
227 cur = next;
228 }
229}
230
Daniel Veillard97b58771998-10-20 06:14:16 +0000231/**
232 * xmlNewDtd:
233 * @doc: the document pointer
234 * @name: the DTD name
235 * @ExternalID: the external ID
236 * @SystemID: the system ID
237 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000238 * Creation of a new DTD.
Daniel Veillard97b58771998-10-20 06:14:16 +0000239 * return values: a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000240 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000241xmlDtdPtr
242xmlNewDtd(xmlDocPtr doc, const CHAR *name,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000243 const CHAR *ExternalID, const CHAR *SystemID) {
244 xmlDtdPtr cur;
245
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000246 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000247 fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000248 /* !!! */ (char *) name, doc->name,
249 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000250 }
251
252 /*
253 * Allocate a new DTD and fill the fields.
254 */
255 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
256 if (cur == NULL) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000257 fprintf(stderr, "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000258 return(NULL);
259 }
260
261 if (name != NULL)
262 cur->name = xmlStrdup(name);
263 else
264 cur->name = NULL;
265 if (ExternalID != NULL)
266 cur->ExternalID = xmlStrdup(ExternalID);
267 else
268 cur->ExternalID = NULL;
269 if (SystemID != NULL)
270 cur->SystemID = xmlStrdup(SystemID);
271 else
272 cur->SystemID = NULL;
273 cur->elements = NULL;
274 cur->entities = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000275 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000276 doc->extSubset = cur;
277
278 return(cur);
279}
280
281/**
282 * xmlCreateIntSubset:
283 * @doc: the document pointer
284 * @name: the DTD name
285 * @ExternalID: the external ID
286 * @SystemID: the system ID
287 *
288 * Creatte the internal subset of a document
289 * return values: a pointer to the new DTD structure
290 */
291xmlDtdPtr
292xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
293 const CHAR *ExternalID, const CHAR *SystemID) {
294 xmlDtdPtr cur;
295
296 if ((doc != NULL) && (doc->intSubset != NULL)) {
297 fprintf(stderr,
298 "xmlCreateIntSubset(): document %s already have an internal subset\n",
299 doc->name);
300 return(NULL);
301 }
302
303 /*
304 * Allocate a new DTD and fill the fields.
305 */
306 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
307 if (cur == NULL) {
308 fprintf(stderr, "xmlNewDtd : malloc failed\n");
309 return(NULL);
310 }
311
312 if (name != NULL)
313 cur->name = xmlStrdup(name);
314 else
315 cur->name = NULL;
316 if (ExternalID != NULL)
317 cur->ExternalID = xmlStrdup(ExternalID);
318 else
319 cur->ExternalID = NULL;
320 if (SystemID != NULL)
321 cur->SystemID = xmlStrdup(SystemID);
322 else
323 cur->SystemID = NULL;
324 cur->elements = NULL;
325 cur->entities = NULL;
326 if (doc != NULL)
327 doc->intSubset = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000328
329 return(cur);
330}
331
Daniel Veillard97b58771998-10-20 06:14:16 +0000332/**
333 * xmlFreeDtd:
334 * @cur: the DTD structure to free up
335 *
336 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000337 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000338void
339xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000340 if (cur == NULL) {
341 fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
342 return;
343 }
344 if (cur->name != NULL) free((char *) cur->name);
345 if (cur->SystemID != NULL) free((char *) cur->SystemID);
346 if (cur->ExternalID != NULL) free((char *) cur->ExternalID);
347 if (cur->elements != NULL)
348 fprintf(stderr, "xmlFreeDtd: cur->elements != NULL !!! \n");
349 if (cur->entities != NULL)
350 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
351 memset(cur, -1, sizeof(xmlDtd));
352 free(cur);
353}
354
Daniel Veillard97b58771998-10-20 06:14:16 +0000355/**
356 * xmlNewDoc:
357 * @version: CHAR string giving the version of XML "1.0"
358 *
359 * Create a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000360 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000361xmlDocPtr
362xmlNewDoc(const CHAR *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000363 xmlDocPtr cur;
364
365 if (version == NULL) {
366 fprintf(stderr, "xmlNewDoc : version == NULL\n");
367 return(NULL);
368 }
369
370 /*
371 * Allocate a new document and fill the fields.
372 */
373 cur = (xmlDocPtr) malloc(sizeof(xmlDoc));
374 if (cur == NULL) {
375 fprintf(stderr, "xmlNewDoc : malloc failed\n");
376 return(NULL);
377 }
378
Daniel Veillard33942841998-10-18 19:12:41 +0000379 cur->type = XML_DOCUMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000380 cur->version = xmlStrdup(version);
381 cur->name = NULL;
382 cur->root = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000383 cur->intSubset = NULL;
384 cur->extSubset = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000385 cur->oldNs = NULL;
386 cur->encoding = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000387 cur->standalone = -1;
Daniel Veillard15a8df41998-09-24 19:15:06 +0000388 cur->compression = xmlCompressMode;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000389#ifndef WITHOUT_CORBA
390 cur->_private = NULL;
391 cur->vepv = NULL;
392#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000393 return(cur);
394}
395
Daniel Veillard97b58771998-10-20 06:14:16 +0000396/**
397 * xmlFreeDoc:
398 * @cur: pointer to the document
399 * @:
400 *
401 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000402 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000403void
404xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000405 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000406#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000407 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000408#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000409 return;
410 }
411 free((char *) cur->version);
412 if (cur->name != NULL) free((char *) cur->name);
413 if (cur->encoding != NULL) free((char *) cur->encoding);
414 if (cur->root != NULL) xmlFreeNode(cur->root);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000415 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
416 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000417 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000418 memset(cur, -1, sizeof(xmlDoc));
419 free(cur);
420}
421
Daniel Veillard97b58771998-10-20 06:14:16 +0000422/**
Daniel Veillard16253641998-10-28 22:58:05 +0000423 * xmlStringLenGetNodeList:
424 * @doc: the document
425 * @value: the value of the text
426 * @int len: the length of the string value
427 *
428 * Parse the value string and build the node list associated. Should
429 * produce a flat tree with only TEXTs and ENTITY_REFs.
430 * return values: a pointer to the first child
431 */
432xmlNodePtr
433xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
434 xmlNodePtr ret = NULL, last = NULL;
435 xmlNodePtr node;
436 CHAR *val;
437 const CHAR *cur = value;
438 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000439 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000440
441 if (value == NULL) return(NULL);
442
443 q = cur;
444 while ((*cur != 0) && (cur - value < len)) {
445 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000446 /*
447 * Save the current text.
448 */
Daniel Veillard16253641998-10-28 22:58:05 +0000449 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000450 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
451 xmlNodeAddContentLen(last, q, cur - q);
452 } else {
453 node = xmlNewDocTextLen(doc, q, cur - q);
454 if (node == NULL) return(ret);
455 if (last == NULL)
456 last = ret = node;
457 else {
458 last->next = node;
459 node->prev = last;
460 last = node;
461 }
Daniel Veillard16253641998-10-28 22:58:05 +0000462 }
463 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000464 /*
465 * Read the entity string
466 */
Daniel Veillard16253641998-10-28 22:58:05 +0000467 cur++;
468 q = cur;
469 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
470 if ((*cur == 0) || (cur - value >= len)) {
471 fprintf(stderr,
472 "xmlStringGetNodeList: unterminated entity %30s\n", q);
473 return(ret);
474 }
475 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000476 /*
477 * Predefined entities don't generate nodes
478 */
Daniel Veillard16253641998-10-28 22:58:05 +0000479 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000480 ent = xmlGetDocEntity(doc, val);
481 if ((ent != NULL) &&
482 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
483 if (last == NULL) {
484 node = xmlNewDocText(doc, ent->content);
485 last = ret = node;
486 } else
487 xmlNodeAddContent(last, ent->content);
488
489 } else {
490 /*
491 * Create a new REFERENCE_REF node
492 */
493 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000494 if (node == NULL) {
495 if (val != NULL) free(val);
496 return(ret);
497 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000498 if (last == NULL)
499 last = ret = node;
500 else {
501 last->next = node;
502 node->prev = last;
503 last = node;
504 }
Daniel Veillard16253641998-10-28 22:58:05 +0000505 }
506 free(val);
507 }
508 cur++;
509 q = cur;
510 } else
511 cur++;
512 }
513 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000514 /*
515 * Handle the last piece of text.
516 */
517 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
518 xmlNodeAddContentLen(last, q, cur - q);
519 } else {
520 node = xmlNewDocTextLen(doc, q, cur - q);
521 if (node == NULL) return(ret);
522 if (last == NULL)
523 last = ret = node;
524 else {
525 last->next = node;
526 node->prev = last;
527 last = node;
528 }
Daniel Veillard16253641998-10-28 22:58:05 +0000529 }
530 }
531 return(ret);
532}
533
534/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000535 * xmlStringGetNodeList:
536 * @doc: the document
537 * @value: the value of the attribute
538 *
539 * Parse the value string and build the node list associated. Should
540 * produce a flat tree with only TEXTs and ENTITY_REFs.
541 * return values: a pointer to the first child
542 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000543xmlNodePtr
544xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000545 xmlNodePtr ret = NULL, last = NULL;
546 xmlNodePtr node;
547 CHAR *val;
548 const CHAR *cur = value;
549 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000550 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000551
552 if (value == NULL) return(NULL);
553
554 q = cur;
555 while (*cur != 0) {
556 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000557 /*
558 * Save the current text.
559 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000560 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000561 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
562 xmlNodeAddContentLen(last, q, cur - q);
563 } else {
564 node = xmlNewDocTextLen(doc, q, cur - q);
565 if (node == NULL) return(ret);
566 if (last == NULL)
567 last = ret = node;
568 else {
569 last->next = node;
570 node->prev = last;
571 last = node;
572 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000573 }
574 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000575 /*
576 * Read the entity string
577 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000578 cur++;
579 q = cur;
580 while ((*cur != 0) && (*cur != ';')) cur++;
581 if (*cur == 0) {
582 fprintf(stderr,
583 "xmlStringGetNodeList: unterminated entity %30s\n", q);
584 return(ret);
585 }
586 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000587 /*
588 * Predefined entities don't generate nodes
589 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000590 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000591 ent = xmlGetDocEntity(doc, val);
592 if ((ent != NULL) &&
593 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
594 if (last == NULL) {
595 node = xmlNewDocText(doc, ent->content);
596 last = ret = node;
597 } else
598 xmlNodeAddContent(last, ent->content);
599
600 } else {
601 /*
602 * Create a new REFERENCE_REF node
603 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000604 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000605 if (node == NULL) {
606 if (val != NULL) free(val);
607 return(ret);
608 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000609 if (last == NULL)
610 last = ret = node;
611 else {
612 last->next = node;
613 node->prev = last;
614 last = node;
615 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000616 }
617 free(val);
618 }
619 cur++;
620 q = cur;
621 } else
622 cur++;
623 }
624 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000625 /*
626 * Handle the last piece of text.
627 */
628 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
629 xmlNodeAddContentLen(last, q, cur - q);
630 } else {
631 node = xmlNewDocTextLen(doc, q, cur - q);
632 if (node == NULL) return(ret);
633 if (last == NULL)
634 last = ret = node;
635 else {
636 last->next = node;
637 node->prev = last;
638 last = node;
639 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000640 }
641 }
642 return(ret);
643}
644
645/**
646 * xmlNodeListGetString:
647 * @doc: the document
648 * @list: a Node list
649 * @inLine: should we replace entity contents or show their external form
650 *
651 * Returns the string equivalent to the text contained in the Node list
652 * made of TEXTs and ENTITY_REFs
653 * return values: a pointer to the string copy, the calller must free it.
654 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000655CHAR *
656xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000657 xmlNodePtr node = list;
658 CHAR *ret = NULL;
659 xmlEntityPtr ent;
660
661 if (list == NULL) return(NULL);
662
663 while (node != NULL) {
664 if (node->type == XML_TEXT_NODE) {
665 if (inLine)
666 ret = xmlStrcat(ret, node->content);
667 else
668 ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
669 } else if (node->type == XML_ENTITY_REF_NODE) {
670 if (inLine) {
671 ent = xmlGetDocEntity(doc, node->name);
672 if (ent != NULL)
673 ret = xmlStrcat(ret, ent->content);
674 else
675 ret = xmlStrcat(ret, node->content);
676 } else {
677 CHAR buf[2];
678 buf[0] = '&'; buf[1] = 0;
679 ret = xmlStrncat(ret, buf, 1);
680 ret = xmlStrcat(ret, node->name);
681 buf[0] = ';'; buf[1] = 0;
682 ret = xmlStrncat(ret, buf, 1);
683 }
684 }
685#if 0
686 else {
687 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
688 node->type);
689 }
690#endif
691 node = node->next;
692 }
693 return(ret);
694}
695
696/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000697 * xmlNewProp:
698 * @node: the holding node
699 * @name: the name of the attribute
700 * @value: the value of the attribute
701 *
702 * Create a new property carried by a node.
703 * return values: a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000704 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000705xmlAttrPtr
706xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000707 xmlAttrPtr cur;
708
709 if (name == NULL) {
710 fprintf(stderr, "xmlNewProp : name == NULL\n");
711 return(NULL);
712 }
713
714 /*
715 * Allocate a new property and fill the fields.
716 */
717 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
718 if (cur == NULL) {
719 fprintf(stderr, "xmlNewProp : malloc failed\n");
720 return(NULL);
721 }
722
Daniel Veillard33942841998-10-18 19:12:41 +0000723 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000724 cur->node = node;
725 cur->name = xmlStrdup(name);
726 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +0000727 cur->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000728 else
Daniel Veillardccb09631998-10-27 06:21:04 +0000729 cur->val = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000730#ifndef WITHOUT_CORBA
731 cur->_private = NULL;
732 cur->vepv = NULL;
733#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000734
735 /*
736 * Add it at the end to preserve parsing order ...
737 */
738 cur->next = NULL;
739 if (node != NULL) {
740 if (node->properties == NULL) {
741 node->properties = cur;
742 } else {
743 xmlAttrPtr prev = node->properties;
744
745 while (prev->next != NULL) prev = prev->next;
746 prev->next = cur;
747 }
748 }
749 return(cur);
750}
751
Daniel Veillard97b58771998-10-20 06:14:16 +0000752/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000753 * xmlNewDocProp:
754 * @doc: the document
755 * @name: the name of the attribute
756 * @value: the value of the attribute
757 *
758 * Create a new property carried by a document.
759 * return values: a pointer to the attribute
760 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000761xmlAttrPtr
762xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000763 xmlAttrPtr cur;
764
765 if (name == NULL) {
766 fprintf(stderr, "xmlNewProp : name == NULL\n");
767 return(NULL);
768 }
769
770 /*
771 * Allocate a new property and fill the fields.
772 */
773 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
774 if (cur == NULL) {
775 fprintf(stderr, "xmlNewProp : malloc failed\n");
776 return(NULL);
777 }
778
779 cur->type = XML_ATTRIBUTE_NODE;
780 cur->node = NULL;
781 cur->name = xmlStrdup(name);
782 if (value != NULL)
783 cur->val = xmlStringGetNodeList(doc, value);
784 else
785 cur->val = NULL;
786#ifndef WITHOUT_CORBA
787 cur->_private = NULL;
788 cur->vepv = NULL;
789#endif
790
791 cur->next = NULL;
792 return(cur);
793}
794
795/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000796 * xmlFreePropList:
797 * @cur: the first property in the list
798 *
799 * Free a property and all its siblings, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000800 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000801void
802xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000803 xmlAttrPtr next;
804 if (cur == NULL) {
805 fprintf(stderr, "xmlFreePropList : property == NULL\n");
806 return;
807 }
808 while (cur != NULL) {
809 next = cur->next;
810 xmlFreeProp(cur);
811 cur = next;
812 }
813}
814
Daniel Veillard97b58771998-10-20 06:14:16 +0000815/**
816 * xmlFreeProp:
817 * @cur: the first property in the list
818 *
819 * Free one property, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000820 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000821void
822xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000823 if (cur == NULL) {
824 fprintf(stderr, "xmlFreeProp : property == NULL\n");
825 return;
826 }
827 if (cur->name != NULL) free((char *) cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +0000828 if (cur->val != NULL) xmlFreeNodeList(cur->val);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000829 memset(cur, -1, sizeof(xmlAttr));
830 free(cur);
831}
832
Daniel Veillard97b58771998-10-20 06:14:16 +0000833/**
834 * xmlNewNode:
835 * @ns: namespace if any
836 * @name: the node name
837 * @content: the text content if any
838 *
839 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +0000840 * If content is non NULL, a child list containing the TEXTs and
841 * ENTITY_REFs node will be created.
Daniel Veillard97b58771998-10-20 06:14:16 +0000842 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000843 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000844xmlNodePtr
845xmlNewNode(xmlNsPtr ns, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000846 xmlNodePtr cur;
847
848 if (name == NULL) {
849 fprintf(stderr, "xmlNewNode : name == NULL\n");
850 return(NULL);
851 }
852
853 /*
854 * Allocate a new node and fill the fields.
855 */
856 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
857 if (cur == NULL) {
858 fprintf(stderr, "xmlNewNode : malloc failed\n");
859 return(NULL);
860 }
861
Daniel Veillard33942841998-10-18 19:12:41 +0000862 cur->type = XML_ELEMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000863 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000864 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000865 cur->next = NULL;
866 cur->prev = NULL;
867 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000868 cur->last = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000869 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000870 cur->name = xmlStrdup(name);
871 cur->ns = ns;
872 cur->nsDef = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000873 cur->content = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000874#ifndef WITHOUT_CORBA
875 cur->_private = NULL;
876 cur->vepv = NULL;
877#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000878 return(cur);
879}
880
Daniel Veillard97b58771998-10-20 06:14:16 +0000881/**
882 * xmlNewDocNode:
883 * @doc: the document
884 * @ns: namespace if any
885 * @name: the node name
886 * @content: the text content if any
887 *
888 * Creation of a new node element within a document. @ns and @content
889 * are optionnal (NULL).
890 * return values: a pointer to the new node object.
891 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000892xmlNodePtr
893xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard0bef1311998-10-14 02:36:47 +0000894 const CHAR *name, CHAR *content) {
895 xmlNodePtr cur;
896
Daniel Veillardccb09631998-10-27 06:21:04 +0000897 cur = xmlNewNode(ns, name);
898 if (cur != NULL) {
899 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000900 if (content != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000901 cur->childs = xmlStringGetNodeList(doc, content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000902 UPDATE_LAST_CHILD(cur);
903 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000904 }
Daniel Veillard0bef1311998-10-14 02:36:47 +0000905 return(cur);
906}
907
908
Daniel Veillard97b58771998-10-20 06:14:16 +0000909/**
910 * xmlNewText:
911 * @content: the text content
912 *
913 * Creation of a new text node.
914 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000915 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000916xmlNodePtr
917xmlNewText(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000918 xmlNodePtr cur;
919
920 /*
921 * Allocate a new node and fill the fields.
922 */
923 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
924 if (cur == NULL) {
925 fprintf(stderr, "xmlNewText : malloc failed\n");
926 return(NULL);
927 }
928
Daniel Veillard33942841998-10-18 19:12:41 +0000929 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000930 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000931 cur->parent = NULL;
932 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000933 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000934 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000935 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000936 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000937 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000938 cur->name = xmlStrdup(xmlStringText);
939 cur->ns = NULL;
940 cur->nsDef = NULL;
941 if (content != NULL)
942 cur->content = xmlStrdup(content);
943 else
944 cur->content = NULL;
945 return(cur);
946}
947
Daniel Veillard97b58771998-10-20 06:14:16 +0000948/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000949 * xmlNewReference:
950 * @doc: the document
951 * @name: the reference name, or the reference string with & and ;
952 *
953 * Creation of a new reference node.
954 * return values: a pointer to the new node object.
955 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000956xmlNodePtr
957xmlNewReference(xmlDocPtr doc, const CHAR *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000958 xmlNodePtr cur;
959 xmlEntityPtr ent;
960
961 /*
962 * Allocate a new node and fill the fields.
963 */
964 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
965 if (cur == NULL) {
966 fprintf(stderr, "xmlNewText : malloc failed\n");
967 return(NULL);
968 }
969
970 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillard10c6a8f1998-10-28 01:00:12 +0000971 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +0000972 cur->parent = NULL;
973 cur->next = NULL;
974 cur->prev = NULL;
975 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000976 cur->last = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000977 cur->properties = NULL;
978 if (name[0] == '&') {
979 int len;
980 name++;
981 len = xmlStrlen(name);
982 if (name[len - 1] == ';')
983 cur->name = xmlStrndup(name, len - 1);
984 else
985 cur->name = xmlStrndup(name, len);
986 } else
987 cur->name = xmlStrdup(name);
988 cur->ns = NULL;
989 cur->nsDef = NULL;
990
991 ent = xmlGetDocEntity(doc, cur->name);
992 if (ent != NULL)
993 cur->content = ent->content;
994 else
995 cur->content = NULL;
996 return(cur);
997}
998
999/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001000 * xmlNewDocText:
1001 * @doc: the document
1002 * @content: the text content
1003 *
1004 * Creation of a new text node within a document.
1005 * return values: a pointer to the new node object.
1006 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001007xmlNodePtr
1008xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001009 xmlNodePtr cur;
1010
1011 cur = xmlNewText(content);
1012 if (cur != NULL) cur->doc = doc;
1013 return(cur);
1014}
1015
Daniel Veillard97b58771998-10-20 06:14:16 +00001016/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001017 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001018 * @content: the text content
1019 * @len: the text len.
1020 *
1021 * Creation of a new text node with an extra parameter for the content's lenght
1022 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001023 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001024xmlNodePtr
1025xmlNewTextLen(const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001026 xmlNodePtr cur;
1027
1028 /*
1029 * Allocate a new node and fill the fields.
1030 */
1031 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1032 if (cur == NULL) {
1033 fprintf(stderr, "xmlNewText : malloc failed\n");
1034 return(NULL);
1035 }
1036
Daniel Veillard33942841998-10-18 19:12:41 +00001037 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001038 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001039 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001040 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001041 cur->next = NULL;
1042 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001043 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001044 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001045 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001046 cur->name = xmlStrdup(xmlStringText);
1047 cur->ns = NULL;
1048 cur->nsDef = NULL;
1049 if (content != NULL)
1050 cur->content = xmlStrndup(content, len);
1051 else
1052 cur->content = NULL;
1053 return(cur);
1054}
1055
Daniel Veillard97b58771998-10-20 06:14:16 +00001056/**
1057 * xmlNewDocTextLen:
1058 * @doc: the document
1059 * @content: the text content
1060 * @len: the text len.
1061 *
1062 * Creation of a new text node with an extra content lenght parameter. The
1063 * text node pertain to a given document.
1064 * return values: a pointer to the new node object.
1065 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001066xmlNodePtr
1067xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001068 xmlNodePtr cur;
1069
1070 cur = xmlNewTextLen(content, len);
1071 if (cur != NULL) cur->doc = doc;
1072 return(cur);
1073}
1074
Daniel Veillard97b58771998-10-20 06:14:16 +00001075/**
1076 * xmlNewComment:
1077 * @content: the comment content
1078 *
1079 * Creation of a new node containing a comment.
1080 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001081 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001082xmlNodePtr
1083xmlNewComment(CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001084 xmlNodePtr cur;
1085
1086 /*
1087 * Allocate a new node and fill the fields.
1088 */
1089 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1090 if (cur == NULL) {
1091 fprintf(stderr, "xmlNewComment : malloc failed\n");
1092 return(NULL);
1093 }
1094
Daniel Veillard33942841998-10-18 19:12:41 +00001095 cur->type = XML_COMMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001096 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001097 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001098 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001099 cur->next = NULL;
1100 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001101 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001102 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001103 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001104 cur->name = xmlStrdup(xmlStringText);
1105 cur->ns = NULL;
1106 cur->nsDef = NULL;
1107 if (content != NULL)
1108 cur->content = xmlStrdup(content);
1109 else
1110 cur->content = NULL;
1111 return(cur);
1112}
1113
Daniel Veillard97b58771998-10-20 06:14:16 +00001114/**
1115 * xmlNewComment:
1116 * @doc: the document
1117 * @content: the comment content
1118 *
1119 * Creation of a new node containing a commentwithin a document.
1120 * return values: a pointer to the new node object.
1121 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001122xmlNodePtr
1123xmlNewDocComment(xmlDocPtr doc, CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001124 xmlNodePtr cur;
1125
1126 cur = xmlNewComment(content);
1127 if (cur != NULL) cur->doc = doc;
1128 return(cur);
1129}
1130
Daniel Veillard97b58771998-10-20 06:14:16 +00001131/**
1132 * xmlNewChild:
1133 * @parent: the parent node
1134 * @ns: a namespace if any
1135 * @name: the name of the child
1136 * @content: the content of the child if any.
1137 *
1138 *
1139 * Creation of a new child element, added at the end of @parent childs list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001140 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1141 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard97b58771998-10-20 06:14:16 +00001142 * return values: a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001143 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001144xmlNodePtr
1145xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001146 const CHAR *name, CHAR *content) {
1147 xmlNodePtr cur, prev;
1148
1149 if (parent == NULL) {
1150 fprintf(stderr, "xmlNewChild : parent == NULL\n");
1151 return(NULL);
1152 }
1153
1154 if (name == NULL) {
1155 fprintf(stderr, "xmlNewChild : name == NULL\n");
1156 return(NULL);
1157 }
1158
1159 /*
1160 * Allocate a new node
1161 */
1162 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001163 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001164 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001165 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001166 if (cur == NULL) return(NULL);
1167
1168 /*
1169 * add the new element at the end of the childs list.
1170 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001171 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001172 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001173 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001174 if (parent->childs == NULL) {
1175 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001176 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001177 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001178 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001179 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001180 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001181 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001182 }
1183
1184 return(cur);
1185}
1186
Daniel Veillard97b58771998-10-20 06:14:16 +00001187/**
1188 * xmlAddChild:
1189 * @parent: the parent node
1190 * @cur: the child node
1191 *
1192 * Add a new child element, to @parent, at the end of the child list.
1193 * return values: the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001194 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001195xmlNodePtr
1196xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001197 xmlNodePtr prev;
1198
1199 if (parent == NULL) {
1200 fprintf(stderr, "xmladdChild : parent == NULL\n");
1201 return(NULL);
1202 }
1203
1204 if (cur == NULL) {
1205 fprintf(stderr, "xmladdChild : child == NULL\n");
1206 return(NULL);
1207 }
1208
Daniel Veillard0bef1311998-10-14 02:36:47 +00001209 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1210 (cur->doc != parent->doc)) {
1211 fprintf(stderr, "Elements moved to a different document\n");
1212 }
1213
Daniel Veillard260a68f1998-08-13 03:39:55 +00001214 /*
1215 * add the new element at the end of the childs list.
1216 */
1217 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001218 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001219
Daniel Veillardccb09631998-10-27 06:21:04 +00001220 /*
1221 * Handle the case where parent->content != NULL, in that case it will
1222 * create a intermediate TEXT node.
1223 */
1224 if (parent->content != NULL) {
1225 xmlNodePtr text;
1226
1227 text = xmlNewDocText(parent->doc, parent->content);
1228 if (text != NULL) {
1229 text->next = parent->childs;
1230 if (text->next != NULL)
1231 text->next->prev = text;
1232 parent->childs = text;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001233 UPDATE_LAST_CHILD(parent);
Daniel Veillardccb09631998-10-27 06:21:04 +00001234 free(parent->content);
1235 parent->content = NULL;
1236 }
1237 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001238 if (parent->childs == NULL) {
1239 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001240 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001241 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001242 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001243 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001244 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001245 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001246 }
1247
1248 return(cur);
1249}
1250
Daniel Veillard97b58771998-10-20 06:14:16 +00001251/**
1252 * xmlGetLastChild:
1253 * @parent: the parent node
1254 *
1255 * Search the last child of a node.
1256 * return values: the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001257 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001258xmlNodePtr
1259xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001260 if (parent == NULL) {
1261 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1262 return(NULL);
1263 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001264 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001265}
1266
Daniel Veillard97b58771998-10-20 06:14:16 +00001267/**
1268 * xmlFreeNodeList:
1269 * @cur: the first node in the list
1270 *
1271 * Free a node and all its siblings, this is a recursive behaviour, all
1272 * the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001273 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001274void
1275xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001276 xmlNodePtr next;
1277 if (cur == NULL) {
1278 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1279 return;
1280 }
1281 while (cur != NULL) {
1282 next = cur->next;
1283 xmlFreeNode(cur);
1284 cur = next;
1285 }
1286}
1287
Daniel Veillard97b58771998-10-20 06:14:16 +00001288/**
1289 * xmlFreeNode:
1290 * @cur: the node
1291 *
1292 * Free a node, this is a recursive behaviour, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001293 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001294void
1295xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001296 if (cur == NULL) {
1297 fprintf(stderr, "xmlFreeNode : node == NULL\n");
1298 return;
1299 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001300 cur->doc = NULL;
1301 cur->parent = NULL;
1302 cur->next = NULL;
1303 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001304 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
Daniel Veillardccb09631998-10-27 06:21:04 +00001305 if (cur->properties != NULL) xmlFreePropList(cur->properties);
1306 if (cur->type != XML_ENTITY_REF_NODE)
1307 if (cur->content != NULL) free(cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001308 if (cur->name != NULL) free((char *) cur->name);
1309 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1310 memset(cur, -1, sizeof(xmlNode));
1311 free(cur);
1312}
1313
Daniel Veillard16253641998-10-28 22:58:05 +00001314/**
1315 * xmlUnlinkNode:
1316 * @cur: the node
1317 *
1318 * Unlink a node from it's current context, the node is not freed
1319 */
1320void
1321xmlUnlinkNode(xmlNodePtr cur) {
1322 if (cur == NULL) {
1323 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1324 return;
1325 }
1326 if ((cur->parent != NULL) && (cur->parent->childs == cur))
1327 cur->parent->childs = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001328 if ((cur->parent != NULL) && (cur->parent->last == cur))
1329 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00001330 if (cur->next != NULL)
1331 cur->next->prev = cur->prev;
1332 if (cur->prev != NULL)
1333 cur->prev->next = cur->next;
1334 cur->next = cur->prev = NULL;
1335 cur->parent = NULL;
1336}
1337
Daniel Veillard260a68f1998-08-13 03:39:55 +00001338/************************************************************************
1339 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001340 * Copy operations *
1341 * *
1342 ************************************************************************/
1343
1344/**
1345 * xmlCopyNamespace:
1346 * @cur: the namespace
1347 *
1348 * Do a copy of the namespace.
1349 *
1350 * Returns: a new xmlNsPtr, or NULL in case of error.
1351 */
1352xmlNsPtr
1353xmlCopyNamespace(xmlNsPtr cur) {
1354 xmlNsPtr ret;
1355
1356 if (cur == NULL) return(NULL);
1357 switch (cur->type) {
1358 case XML_GLOBAL_NAMESPACE:
1359 ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
1360 break;
1361 case XML_LOCAL_NAMESPACE:
1362 ret = xmlNewNs(NULL, cur->href, cur->prefix);
1363 break;
1364 default:
1365 fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
1366 return(NULL);
1367 }
1368 return(ret);
1369}
1370
1371/**
1372 * xmlCopyNamespaceList:
1373 * @cur: the first namespace
1374 *
1375 * Do a copy of an namespace list.
1376 *
1377 * Returns: a new xmlNsPtr, or NULL in case of error.
1378 */
1379xmlNsPtr
1380xmlCopyNamespaceList(xmlNsPtr cur) {
1381 xmlNsPtr ret = NULL;
1382 xmlNsPtr p = NULL,q;
1383
1384 while (cur != NULL) {
1385 q = xmlCopyNamespace(cur);
1386 if (p == NULL) {
1387 ret = p = q;
1388 } else {
1389 p->next = q;
1390 p = q;
1391 }
1392 cur = cur->next;
1393 }
1394 return(ret);
1395}
1396
1397/**
1398 * xmlCopyProp:
1399 * @cur: the attribute
1400 *
1401 * Do a copy of the attribute.
1402 *
1403 * Returns: a new xmlAttrPtr, or NULL in case of error.
1404 */
1405xmlAttrPtr
1406xmlCopyProp(xmlAttrPtr cur) {
1407 xmlAttrPtr ret;
1408
1409 if (cur == NULL) return(NULL);
1410 if (cur->val != NULL)
1411 ret = xmlNewDocProp(cur->val->doc, cur->name, NULL);
1412 else
1413 ret = xmlNewDocProp(NULL, cur->name, NULL);
1414 if (ret == NULL) return(NULL);
1415 if (cur->val != NULL)
1416 ret->val = xmlCopyNodeList(cur->val);
1417 return(ret);
1418}
1419
1420/**
1421 * xmlCopyPropList:
1422 * @cur: the first attribute
1423 *
1424 * Do a copy of an attribute list.
1425 *
1426 * Returns: a new xmlAttrPtr, or NULL in case of error.
1427 */
1428xmlAttrPtr
1429xmlCopyPropList(xmlAttrPtr cur) {
1430 xmlAttrPtr ret = NULL;
1431 xmlAttrPtr p = NULL,q;
1432
1433 while (cur != NULL) {
1434 q = xmlCopyProp(cur);
1435 if (p == NULL) {
1436 ret = p = q;
1437 } else {
1438 p->next = q;
1439 p = q;
1440 }
1441 cur = cur->next;
1442 }
1443 return(ret);
1444}
1445
1446/*
1447 * NOTE about the CopyNode operations !
1448 *
1449 * They are splitted into external and internal parts for one
1450 * tricky reason: namespaces. Doing a direct copy of a node
1451 * say RPM:Copyright without changing the namespace pointer to
1452 * something else can produce stale links. One way to do it is
1453 * to keep a reference counter but this doesn't work as soon
1454 * as one move the element or the subtree out of the scope of
1455 * the existing namespace. The actual solution seems to add
1456 * a copy of the namespace at the top of the copied tree if
1457 * not available in the subtree.
1458 * Hence two functions, the public front-end call the inner ones
1459 */
1460
1461static xmlNodePtr
1462xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
1463
1464static xmlNodePtr
1465xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
1466 int recursive) {
1467 xmlNodePtr ret;
1468
1469 if (node == NULL) return(NULL);
1470 /*
1471 * Allocate a new node and fill the fields.
1472 */
1473 ret = (xmlNodePtr) malloc(sizeof(xmlNode));
1474 if (ret == NULL) {
1475 fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
1476 return(NULL);
1477 }
1478
1479 ret->type = node->type;
1480 ret->doc = doc;
1481 ret->parent = parent;
1482 ret->next = NULL;
1483 ret->prev = NULL;
1484 ret->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001485 ret->last = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001486 ret->properties = NULL;
1487 if (node->name != NULL)
1488 ret->name = xmlStrdup(node->name);
1489 else
1490 ret->name = NULL;
1491 ret->ns = NULL;
1492 ret->nsDef = NULL;
1493 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE))
1494 ret->content = xmlStrdup(node->content);
1495 else
1496 ret->content = NULL;
1497#ifndef WITHOUT_CORBA
1498 ret->_private = NULL;
1499 ret->vepv = NULL;
1500#endif
1501 if (parent != NULL)
1502 xmlAddChild(parent, ret);
1503
1504 if (!recursive) return(ret);
1505 if (node->properties != NULL)
1506 ret->properties = xmlCopyPropList(node->properties);
1507 if (node->nsDef != NULL)
1508 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
1509
1510 if (node->ns != NULL) {
1511 xmlNsPtr ns;
1512
1513 ns = xmlSearchNs(doc, ret, node->ns->prefix);
1514 if (ns == NULL) {
1515 /*
1516 * Humm, we are copying an element whose namespace is defined
1517 * out of the new tree scope. Search it in the original tree
1518 * and add it at the top of the new tree
1519 */
1520 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
1521 if (ns != NULL) {
1522 xmlNodePtr root = ret;
1523
1524 while (root->parent != NULL) root = root->parent;
1525 xmlNewNs(root, ns->href, ns->prefix);
1526 }
1527 } else {
1528 /*
1529 * reference the existing namespace definition in our own tree.
1530 */
1531 ret->ns = ns;
1532 }
1533 }
1534 if (node->childs != NULL)
1535 ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001536 UPDATE_LAST_CHILD(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001537 return(ret);
1538}
1539
1540static xmlNodePtr
1541xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
1542 xmlNodePtr ret = NULL;
1543 xmlNodePtr p = NULL,q;
1544
1545 while (node != NULL) {
1546 q = xmlStaticCopyNode(node, doc, parent, 1);
1547 if (parent == NULL) {
1548 if (ret == NULL) ret = q;
1549 } else {
1550 if (ret == NULL) {
1551 q->prev = NULL;
1552 ret = p = q;
1553 } else {
1554 p->next = q;
1555 q->prev = p;
1556 p = q;
1557 }
1558 }
1559 node = node->next;
1560 }
1561 return(ret);
1562}
1563
1564/**
1565 * xmlCopyNode:
1566 * @node: the node
1567 * @recursive: if 1 do a recursive copy.
1568 *
1569 * Do a copy of the node.
1570 *
1571 * Returns: a new xmlNodePtr, or NULL in case of error.
1572 */
1573xmlNodePtr
1574xmlCopyNode(xmlNodePtr node, int recursive) {
1575 xmlNodePtr ret;
1576
1577 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
1578 return(ret);
1579}
1580
1581/**
1582 * xmlCopyNodeList:
1583 * @node: the first node in the list.
1584 *
1585 * Do a recursive copy of the node list.
1586 *
1587 * Returns: a new xmlNodePtr, or NULL in case of error.
1588 */
1589xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
1590 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
1591 return(ret);
1592}
1593
1594/**
1595 * xmlCopyElement:
1596 * @elem: the element
1597 *
1598 * Do a copy of the element definition.
1599 *
1600 * Returns: a new xmlElementPtr, or NULL in case of error.
1601xmlElementPtr
1602xmlCopyElement(xmlElementPtr elem) {
1603 xmlElementPtr ret;
1604
1605 if (elem == NULL) return(NULL);
1606 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
1607 if (ret == NULL) return(NULL);
1608 if (!recursive) return(ret);
1609 if (elem->properties != NULL)
1610 ret->properties = xmlCopyPropList(elem->properties);
1611
1612 if (elem->nsDef != NULL)
1613 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
1614 if (elem->childs != NULL)
1615 ret->childs = xmlCopyElementList(elem->childs);
1616 return(ret);
1617}
1618 */
1619
1620/**
1621 * xmlCopyDtd:
1622 * @dtd: the dtd
1623 *
1624 * Do a copy of the dtd.
1625 *
1626 * Returns: a new xmlDtdPtr, or NULL in case of error.
1627 */
1628xmlDtdPtr
1629xmlCopyDtd(xmlDtdPtr dtd) {
1630 xmlDtdPtr ret;
1631
1632 if (dtd == NULL) return(NULL);
1633 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
1634 if (ret == NULL) return(NULL);
1635 if (dtd->entities != NULL)
1636 ret->entities = (void *) xmlCopyEntitiesTable(
1637 (xmlEntitiesTablePtr) dtd->entities);
1638 /*
1639 * TODO: support for Element definitions.
1640 */
1641 return(ret);
1642}
1643
1644/**
1645 * xmlCopyDoc:
1646 * @doc: the document
1647 * @recursive: if 1 do a recursive copy.
1648 *
1649 * Do a copy of the document info. If recursive, the content tree will
1650 * be copied too as well as Dtd, namespaces and entities.
1651 *
1652 * Returns: a new xmlDocPtr, or NULL in case of error.
1653 */
1654xmlDocPtr
1655xmlCopyDoc(xmlDocPtr doc, int recursive) {
1656 xmlDocPtr ret;
1657
1658 if (doc == NULL) return(NULL);
1659 ret = xmlNewDoc(doc->version);
1660 if (ret == NULL) return(NULL);
1661 if (doc->name != NULL)
1662 ret->name = strdup(doc->name);
1663 if (doc->encoding != NULL)
1664 ret->encoding = xmlStrdup(doc->encoding);
1665 ret->compression = doc->compression;
1666 ret->standalone = doc->standalone;
1667 if (!recursive) return(ret);
1668
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001669 if (doc->intSubset != NULL)
1670 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001671 if (doc->oldNs != NULL)
1672 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
1673 if (doc->root != NULL)
1674 ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL);
1675 return(ret);
1676}
1677
1678/************************************************************************
1679 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001680 * Content access functions *
1681 * *
1682 ************************************************************************/
1683
Daniel Veillard97b58771998-10-20 06:14:16 +00001684/**
Daniel Veillard16253641998-10-28 22:58:05 +00001685 * xmlNodeGetContent:
1686 * @cur: the node being read
1687 *
1688 * Read the value of a node, this can be either the text carried
1689 * directly by this node if it's a TEXT node or the aggregate string
1690 * of the values carried by this node child's (TEXT and ENTITY_REF).
1691 * Entity references are substitued.
1692 * Return value: a new CHAR * or NULL if no content is available.
1693 */
1694CHAR *
1695xmlNodeGetContent(xmlNodePtr cur) {
1696 if (cur == NULL) return(NULL);
1697 switch (cur->type) {
1698 case XML_DOCUMENT_FRAG_NODE:
1699 case XML_ELEMENT_NODE:
1700 return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1701 break;
1702 case XML_ATTRIBUTE_NODE:
1703 case XML_CDATA_SECTION_NODE:
1704 case XML_ENTITY_REF_NODE:
1705 case XML_ENTITY_NODE:
1706 case XML_PI_NODE:
1707 case XML_COMMENT_NODE:
1708 case XML_DOCUMENT_NODE:
1709 case XML_DOCUMENT_TYPE_NODE:
1710 case XML_NOTATION_NODE:
1711 return(NULL);
1712 case XML_TEXT_NODE:
1713 if (cur->content != NULL)
1714 return(xmlStrdup(cur->content));
1715 return(NULL);
1716 }
1717 return(NULL);
1718}
1719
1720/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001721 * xmlNodeSetContent:
1722 * @cur: the node being modified
1723 * @content: the new value of the content
1724 *
1725 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001726 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001727void
1728xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001729 if (cur == NULL) {
1730 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1731 return;
1732 }
Daniel Veillard16253641998-10-28 22:58:05 +00001733 switch (cur->type) {
1734 case XML_DOCUMENT_FRAG_NODE:
1735 case XML_ELEMENT_NODE:
1736 if (cur->content != NULL) {
1737 free(cur->content);
1738 cur->content = NULL;
1739 }
1740 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1741 cur->childs = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001742 UPDATE_LAST_CHILD(cur);
Daniel Veillard16253641998-10-28 22:58:05 +00001743 break;
1744 case XML_ATTRIBUTE_NODE:
1745 break;
1746 case XML_TEXT_NODE:
1747 case XML_CDATA_SECTION_NODE:
1748 case XML_ENTITY_REF_NODE:
1749 case XML_ENTITY_NODE:
1750 case XML_PI_NODE:
1751 case XML_COMMENT_NODE:
1752 if (cur->content != NULL) free(cur->content);
1753 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001754 cur->last = cur->childs = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001755 if (content != NULL)
1756 cur->content = xmlStrdup(content);
1757 else
1758 cur->content = NULL;
1759 case XML_DOCUMENT_NODE:
1760 case XML_DOCUMENT_TYPE_NODE:
1761 break;
1762 case XML_NOTATION_NODE:
1763 break;
1764 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001765}
1766
Daniel Veillard97b58771998-10-20 06:14:16 +00001767/**
1768 * xmlNodeSetContentLen:
1769 * @cur: the node being modified
1770 * @content: the new value of the content
1771 * @len: the size of @content
1772 *
1773 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001774 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001775void
1776xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001777 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001778 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001779 return;
1780 }
Daniel Veillard16253641998-10-28 22:58:05 +00001781 switch (cur->type) {
1782 case XML_DOCUMENT_FRAG_NODE:
1783 case XML_ELEMENT_NODE:
1784 if (cur->content != NULL) {
1785 free(cur->content);
1786 cur->content = NULL;
1787 }
1788 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1789 cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001790 UPDATE_LAST_CHILD(cur);
Daniel Veillard16253641998-10-28 22:58:05 +00001791 break;
1792 case XML_ATTRIBUTE_NODE:
1793 break;
1794 case XML_TEXT_NODE:
1795 case XML_CDATA_SECTION_NODE:
1796 case XML_ENTITY_REF_NODE:
1797 case XML_ENTITY_NODE:
1798 case XML_PI_NODE:
1799 case XML_COMMENT_NODE:
1800 if (cur->content != NULL) free(cur->content);
1801 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001802 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001803 if (content != NULL)
1804 cur->content = xmlStrndup(content, len);
1805 else
1806 cur->content = NULL;
1807 case XML_DOCUMENT_NODE:
1808 case XML_DOCUMENT_TYPE_NODE:
1809 break;
1810 case XML_NOTATION_NODE:
1811 if (cur->content != NULL) free(cur->content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001812 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1813 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001814 if (content != NULL)
1815 cur->content = xmlStrndup(content, len);
1816 else
1817 cur->content = NULL;
1818 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001819 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001820}
1821
Daniel Veillard97b58771998-10-20 06:14:16 +00001822/**
1823 * xmlNodeAddContentLen:
1824 * @cur: the node being modified
1825 * @content: extra content
1826 * @len: the size of @content
1827 *
1828 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001829 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001830void
1831xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001832 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001833 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1834 return;
1835 }
1836 if (len <= 0) return;
1837 switch (cur->type) {
1838 case XML_DOCUMENT_FRAG_NODE:
1839 case XML_ELEMENT_NODE: {
1840 xmlNodePtr last = NULL, new;
1841
1842 if (cur->childs != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001843 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001844 } else {
1845 if (cur->content != NULL) {
1846 cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001847 UPDATE_LAST_CHILD(cur);
Daniel Veillard16253641998-10-28 22:58:05 +00001848 free(cur->content);
1849 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001850 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001851 }
1852 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001853 new = xmlNewTextLen(content, len);
Daniel Veillard16253641998-10-28 22:58:05 +00001854 if (new != NULL) {
1855 xmlAddChild(cur, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001856 if ((last != NULL) && (last->next == new)) {
Daniel Veillard16253641998-10-28 22:58:05 +00001857 xmlTextMerge(last, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001858 }
Daniel Veillard16253641998-10-28 22:58:05 +00001859 }
1860 break;
1861 }
1862 case XML_ATTRIBUTE_NODE:
1863 break;
1864 case XML_TEXT_NODE:
1865 case XML_CDATA_SECTION_NODE:
1866 case XML_ENTITY_REF_NODE:
1867 case XML_ENTITY_NODE:
1868 case XML_PI_NODE:
1869 case XML_COMMENT_NODE:
1870 if (content != NULL)
1871 cur->content = xmlStrncat(cur->content, content, len);
1872 case XML_DOCUMENT_NODE:
1873 case XML_DOCUMENT_TYPE_NODE:
1874 break;
1875 case XML_NOTATION_NODE:
1876 if (content != NULL)
1877 cur->content = xmlStrncat(cur->content, content, len);
1878 break;
1879 }
1880}
1881
1882/**
1883 * xmlNodeAddContent:
1884 * @cur: the node being modified
1885 * @content: extra content
1886 *
1887 * Append the extra substring to the node content.
1888 */
1889void
1890xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1891 int len;
1892
1893 if (cur == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001894 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1895 return;
1896 }
Daniel Veillard16253641998-10-28 22:58:05 +00001897 if (content == NULL) return;
1898 len = xmlStrlen(content);
1899 xmlNodeAddContentLen(cur, content, len);
1900}
1901
1902/**
1903 * xmlTextMerge:
1904 * @first: the first text node
1905 * @second: the second text node being merged
1906 *
1907 * Merge two text nodes into one
1908 * Return values: the first text node augmented
1909 */
1910xmlNodePtr
1911xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1912 if (first == NULL) return(second);
1913 if (second == NULL) return(first);
1914 if (first->type != XML_TEXT_NODE) return(first);
1915 if (second->type != XML_TEXT_NODE) return(first);
1916 xmlNodeAddContent(first, second->content);
1917 xmlUnlinkNode(second);
1918 xmlFreeNode(second);
1919 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001920}
1921
Daniel Veillard97b58771998-10-20 06:14:16 +00001922/**
1923 * xmlSearchNs:
1924 * @doc: the document
1925 * @node: the current node
1926 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00001927 *
Daniel Veillard97b58771998-10-20 06:14:16 +00001928 * Search a Ns registered under a given name space for a document.
1929 * recurse on the parents until it finds the defined namespace
1930 * or return NULL otherwise.
1931 * @nameSpace can be NULL, this is a search for the default namespace.
1932 * return values: the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001933 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001934xmlNsPtr
1935xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001936 xmlNsPtr cur;
1937
1938 while (node != NULL) {
1939 cur = node->nsDef;
1940 while (cur != NULL) {
1941 if ((cur->prefix == NULL) && (nameSpace == NULL))
1942 return(cur);
1943 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1944 (!xmlStrcmp(cur->prefix, nameSpace)))
1945 return(cur);
1946 cur = cur->next;
1947 }
1948 node = node->parent;
1949 }
1950 if (doc != NULL) {
1951 cur = doc->oldNs;
1952 while (cur != NULL) {
1953 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1954 (!xmlStrcmp(cur->prefix, nameSpace)))
1955 return(cur);
1956 cur = cur->next;
1957 }
1958 }
1959 return(NULL);
1960}
1961
Daniel Veillard97b58771998-10-20 06:14:16 +00001962/**
1963 * xmlSearchNsByHref:
1964 * @doc: the document
1965 * @node: the current node
1966 * @href: the namespace value
1967 *
1968 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1969 * the defined namespace or return NULL otherwise.
1970 * return values: the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001971 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001972xmlNsPtr
1973xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001974 xmlNsPtr cur;
1975
1976 while (node != NULL) {
1977 cur = node->nsDef;
1978 while (cur != NULL) {
1979 if ((cur->href != NULL) && (href != NULL) &&
1980 (!xmlStrcmp(cur->href, href)))
1981 return(cur);
1982 cur = cur->next;
1983 }
1984 node = node->parent;
1985 }
1986 if (doc != NULL) {
1987 cur = doc->oldNs;
1988 while (cur != NULL) {
1989 if ((cur->href != NULL) && (href != NULL) &&
1990 (!xmlStrcmp(cur->href, href)))
1991 return(cur);
1992 cur = cur->next;
1993 }
1994 }
1995 return(NULL);
1996}
1997
Daniel Veillard97b58771998-10-20 06:14:16 +00001998/**
1999 * xmlGetProp:
2000 * @node: the node
2001 * @name: the attribute name
2002 *
2003 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00002004 * This does the entity substitution.
Daniel Veillard97b58771998-10-20 06:14:16 +00002005 * return values: the attribute value or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002006 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002007CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002008 xmlAttrPtr prop = node->properties;
2009
2010 while (prop != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002011 if (!xmlStrcmp(prop->name, name))
2012 return(xmlNodeListGetString(node->doc, prop->val, 1));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002013 prop = prop->next;
2014 }
2015 return(NULL);
2016}
2017
Daniel Veillard97b58771998-10-20 06:14:16 +00002018/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002019 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00002020 * @node: the node
2021 * @name: the attribute name
2022 * @value: the attribute value
2023 *
2024 * Set (or reset) an attribute carried by a node.
2025 * return values: the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002026 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002027xmlAttrPtr
2028xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002029 xmlAttrPtr prop = node->properties;
2030
2031 while (prop != NULL) {
2032 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002033 if (prop->val != NULL)
2034 xmlFreeNode(prop->val);
2035 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002036 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00002037 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002038 return(prop);
2039 }
2040 prop = prop->next;
2041 }
2042 prop = xmlNewProp(node, name, value);
2043 return(prop);
2044}
2045
Daniel Veillard97b58771998-10-20 06:14:16 +00002046/**
2047 * xmlNodeIsText:
2048 * @node: the node
2049 *
2050 * Is this node a Text node ?
2051 * return values: 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00002052 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002053int
2054xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002055 if (node == NULL) return(0);
2056
Daniel Veillard0bef1311998-10-14 02:36:47 +00002057 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002058 return(0);
2059}
2060
Daniel Veillard97b58771998-10-20 06:14:16 +00002061/**
2062 * xmlNodeIsText:
2063 * @node: the node
2064 * @content: the content
2065 * @len: @content lenght
2066 *
2067 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00002068 */
Daniel Veillard97b58771998-10-20 06:14:16 +00002069
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002070void
2071xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002072 if (node == NULL) return;
2073
Daniel Veillard0bef1311998-10-14 02:36:47 +00002074 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002075 fprintf(stderr, "xmlTextConcat: node is not text\n");
2076 return;
2077 }
2078 node->content = xmlStrncat(node->content, content, len);
2079}
2080
2081/************************************************************************
2082 * *
2083 * Output : to a FILE or in memory *
2084 * *
2085 ************************************************************************/
2086
Daniel Veillard260a68f1998-08-13 03:39:55 +00002087static CHAR *buffer = NULL;
2088static int buffer_index = 0;
2089static int buffer_size = 0;
2090
Daniel Veillard97b58771998-10-20 06:14:16 +00002091/**
2092 * xmlBufferWriteCHAR:
2093 * @string: the string to add
2094 *
2095 * routine which manage and grows an output buffer. This one add
2096 * CHARs at the end of the array.
2097 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002098void
2099xmlBufferWriteCHAR(const CHAR *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002100 const CHAR *cur;
2101
2102 if (buffer == NULL) {
2103 buffer_size = 50000;
2104 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2105 if (buffer == NULL) {
2106 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2107 exit(1);
2108 }
2109 }
2110
2111 if (string == NULL) return;
2112 for (cur = string;*cur != 0;cur++) {
2113 if (buffer_index + 10 >= buffer_size) {
2114 buffer_size *= 2;
2115 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2116 if (buffer == NULL) {
2117 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2118 exit(1);
2119 }
2120 }
2121 buffer[buffer_index++] = *cur;
2122 }
2123 buffer[buffer_index] = 0;
2124}
2125
Daniel Veillard97b58771998-10-20 06:14:16 +00002126/**
2127 * xmlBufferWriteChar:
2128 * @string: the string to add
2129 *
2130 * routine which manage and grows an output buffer. This one add
2131 * C chars at the end of the array.
2132 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002133void
2134xmlBufferWriteChar(const char *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002135 const char *cur;
2136
2137 if (buffer == NULL) {
2138 buffer_size = 50000;
2139 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2140 if (buffer == NULL) {
2141 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2142 exit(1);
2143 }
2144 }
2145
2146 if (string == NULL) return;
2147 for (cur = string;*cur != 0;cur++) {
2148 if (buffer_index + 10 >= buffer_size) {
2149 buffer_size *= 2;
2150 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2151 if (buffer == NULL) {
2152 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2153 exit(1);
2154 }
2155 }
2156 buffer[buffer_index++] = *cur;
2157 }
2158 buffer[buffer_index] = 0;
2159}
2160
Daniel Veillard97b58771998-10-20 06:14:16 +00002161/**
2162 * xmlGlobalNsDump:
2163 * @cur: a namespace
2164 *
2165 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002166 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002167static void
2168xmlGlobalNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002169 if (cur == NULL) {
2170 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
2171 return;
2172 }
2173 if (cur->type == XML_GLOBAL_NAMESPACE) {
2174 xmlBufferWriteChar("<?namespace");
2175 if (cur->href != NULL) {
2176 xmlBufferWriteChar(" href=\"");
2177 xmlBufferWriteCHAR(cur->href);
2178 xmlBufferWriteChar("\"");
2179 }
2180 if (cur->prefix != NULL) {
2181 xmlBufferWriteChar(" AS=\"");
2182 xmlBufferWriteCHAR(cur->prefix);
2183 xmlBufferWriteChar("\"");
2184 }
2185 xmlBufferWriteChar("?>\n");
2186 }
2187}
2188
Daniel Veillard97b58771998-10-20 06:14:16 +00002189/**
2190 * xmlGlobalNsListDump:
2191 * @cur: the first namespace
2192 *
2193 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002194 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002195static void
2196xmlGlobalNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002197 while (cur != NULL) {
2198 xmlGlobalNsDump(cur);
2199 cur = cur->next;
2200 }
2201}
2202
Daniel Veillard97b58771998-10-20 06:14:16 +00002203/**
2204 * xmlNsDump:
2205 * @cur: a namespace
2206 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002207 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00002208 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002209 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002210static void
2211xmlNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002212 if (cur == NULL) {
2213 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
2214 return;
2215 }
2216 if (cur->type == XML_LOCAL_NAMESPACE) {
2217 /* Within the context of an element attributes */
2218 if (cur->prefix != NULL) {
2219 xmlBufferWriteChar(" xmlns:");
2220 xmlBufferWriteCHAR(cur->prefix);
2221 } else
2222 xmlBufferWriteChar(" xmlns");
2223 xmlBufferWriteChar("=\"");
2224 xmlBufferWriteCHAR(cur->href);
2225 xmlBufferWriteChar("\"");
2226 }
2227}
2228
Daniel Veillard97b58771998-10-20 06:14:16 +00002229/**
2230 * xmlNsListDump:
2231 * @cur: the first namespace
2232 *
2233 * Dump a list of local Namespace definitions.
2234 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002235 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002236static void
2237xmlNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002238 while (cur != NULL) {
2239 xmlNsDump(cur);
2240 cur = cur->next;
2241 }
2242}
2243
Daniel Veillard97b58771998-10-20 06:14:16 +00002244/**
2245 * xmlDtdDump:
2246 * @doc: the document
2247 *
2248 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002249 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002250static void
2251xmlDtdDump(xmlDocPtr doc) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002252 xmlDtdPtr cur = doc->intSubset;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002253
2254 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002255 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002256 return;
2257 }
2258 xmlBufferWriteChar("<!DOCTYPE ");
2259 xmlBufferWriteCHAR(cur->name);
2260 if (cur->ExternalID != NULL) {
2261 xmlBufferWriteChar(" PUBLIC \"");
2262 xmlBufferWriteCHAR(cur->ExternalID);
2263 xmlBufferWriteChar("\" \"");
2264 xmlBufferWriteCHAR(cur->SystemID);
2265 xmlBufferWriteChar("\"");
2266 } else if (cur->SystemID != NULL) {
2267 xmlBufferWriteChar(" SYSTEM \"");
2268 xmlBufferWriteCHAR(cur->SystemID);
2269 xmlBufferWriteChar("\"");
2270 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002271 if (cur->entities == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002272 xmlBufferWriteChar(">\n");
2273 return;
2274 }
2275 xmlBufferWriteChar(" [\n");
2276 if (cur->entities != NULL)
2277 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002278 xmlBufferWriteChar("]");
2279
2280 /* TODO !!! a lot more things to dump ... */
2281 xmlBufferWriteChar(">\n");
2282}
2283
Daniel Veillard97b58771998-10-20 06:14:16 +00002284/**
2285 * xmlAttrDump:
2286 * @doc: the document
2287 * @cur: the attribute pointer
2288 *
2289 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00002290 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002291static void
2292xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002293 CHAR *value;
2294
Daniel Veillard260a68f1998-08-13 03:39:55 +00002295 if (cur == NULL) {
2296 fprintf(stderr, "xmlAttrDump : property == NULL\n");
2297 return;
2298 }
2299 xmlBufferWriteChar(" ");
2300 xmlBufferWriteCHAR(cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002301 value = xmlNodeListGetString(doc, cur->val, 0);
2302 if (value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002303 xmlBufferWriteChar("=\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00002304 xmlBufferWriteCHAR(value);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002305 xmlBufferWriteChar("\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00002306 free(value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002307 }
2308}
2309
Daniel Veillard97b58771998-10-20 06:14:16 +00002310/**
2311 * xmlAttrListDump:
2312 * @doc: the document
2313 * @cur: the first attribute pointer
2314 *
2315 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00002316 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002317static void
2318xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002319 if (cur == NULL) {
2320 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
2321 return;
2322 }
2323 while (cur != NULL) {
2324 xmlAttrDump(doc, cur);
2325 cur = cur->next;
2326 }
2327}
2328
Daniel Veillard260a68f1998-08-13 03:39:55 +00002329
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002330static void
2331xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00002332/**
2333 * xmlNodeListDump:
2334 * @doc: the document
2335 * @cur: the first node
2336 * @level: the imbrication level for indenting
2337 *
2338 * Dump an XML node list, recursive behaviour,children are printed too.
2339 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002340static void
2341xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002342 int needIndent = 0, i;
2343
Daniel Veillard260a68f1998-08-13 03:39:55 +00002344 if (cur == NULL) {
2345 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
2346 return;
2347 }
2348 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002349 if ((cur->type != XML_TEXT_NODE) &&
2350 (cur->type != XML_ENTITY_REF_NODE)) {
2351 if (!needIndent) {
2352 needIndent = 1;
2353 xmlBufferWriteChar("\n");
2354 }
2355 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002356 xmlNodeDump(doc, cur, level);
2357 cur = cur->next;
2358 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002359 if ((xmlIndentTreeOutput) && (needIndent))
2360 for (i = 1;i < level;i++)
2361 xmlBufferWriteChar(" ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002362}
2363
Daniel Veillard97b58771998-10-20 06:14:16 +00002364/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002365 * xmlNodeDump:
Daniel Veillard97b58771998-10-20 06:14:16 +00002366 * @doc: the document
2367 * @cur: the current node
2368 * @level: the imbrication level for indenting
2369 *
2370 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002371 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002372static void
2373xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002374 int i;
2375
2376 if (cur == NULL) {
2377 fprintf(stderr, "xmlNodeDump : node == NULL\n");
2378 return;
2379 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002380 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002381 if (cur->content != NULL)
2382 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2383 return;
2384 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002385 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002386 if (cur->content != NULL) {
2387 xmlBufferWriteChar("<!--");
2388 xmlBufferWriteCHAR(cur->content);
2389 xmlBufferWriteChar("-->");
2390 }
2391 return;
2392 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002393 if (cur->type == XML_ENTITY_REF_NODE) {
2394 xmlBufferWriteChar("&");
2395 xmlBufferWriteCHAR(cur->name);
2396 xmlBufferWriteChar(";");
2397 return;
2398 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002399 if (xmlIndentTreeOutput)
2400 for (i = 0;i < level;i++)
2401 xmlBufferWriteChar(" ");
2402
2403 xmlBufferWriteChar("<");
2404 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2405 xmlBufferWriteCHAR(cur->ns->prefix);
2406 xmlBufferWriteChar(":");
2407 }
2408
2409 xmlBufferWriteCHAR(cur->name);
2410 if (cur->nsDef)
2411 xmlNsListDump(cur->nsDef);
2412 if (cur->properties != NULL)
2413 xmlAttrListDump(doc, cur->properties);
2414
2415 if ((cur->content == NULL) && (cur->childs == NULL)) {
2416 xmlBufferWriteChar("/>\n");
2417 return;
2418 }
2419 xmlBufferWriteChar(">");
2420 if (cur->content != NULL)
2421 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2422 if (cur->childs != NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002423 xmlNodeListDump(doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002424 }
2425 xmlBufferWriteChar("</");
2426 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2427 xmlBufferWriteCHAR(cur->ns->prefix);
2428 xmlBufferWriteChar(":");
2429 }
2430
2431 xmlBufferWriteCHAR(cur->name);
2432 xmlBufferWriteChar(">\n");
2433}
2434
Daniel Veillard97b58771998-10-20 06:14:16 +00002435/**
2436 * xmlDocContentDump:
2437 * @cur: the document
2438 *
2439 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002440 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002441static void
2442xmlDocContentDump(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002443 if (oldXMLWDcompatibility)
2444 xmlBufferWriteChar("<?XML version=\"");
2445 else
2446 xmlBufferWriteChar("<?xml version=\"");
2447 xmlBufferWriteCHAR(cur->version);
2448 xmlBufferWriteChar("\"");
2449 if (cur->encoding != NULL) {
2450 xmlBufferWriteChar(" encoding=\"");
2451 xmlBufferWriteCHAR(cur->encoding);
2452 xmlBufferWriteChar("\"");
2453 }
2454 switch (cur->standalone) {
2455 case 0:
2456 xmlBufferWriteChar(" standalone=\"no\"");
2457 break;
2458 case 1:
2459 xmlBufferWriteChar(" standalone=\"yes\"");
2460 break;
2461 }
2462 xmlBufferWriteChar("?>\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002463 if (cur->intSubset != NULL)
Daniel Veillard260a68f1998-08-13 03:39:55 +00002464 xmlDtdDump(cur);
2465 if (cur->root != NULL) {
2466 /* global namespace definitions, the old way */
2467 if (oldXMLWDcompatibility)
2468 xmlGlobalNsListDump(cur->oldNs);
2469 else
2470 xmlUpgradeOldNs(cur);
2471 xmlNodeDump(cur, cur->root, 0);
2472 }
2473}
2474
Daniel Veillard97b58771998-10-20 06:14:16 +00002475/**
2476 * xmlDocDumpMemory:
2477 * @cur: the document
2478 * @mem: OUT: the memory pointer
2479 * @size: OUT: the memory lenght
2480 *
2481 * Dump an XML document in memory and return the CHAR * and it's size.
2482 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002483 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002484void
2485xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002486 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002487#ifdef DEBUG_TREE
2488 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
2489#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002490 *mem = NULL;
2491 *size = 0;
2492 return;
2493 }
2494 buffer_index = 0;
2495 xmlDocContentDump(cur);
2496
2497 *mem = buffer;
2498 *size = buffer_index;
2499}
2500
Daniel Veillard97b58771998-10-20 06:14:16 +00002501/**
2502 * xmlGetDocCompressMode:
2503 * @doc: the document
2504 *
2505 * get the compression ratio for a document, ZLIB based
2506 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002507 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002508int
2509 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002510 if (doc == NULL) return(-1);
2511 return(doc->compression);
2512}
2513
Daniel Veillard97b58771998-10-20 06:14:16 +00002514/**
2515 * xmlSetDocCompressMode:
2516 * @doc: the document
2517 * @mode: the compression ratio
2518 *
2519 * set the compression ratio for a document, ZLIB based
2520 * Correct values: 0 (uncompressed) to 9 (max compression)
2521 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002522void
2523xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002524 if (doc == NULL) return;
2525 if (mode < 0) doc->compression = 0;
2526 else if (mode > 9) doc->compression = 9;
2527 else doc->compression = mode;
2528}
2529
Daniel Veillard97b58771998-10-20 06:14:16 +00002530/**
2531 * xmlGetCompressMode:
2532 *
2533 * get the default compression mode used, ZLIB based.
2534 * return values: 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002535 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002536int
2537 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002538 return(xmlCompressMode);
2539}
Daniel Veillard97b58771998-10-20 06:14:16 +00002540
2541/**
2542 * xmlSetCompressMode:
2543 * @mode: the compression ratio
2544 *
2545 * set the default compression mode used, ZLIB based
2546 * Correct values: 0 (uncompressed) to 9 (max compression)
2547 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002548void
2549xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002550 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002551 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002552 else xmlCompressMode = mode;
2553}
2554
Daniel Veillard97b58771998-10-20 06:14:16 +00002555/**
2556 * xmlDocDump:
2557 * @f: the FILE*
2558 * @cur: the document
2559 *
2560 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002561 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002562void
2563xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002564 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002565#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002566 fprintf(stderr, "xmlDocDump : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002567#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002568 return;
2569 }
2570 buffer_index = 0;
2571 xmlDocContentDump(cur);
2572
2573 fwrite(buffer, sizeof(CHAR), buffer_index, f);
2574}
2575
Daniel Veillard97b58771998-10-20 06:14:16 +00002576/**
2577 * xmlSaveFile:
2578 * @filename: the filename
2579 * @cur: the document
2580 *
2581 * Dump an XML document to a file. Will use compression if
2582 * compiled in and enabled.
2583 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002584 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002585int
2586xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002587#ifdef HAVE_ZLIB_H
2588 gzFile zoutput = NULL;
2589 char mode[15];
2590#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002591 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002592 int ret;
2593
2594#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002595 if ((cur->compression > 0) && (cur->compression <= 9)) {
2596 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002597 zoutput = gzopen(filename, mode);
2598 }
2599 if (zoutput == NULL) {
2600#endif
2601 output = fopen(filename, "w");
2602 if (output == NULL) return(-1);
2603#ifdef HAVE_ZLIB_H
2604 }
2605#endif
2606
2607 /*
2608 * save the content to a temp buffer.
2609 */
2610 buffer_index = 0;
2611 xmlDocContentDump(cur);
2612
2613#ifdef HAVE_ZLIB_H
2614 if (zoutput != NULL) {
2615 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
2616 gzclose(zoutput);
2617 return(ret);
2618 }
2619#endif
2620 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
2621 fclose(output);
2622 return(ret * sizeof(CHAR));
2623}
2624