blob: 617264cd7a19481a68a63bf42c935c244e8aaed5 [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; \
Daniel Veillard1e346af1999-02-22 10:33:01 +000038}}
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000039
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 Veillard1e346af1999-02-22 10:33:01 +000080 * Returns 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.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000135 * Returns 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 Veillard1e346af1999-02-22 10:33:01 +0000240 * Returns 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;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000274 cur->notations = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000275 cur->elements = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000276 cur->attributes = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000277 cur->entities = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000278 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000279 doc->extSubset = cur;
280
281 return(cur);
282}
283
284/**
285 * xmlCreateIntSubset:
286 * @doc: the document pointer
287 * @name: the DTD name
288 * @ExternalID: the external ID
289 * @SystemID: the system ID
290 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000291 * Create the internal subset of a document
292 * Returns a pointer to the new DTD structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000293 */
294xmlDtdPtr
295xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
296 const CHAR *ExternalID, const CHAR *SystemID) {
297 xmlDtdPtr cur;
298
299 if ((doc != NULL) && (doc->intSubset != NULL)) {
300 fprintf(stderr,
301 "xmlCreateIntSubset(): document %s already have an internal subset\n",
302 doc->name);
303 return(NULL);
304 }
305
306 /*
307 * Allocate a new DTD and fill the fields.
308 */
309 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
310 if (cur == NULL) {
311 fprintf(stderr, "xmlNewDtd : malloc failed\n");
312 return(NULL);
313 }
314
315 if (name != NULL)
316 cur->name = xmlStrdup(name);
317 else
318 cur->name = NULL;
319 if (ExternalID != NULL)
320 cur->ExternalID = xmlStrdup(ExternalID);
321 else
322 cur->ExternalID = NULL;
323 if (SystemID != NULL)
324 cur->SystemID = xmlStrdup(SystemID);
325 else
326 cur->SystemID = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000327 cur->notations = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000328 cur->elements = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000329 cur->attributes = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000330 cur->entities = NULL;
331 if (doc != NULL)
332 doc->intSubset = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000333
334 return(cur);
335}
336
Daniel Veillard97b58771998-10-20 06:14:16 +0000337/**
338 * xmlFreeDtd:
339 * @cur: the DTD structure to free up
340 *
341 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000342 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000343void
344xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000345 if (cur == NULL) {
346 fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
347 return;
348 }
349 if (cur->name != NULL) free((char *) cur->name);
350 if (cur->SystemID != NULL) free((char *) cur->SystemID);
351 if (cur->ExternalID != NULL) free((char *) cur->ExternalID);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000352 if (cur->notations != NULL)
353 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000354 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000355 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000356 if (cur->attributes != NULL)
357 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000358 if (cur->entities != NULL)
359 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
360 memset(cur, -1, sizeof(xmlDtd));
361 free(cur);
362}
363
Daniel Veillard97b58771998-10-20 06:14:16 +0000364/**
365 * xmlNewDoc:
366 * @version: CHAR string giving the version of XML "1.0"
367 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000368 * Returns a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000369 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000370xmlDocPtr
371xmlNewDoc(const CHAR *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000372 xmlDocPtr cur;
373
374 if (version == NULL) {
375 fprintf(stderr, "xmlNewDoc : version == NULL\n");
376 return(NULL);
377 }
378
379 /*
380 * Allocate a new document and fill the fields.
381 */
382 cur = (xmlDocPtr) malloc(sizeof(xmlDoc));
383 if (cur == NULL) {
384 fprintf(stderr, "xmlNewDoc : malloc failed\n");
385 return(NULL);
386 }
387
Daniel Veillard33942841998-10-18 19:12:41 +0000388 cur->type = XML_DOCUMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000389 cur->version = xmlStrdup(version);
390 cur->name = NULL;
391 cur->root = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000392 cur->intSubset = NULL;
393 cur->extSubset = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000394 cur->oldNs = NULL;
395 cur->encoding = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000396 cur->standalone = -1;
Daniel Veillard15a8df41998-09-24 19:15:06 +0000397 cur->compression = xmlCompressMode;
Daniel Veillard27d88741999-05-29 11:51:49 +0000398#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000399 cur->_private = NULL;
400 cur->vepv = NULL;
401#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000402 return(cur);
403}
404
Daniel Veillard97b58771998-10-20 06:14:16 +0000405/**
406 * xmlFreeDoc:
407 * @cur: pointer to the document
408 * @:
409 *
410 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000411 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000412void
413xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000414 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000415#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000416 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000417#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000418 return;
419 }
420 free((char *) cur->version);
421 if (cur->name != NULL) free((char *) cur->name);
422 if (cur->encoding != NULL) free((char *) cur->encoding);
423 if (cur->root != NULL) xmlFreeNode(cur->root);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000424 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
425 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000426 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000427 memset(cur, -1, sizeof(xmlDoc));
428 free(cur);
429}
430
Daniel Veillard97b58771998-10-20 06:14:16 +0000431/**
Daniel Veillard16253641998-10-28 22:58:05 +0000432 * xmlStringLenGetNodeList:
433 * @doc: the document
434 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000435 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000436 *
437 * Parse the value string and build the node list associated. Should
438 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000439 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000440 */
441xmlNodePtr
442xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
443 xmlNodePtr ret = NULL, last = NULL;
444 xmlNodePtr node;
445 CHAR *val;
446 const CHAR *cur = value;
447 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000448 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000449
450 if (value == NULL) return(NULL);
451
452 q = cur;
453 while ((*cur != 0) && (cur - value < len)) {
454 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000455 /*
456 * Save the current text.
457 */
Daniel Veillard16253641998-10-28 22:58:05 +0000458 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000459 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
460 xmlNodeAddContentLen(last, q, cur - q);
461 } else {
462 node = xmlNewDocTextLen(doc, q, cur - q);
463 if (node == NULL) return(ret);
464 if (last == NULL)
465 last = ret = node;
466 else {
467 last->next = node;
468 node->prev = last;
469 last = node;
470 }
Daniel Veillard16253641998-10-28 22:58:05 +0000471 }
472 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000473 /*
474 * Read the entity string
475 */
Daniel Veillard16253641998-10-28 22:58:05 +0000476 cur++;
477 q = cur;
478 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
479 if ((*cur == 0) || (cur - value >= len)) {
480 fprintf(stderr,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000481 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillard16253641998-10-28 22:58:05 +0000482 return(ret);
483 }
484 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000485 /*
486 * Predefined entities don't generate nodes
487 */
Daniel Veillard16253641998-10-28 22:58:05 +0000488 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000489 ent = xmlGetDocEntity(doc, val);
490 if ((ent != NULL) &&
491 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
492 if (last == NULL) {
493 node = xmlNewDocText(doc, ent->content);
494 last = ret = node;
495 } else
496 xmlNodeAddContent(last, ent->content);
497
498 } else {
499 /*
500 * Create a new REFERENCE_REF node
501 */
502 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000503 if (node == NULL) {
504 if (val != NULL) free(val);
505 return(ret);
506 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000507 if (last == NULL)
508 last = ret = node;
509 else {
510 last->next = node;
511 node->prev = last;
512 last = node;
513 }
Daniel Veillard16253641998-10-28 22:58:05 +0000514 }
515 free(val);
516 }
517 cur++;
518 q = cur;
519 } else
520 cur++;
521 }
522 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000523 /*
524 * Handle the last piece of text.
525 */
526 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
527 xmlNodeAddContentLen(last, q, cur - q);
528 } else {
529 node = xmlNewDocTextLen(doc, q, cur - q);
530 if (node == NULL) return(ret);
531 if (last == NULL)
532 last = ret = node;
533 else {
534 last->next = node;
535 node->prev = last;
536 last = node;
537 }
Daniel Veillard16253641998-10-28 22:58:05 +0000538 }
539 }
540 return(ret);
541}
542
543/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000544 * xmlStringGetNodeList:
545 * @doc: the document
546 * @value: the value of the attribute
547 *
548 * Parse the value string and build the node list associated. Should
549 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000550 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000551 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000552xmlNodePtr
553xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000554 xmlNodePtr ret = NULL, last = NULL;
555 xmlNodePtr node;
556 CHAR *val;
557 const CHAR *cur = value;
558 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000559 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000560
561 if (value == NULL) return(NULL);
562
563 q = cur;
564 while (*cur != 0) {
565 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000566 /*
567 * Save the current text.
568 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000569 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000570 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
571 xmlNodeAddContentLen(last, q, cur - q);
572 } else {
573 node = xmlNewDocTextLen(doc, q, cur - q);
574 if (node == NULL) return(ret);
575 if (last == NULL)
576 last = ret = node;
577 else {
578 last->next = node;
579 node->prev = last;
580 last = node;
581 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000582 }
583 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000584 /*
585 * Read the entity string
586 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000587 cur++;
588 q = cur;
589 while ((*cur != 0) && (*cur != ';')) cur++;
590 if (*cur == 0) {
591 fprintf(stderr,
592 "xmlStringGetNodeList: unterminated entity %30s\n", q);
593 return(ret);
594 }
595 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000596 /*
597 * Predefined entities don't generate nodes
598 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000599 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000600 ent = xmlGetDocEntity(doc, val);
601 if ((ent != NULL) &&
602 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
603 if (last == NULL) {
604 node = xmlNewDocText(doc, ent->content);
605 last = ret = node;
606 } else
607 xmlNodeAddContent(last, ent->content);
608
609 } else {
610 /*
611 * Create a new REFERENCE_REF node
612 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000613 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000614 if (node == NULL) {
615 if (val != NULL) free(val);
616 return(ret);
617 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000618 if (last == NULL)
619 last = ret = node;
620 else {
621 last->next = node;
622 node->prev = last;
623 last = node;
624 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000625 }
626 free(val);
627 }
628 cur++;
629 q = cur;
630 } else
631 cur++;
632 }
633 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000634 /*
635 * Handle the last piece of text.
636 */
637 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
638 xmlNodeAddContentLen(last, q, cur - q);
639 } else {
640 node = xmlNewDocTextLen(doc, q, cur - q);
641 if (node == NULL) return(ret);
642 if (last == NULL)
643 last = ret = node;
644 else {
645 last->next = node;
646 node->prev = last;
647 last = node;
648 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000649 }
650 }
651 return(ret);
652}
653
654/**
655 * xmlNodeListGetString:
656 * @doc: the document
657 * @list: a Node list
658 * @inLine: should we replace entity contents or show their external form
659 *
660 * Returns the string equivalent to the text contained in the Node list
661 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000662 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000663 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000664CHAR *
665xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000666 xmlNodePtr node = list;
667 CHAR *ret = NULL;
668 xmlEntityPtr ent;
669
670 if (list == NULL) return(NULL);
671
672 while (node != NULL) {
673 if (node->type == XML_TEXT_NODE) {
674 if (inLine)
675 ret = xmlStrcat(ret, node->content);
676 else
677 ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
678 } else if (node->type == XML_ENTITY_REF_NODE) {
679 if (inLine) {
680 ent = xmlGetDocEntity(doc, node->name);
681 if (ent != NULL)
682 ret = xmlStrcat(ret, ent->content);
683 else
684 ret = xmlStrcat(ret, node->content);
685 } else {
686 CHAR buf[2];
687 buf[0] = '&'; buf[1] = 0;
688 ret = xmlStrncat(ret, buf, 1);
689 ret = xmlStrcat(ret, node->name);
690 buf[0] = ';'; buf[1] = 0;
691 ret = xmlStrncat(ret, buf, 1);
692 }
693 }
694#if 0
695 else {
696 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
697 node->type);
698 }
699#endif
700 node = node->next;
701 }
702 return(ret);
703}
704
705/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000706 * xmlNewProp:
707 * @node: the holding node
708 * @name: the name of the attribute
709 * @value: the value of the attribute
710 *
711 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000712 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000713 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000714xmlAttrPtr
715xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000716 xmlAttrPtr cur;
717
718 if (name == NULL) {
719 fprintf(stderr, "xmlNewProp : name == NULL\n");
720 return(NULL);
721 }
722
723 /*
724 * Allocate a new property and fill the fields.
725 */
726 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
727 if (cur == NULL) {
728 fprintf(stderr, "xmlNewProp : malloc failed\n");
729 return(NULL);
730 }
731
Daniel Veillard33942841998-10-18 19:12:41 +0000732 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000733 cur->node = node;
734 cur->name = xmlStrdup(name);
735 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +0000736 cur->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000737 else
Daniel Veillardccb09631998-10-27 06:21:04 +0000738 cur->val = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000739#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000740 cur->_private = NULL;
741 cur->vepv = NULL;
742#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000743
744 /*
745 * Add it at the end to preserve parsing order ...
746 */
747 cur->next = NULL;
748 if (node != NULL) {
749 if (node->properties == NULL) {
750 node->properties = cur;
751 } else {
752 xmlAttrPtr prev = node->properties;
753
754 while (prev->next != NULL) prev = prev->next;
755 prev->next = cur;
756 }
757 }
758 return(cur);
759}
760
Daniel Veillard97b58771998-10-20 06:14:16 +0000761/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000762 * xmlNewDocProp:
763 * @doc: the document
764 * @name: the name of the attribute
765 * @value: the value of the attribute
766 *
767 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000768 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +0000769 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000770xmlAttrPtr
771xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000772 xmlAttrPtr cur;
773
774 if (name == NULL) {
775 fprintf(stderr, "xmlNewProp : name == NULL\n");
776 return(NULL);
777 }
778
779 /*
780 * Allocate a new property and fill the fields.
781 */
782 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
783 if (cur == NULL) {
784 fprintf(stderr, "xmlNewProp : malloc failed\n");
785 return(NULL);
786 }
787
788 cur->type = XML_ATTRIBUTE_NODE;
789 cur->node = NULL;
790 cur->name = xmlStrdup(name);
791 if (value != NULL)
792 cur->val = xmlStringGetNodeList(doc, value);
793 else
794 cur->val = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000795#ifndef XML_WITHOUT_CORBA
Daniel Veillardccb09631998-10-27 06:21:04 +0000796 cur->_private = NULL;
797 cur->vepv = NULL;
798#endif
799
800 cur->next = NULL;
801 return(cur);
802}
803
804/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000805 * xmlFreePropList:
806 * @cur: the first property in the list
807 *
808 * Free a property and all its siblings, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000809 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000810void
811xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000812 xmlAttrPtr next;
813 if (cur == NULL) {
814 fprintf(stderr, "xmlFreePropList : property == NULL\n");
815 return;
816 }
817 while (cur != NULL) {
818 next = cur->next;
819 xmlFreeProp(cur);
820 cur = next;
821 }
822}
823
Daniel Veillard97b58771998-10-20 06:14:16 +0000824/**
825 * xmlFreeProp:
826 * @cur: the first property in the list
827 *
828 * Free one property, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000829 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000830void
831xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000832 if (cur == NULL) {
833 fprintf(stderr, "xmlFreeProp : property == NULL\n");
834 return;
835 }
836 if (cur->name != NULL) free((char *) cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +0000837 if (cur->val != NULL) xmlFreeNodeList(cur->val);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000838 memset(cur, -1, sizeof(xmlAttr));
839 free(cur);
840}
841
Daniel Veillard97b58771998-10-20 06:14:16 +0000842/**
843 * xmlNewNode:
844 * @ns: namespace if any
845 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +0000846 *
847 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +0000848 * If content is non NULL, a child list containing the TEXTs and
849 * ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000850 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000851 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000852xmlNodePtr
853xmlNewNode(xmlNsPtr ns, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000854 xmlNodePtr cur;
855
856 if (name == NULL) {
857 fprintf(stderr, "xmlNewNode : name == NULL\n");
858 return(NULL);
859 }
860
861 /*
862 * Allocate a new node and fill the fields.
863 */
864 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
865 if (cur == NULL) {
866 fprintf(stderr, "xmlNewNode : malloc failed\n");
867 return(NULL);
868 }
869
Daniel Veillard33942841998-10-18 19:12:41 +0000870 cur->type = XML_ELEMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000871 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000872 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000873 cur->next = NULL;
874 cur->prev = NULL;
875 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000876 cur->last = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000877 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000878 cur->name = xmlStrdup(name);
879 cur->ns = ns;
880 cur->nsDef = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000881 cur->content = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000882#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000883 cur->_private = NULL;
884 cur->vepv = NULL;
885#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000886 return(cur);
887}
888
Daniel Veillard97b58771998-10-20 06:14:16 +0000889/**
890 * xmlNewDocNode:
891 * @doc: the document
892 * @ns: namespace if any
893 * @name: the node name
894 * @content: the text content if any
895 *
896 * Creation of a new node element within a document. @ns and @content
897 * are optionnal (NULL).
Daniel Veillard1e346af1999-02-22 10:33:01 +0000898 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +0000899 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000900xmlNodePtr
901xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard0bef1311998-10-14 02:36:47 +0000902 const CHAR *name, CHAR *content) {
903 xmlNodePtr cur;
904
Daniel Veillardccb09631998-10-27 06:21:04 +0000905 cur = xmlNewNode(ns, name);
906 if (cur != NULL) {
907 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000908 if (content != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000909 cur->childs = xmlStringGetNodeList(doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000910 UPDATE_LAST_CHILD(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000911 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000912 }
Daniel Veillard0bef1311998-10-14 02:36:47 +0000913 return(cur);
914}
915
916
Daniel Veillard97b58771998-10-20 06:14:16 +0000917/**
918 * xmlNewText:
919 * @content: the text content
920 *
921 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000922 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000923 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000924xmlNodePtr
925xmlNewText(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000926 xmlNodePtr cur;
927
928 /*
929 * Allocate a new node and fill the fields.
930 */
931 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
932 if (cur == NULL) {
933 fprintf(stderr, "xmlNewText : malloc failed\n");
934 return(NULL);
935 }
936
Daniel Veillard33942841998-10-18 19:12:41 +0000937 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000938 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000939 cur->parent = NULL;
940 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000941 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000942 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000943 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000944 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000945 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000946 cur->name = xmlStrdup(xmlStringText);
947 cur->ns = NULL;
948 cur->nsDef = NULL;
949 if (content != NULL)
950 cur->content = xmlStrdup(content);
951 else
952 cur->content = NULL;
953 return(cur);
954}
955
Daniel Veillard97b58771998-10-20 06:14:16 +0000956/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000957 * xmlNewReference:
958 * @doc: the document
959 * @name: the reference name, or the reference string with & and ;
960 *
961 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000962 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +0000963 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000964xmlNodePtr
965xmlNewReference(xmlDocPtr doc, const CHAR *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000966 xmlNodePtr cur;
967 xmlEntityPtr ent;
968
969 /*
970 * Allocate a new node and fill the fields.
971 */
972 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
973 if (cur == NULL) {
974 fprintf(stderr, "xmlNewText : malloc failed\n");
975 return(NULL);
976 }
977
978 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillard10c6a8f1998-10-28 01:00:12 +0000979 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +0000980 cur->parent = NULL;
981 cur->next = NULL;
982 cur->prev = NULL;
983 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000984 cur->last = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000985 cur->properties = NULL;
986 if (name[0] == '&') {
987 int len;
988 name++;
989 len = xmlStrlen(name);
990 if (name[len - 1] == ';')
991 cur->name = xmlStrndup(name, len - 1);
992 else
993 cur->name = xmlStrndup(name, len);
994 } else
995 cur->name = xmlStrdup(name);
996 cur->ns = NULL;
997 cur->nsDef = NULL;
998
999 ent = xmlGetDocEntity(doc, cur->name);
1000 if (ent != NULL)
1001 cur->content = ent->content;
1002 else
1003 cur->content = NULL;
1004 return(cur);
1005}
1006
1007/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001008 * xmlNewDocText:
1009 * @doc: the document
1010 * @content: the text content
1011 *
1012 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001013 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001014 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001015xmlNodePtr
1016xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001017 xmlNodePtr cur;
1018
1019 cur = xmlNewText(content);
1020 if (cur != NULL) cur->doc = doc;
1021 return(cur);
1022}
1023
Daniel Veillard97b58771998-10-20 06:14:16 +00001024/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001025 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001026 * @content: the text content
1027 * @len: the text len.
1028 *
1029 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001030 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001031 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001032xmlNodePtr
1033xmlNewTextLen(const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001034 xmlNodePtr cur;
1035
1036 /*
1037 * Allocate a new node and fill the fields.
1038 */
1039 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1040 if (cur == NULL) {
1041 fprintf(stderr, "xmlNewText : malloc failed\n");
1042 return(NULL);
1043 }
1044
Daniel Veillard33942841998-10-18 19:12:41 +00001045 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001046 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001047 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001048 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001049 cur->next = NULL;
1050 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001051 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001052 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001053 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001054 cur->name = xmlStrdup(xmlStringText);
1055 cur->ns = NULL;
1056 cur->nsDef = NULL;
1057 if (content != NULL)
1058 cur->content = xmlStrndup(content, len);
1059 else
1060 cur->content = NULL;
1061 return(cur);
1062}
1063
Daniel Veillard97b58771998-10-20 06:14:16 +00001064/**
1065 * xmlNewDocTextLen:
1066 * @doc: the document
1067 * @content: the text content
1068 * @len: the text len.
1069 *
1070 * Creation of a new text node with an extra content lenght parameter. The
1071 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001072 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001073 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001074xmlNodePtr
1075xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001076 xmlNodePtr cur;
1077
1078 cur = xmlNewTextLen(content, len);
1079 if (cur != NULL) cur->doc = doc;
1080 return(cur);
1081}
1082
Daniel Veillard97b58771998-10-20 06:14:16 +00001083/**
1084 * xmlNewComment:
1085 * @content: the comment content
1086 *
1087 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001088 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001089 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001090xmlNodePtr
Daniel Veillard517752b1999-04-05 12:20:10 +00001091xmlNewComment(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001092 xmlNodePtr cur;
1093
1094 /*
1095 * Allocate a new node and fill the fields.
1096 */
1097 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1098 if (cur == NULL) {
1099 fprintf(stderr, "xmlNewComment : malloc failed\n");
1100 return(NULL);
1101 }
1102
Daniel Veillard33942841998-10-18 19:12:41 +00001103 cur->type = XML_COMMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001104 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001105 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001106 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001107 cur->next = NULL;
1108 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001109 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001110 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001111 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001112 cur->name = xmlStrdup(xmlStringText);
1113 cur->ns = NULL;
1114 cur->nsDef = NULL;
1115 if (content != NULL)
1116 cur->content = xmlStrdup(content);
1117 else
1118 cur->content = NULL;
1119 return(cur);
1120}
1121
Daniel Veillard97b58771998-10-20 06:14:16 +00001122/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001123 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001124 * @doc: the document
1125 * @content: the comment content
1126 *
1127 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001128 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001129 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001130xmlNodePtr
Daniel Veillard517752b1999-04-05 12:20:10 +00001131xmlNewDocComment(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001132 xmlNodePtr cur;
1133
1134 cur = xmlNewComment(content);
1135 if (cur != NULL) cur->doc = doc;
1136 return(cur);
1137}
1138
Daniel Veillard97b58771998-10-20 06:14:16 +00001139/**
1140 * xmlNewChild:
1141 * @parent: the parent node
1142 * @ns: a namespace if any
1143 * @name: the name of the child
1144 * @content: the content of the child if any.
1145 *
1146 *
1147 * Creation of a new child element, added at the end of @parent childs list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001148 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1149 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001150 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001151 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001152xmlNodePtr
1153xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001154 const CHAR *name, CHAR *content) {
1155 xmlNodePtr cur, prev;
1156
1157 if (parent == NULL) {
1158 fprintf(stderr, "xmlNewChild : parent == NULL\n");
1159 return(NULL);
1160 }
1161
1162 if (name == NULL) {
1163 fprintf(stderr, "xmlNewChild : name == NULL\n");
1164 return(NULL);
1165 }
1166
1167 /*
1168 * Allocate a new node
1169 */
1170 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001171 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001172 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001173 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001174 if (cur == NULL) return(NULL);
1175
1176 /*
1177 * add the new element at the end of the childs list.
1178 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001179 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001180 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001181 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001182 if (parent->childs == NULL) {
1183 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001184 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001185 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001186 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001187 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001188 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001189 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001190 }
1191
1192 return(cur);
1193}
1194
Daniel Veillard97b58771998-10-20 06:14:16 +00001195/**
1196 * xmlAddChild:
1197 * @parent: the parent node
1198 * @cur: the child node
1199 *
1200 * Add a new child element, to @parent, at the end of the child list.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001201 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001202 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001203xmlNodePtr
1204xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001205 xmlNodePtr prev;
1206
1207 if (parent == NULL) {
1208 fprintf(stderr, "xmladdChild : parent == NULL\n");
1209 return(NULL);
1210 }
1211
1212 if (cur == NULL) {
1213 fprintf(stderr, "xmladdChild : child == NULL\n");
1214 return(NULL);
1215 }
1216
Daniel Veillard0bef1311998-10-14 02:36:47 +00001217 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1218 (cur->doc != parent->doc)) {
1219 fprintf(stderr, "Elements moved to a different document\n");
1220 }
1221
Daniel Veillard260a68f1998-08-13 03:39:55 +00001222 /*
1223 * add the new element at the end of the childs list.
1224 */
1225 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001226 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001227
Daniel Veillardccb09631998-10-27 06:21:04 +00001228 /*
1229 * Handle the case where parent->content != NULL, in that case it will
1230 * create a intermediate TEXT node.
1231 */
1232 if (parent->content != NULL) {
1233 xmlNodePtr text;
1234
1235 text = xmlNewDocText(parent->doc, parent->content);
1236 if (text != NULL) {
1237 text->next = parent->childs;
1238 if (text->next != NULL)
1239 text->next->prev = text;
1240 parent->childs = text;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001241 UPDATE_LAST_CHILD(parent)
Daniel Veillardccb09631998-10-27 06:21:04 +00001242 free(parent->content);
1243 parent->content = NULL;
1244 }
1245 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001246 if (parent->childs == NULL) {
1247 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001248 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001249 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001250 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001251 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001252 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001253 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001254 }
1255
1256 return(cur);
1257}
1258
Daniel Veillard97b58771998-10-20 06:14:16 +00001259/**
1260 * xmlGetLastChild:
1261 * @parent: the parent node
1262 *
1263 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001264 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001265 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001266xmlNodePtr
1267xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001268 if (parent == NULL) {
1269 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1270 return(NULL);
1271 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001272 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001273}
1274
Daniel Veillard97b58771998-10-20 06:14:16 +00001275/**
1276 * xmlFreeNodeList:
1277 * @cur: the first node in the list
1278 *
1279 * Free a node and all its siblings, this is a recursive behaviour, all
1280 * the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001281 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001282void
1283xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001284 xmlNodePtr next;
1285 if (cur == NULL) {
1286 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1287 return;
1288 }
1289 while (cur != NULL) {
1290 next = cur->next;
1291 xmlFreeNode(cur);
1292 cur = next;
1293 }
1294}
1295
Daniel Veillard97b58771998-10-20 06:14:16 +00001296/**
1297 * xmlFreeNode:
1298 * @cur: the node
1299 *
1300 * Free a node, this is a recursive behaviour, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001301 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001302void
1303xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001304 if (cur == NULL) {
1305 fprintf(stderr, "xmlFreeNode : node == NULL\n");
1306 return;
1307 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001308 cur->doc = NULL;
1309 cur->parent = NULL;
1310 cur->next = NULL;
1311 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001312 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
Daniel Veillardccb09631998-10-27 06:21:04 +00001313 if (cur->properties != NULL) xmlFreePropList(cur->properties);
1314 if (cur->type != XML_ENTITY_REF_NODE)
1315 if (cur->content != NULL) free(cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001316 if (cur->name != NULL) free((char *) cur->name);
1317 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1318 memset(cur, -1, sizeof(xmlNode));
1319 free(cur);
1320}
1321
Daniel Veillard16253641998-10-28 22:58:05 +00001322/**
1323 * xmlUnlinkNode:
1324 * @cur: the node
1325 *
1326 * Unlink a node from it's current context, the node is not freed
1327 */
1328void
1329xmlUnlinkNode(xmlNodePtr cur) {
1330 if (cur == NULL) {
1331 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1332 return;
1333 }
1334 if ((cur->parent != NULL) && (cur->parent->childs == cur))
1335 cur->parent->childs = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001336 if ((cur->parent != NULL) && (cur->parent->last == cur))
1337 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00001338 if (cur->next != NULL)
1339 cur->next->prev = cur->prev;
1340 if (cur->prev != NULL)
1341 cur->prev->next = cur->next;
1342 cur->next = cur->prev = NULL;
1343 cur->parent = NULL;
1344}
1345
Daniel Veillard260a68f1998-08-13 03:39:55 +00001346/************************************************************************
1347 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001348 * Copy operations *
1349 * *
1350 ************************************************************************/
1351
1352/**
1353 * xmlCopyNamespace:
1354 * @cur: the namespace
1355 *
1356 * Do a copy of the namespace.
1357 *
1358 * Returns: a new xmlNsPtr, or NULL in case of error.
1359 */
1360xmlNsPtr
1361xmlCopyNamespace(xmlNsPtr cur) {
1362 xmlNsPtr ret;
1363
1364 if (cur == NULL) return(NULL);
1365 switch (cur->type) {
1366 case XML_GLOBAL_NAMESPACE:
1367 ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
1368 break;
1369 case XML_LOCAL_NAMESPACE:
1370 ret = xmlNewNs(NULL, cur->href, cur->prefix);
1371 break;
1372 default:
1373 fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
1374 return(NULL);
1375 }
1376 return(ret);
1377}
1378
1379/**
1380 * xmlCopyNamespaceList:
1381 * @cur: the first namespace
1382 *
1383 * Do a copy of an namespace list.
1384 *
1385 * Returns: a new xmlNsPtr, or NULL in case of error.
1386 */
1387xmlNsPtr
1388xmlCopyNamespaceList(xmlNsPtr cur) {
1389 xmlNsPtr ret = NULL;
1390 xmlNsPtr p = NULL,q;
1391
1392 while (cur != NULL) {
1393 q = xmlCopyNamespace(cur);
1394 if (p == NULL) {
1395 ret = p = q;
1396 } else {
1397 p->next = q;
1398 p = q;
1399 }
1400 cur = cur->next;
1401 }
1402 return(ret);
1403}
1404
1405/**
1406 * xmlCopyProp:
1407 * @cur: the attribute
1408 *
1409 * Do a copy of the attribute.
1410 *
1411 * Returns: a new xmlAttrPtr, or NULL in case of error.
1412 */
1413xmlAttrPtr
1414xmlCopyProp(xmlAttrPtr cur) {
1415 xmlAttrPtr ret;
1416
1417 if (cur == NULL) return(NULL);
1418 if (cur->val != NULL)
1419 ret = xmlNewDocProp(cur->val->doc, cur->name, NULL);
1420 else
1421 ret = xmlNewDocProp(NULL, cur->name, NULL);
1422 if (ret == NULL) return(NULL);
1423 if (cur->val != NULL)
1424 ret->val = xmlCopyNodeList(cur->val);
1425 return(ret);
1426}
1427
1428/**
1429 * xmlCopyPropList:
1430 * @cur: the first attribute
1431 *
1432 * Do a copy of an attribute list.
1433 *
1434 * Returns: a new xmlAttrPtr, or NULL in case of error.
1435 */
1436xmlAttrPtr
1437xmlCopyPropList(xmlAttrPtr cur) {
1438 xmlAttrPtr ret = NULL;
1439 xmlAttrPtr p = NULL,q;
1440
1441 while (cur != NULL) {
1442 q = xmlCopyProp(cur);
1443 if (p == NULL) {
1444 ret = p = q;
1445 } else {
1446 p->next = q;
1447 p = q;
1448 }
1449 cur = cur->next;
1450 }
1451 return(ret);
1452}
1453
1454/*
1455 * NOTE about the CopyNode operations !
1456 *
1457 * They are splitted into external and internal parts for one
1458 * tricky reason: namespaces. Doing a direct copy of a node
1459 * say RPM:Copyright without changing the namespace pointer to
1460 * something else can produce stale links. One way to do it is
1461 * to keep a reference counter but this doesn't work as soon
1462 * as one move the element or the subtree out of the scope of
1463 * the existing namespace. The actual solution seems to add
1464 * a copy of the namespace at the top of the copied tree if
1465 * not available in the subtree.
1466 * Hence two functions, the public front-end call the inner ones
1467 */
1468
1469static xmlNodePtr
1470xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
1471
1472static xmlNodePtr
1473xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
1474 int recursive) {
1475 xmlNodePtr ret;
1476
1477 if (node == NULL) return(NULL);
1478 /*
1479 * Allocate a new node and fill the fields.
1480 */
1481 ret = (xmlNodePtr) malloc(sizeof(xmlNode));
1482 if (ret == NULL) {
1483 fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
1484 return(NULL);
1485 }
1486
1487 ret->type = node->type;
1488 ret->doc = doc;
1489 ret->parent = parent;
1490 ret->next = NULL;
1491 ret->prev = NULL;
1492 ret->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001493 ret->last = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001494 ret->properties = NULL;
1495 if (node->name != NULL)
1496 ret->name = xmlStrdup(node->name);
1497 else
1498 ret->name = NULL;
1499 ret->ns = NULL;
1500 ret->nsDef = NULL;
1501 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE))
1502 ret->content = xmlStrdup(node->content);
1503 else
1504 ret->content = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +00001505#ifndef XML_WITHOUT_CORBA
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001506 ret->_private = NULL;
1507 ret->vepv = NULL;
1508#endif
1509 if (parent != NULL)
1510 xmlAddChild(parent, ret);
1511
1512 if (!recursive) return(ret);
1513 if (node->properties != NULL)
1514 ret->properties = xmlCopyPropList(node->properties);
1515 if (node->nsDef != NULL)
1516 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
1517
1518 if (node->ns != NULL) {
1519 xmlNsPtr ns;
1520
1521 ns = xmlSearchNs(doc, ret, node->ns->prefix);
1522 if (ns == NULL) {
1523 /*
1524 * Humm, we are copying an element whose namespace is defined
1525 * out of the new tree scope. Search it in the original tree
1526 * and add it at the top of the new tree
1527 */
1528 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
1529 if (ns != NULL) {
1530 xmlNodePtr root = ret;
1531
1532 while (root->parent != NULL) root = root->parent;
1533 xmlNewNs(root, ns->href, ns->prefix);
1534 }
1535 } else {
1536 /*
1537 * reference the existing namespace definition in our own tree.
1538 */
1539 ret->ns = ns;
1540 }
1541 }
1542 if (node->childs != NULL)
1543 ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001544 UPDATE_LAST_CHILD(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001545 return(ret);
1546}
1547
1548static xmlNodePtr
1549xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
1550 xmlNodePtr ret = NULL;
1551 xmlNodePtr p = NULL,q;
1552
1553 while (node != NULL) {
1554 q = xmlStaticCopyNode(node, doc, parent, 1);
1555 if (parent == NULL) {
1556 if (ret == NULL) ret = q;
1557 } else {
1558 if (ret == NULL) {
1559 q->prev = NULL;
1560 ret = p = q;
1561 } else {
1562 p->next = q;
1563 q->prev = p;
1564 p = q;
1565 }
1566 }
1567 node = node->next;
1568 }
1569 return(ret);
1570}
1571
1572/**
1573 * xmlCopyNode:
1574 * @node: the node
1575 * @recursive: if 1 do a recursive copy.
1576 *
1577 * Do a copy of the node.
1578 *
1579 * Returns: a new xmlNodePtr, or NULL in case of error.
1580 */
1581xmlNodePtr
1582xmlCopyNode(xmlNodePtr node, int recursive) {
1583 xmlNodePtr ret;
1584
1585 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
1586 return(ret);
1587}
1588
1589/**
1590 * xmlCopyNodeList:
1591 * @node: the first node in the list.
1592 *
1593 * Do a recursive copy of the node list.
1594 *
1595 * Returns: a new xmlNodePtr, or NULL in case of error.
1596 */
1597xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
1598 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
1599 return(ret);
1600}
1601
1602/**
1603 * xmlCopyElement:
1604 * @elem: the element
1605 *
1606 * Do a copy of the element definition.
1607 *
1608 * Returns: a new xmlElementPtr, or NULL in case of error.
1609xmlElementPtr
1610xmlCopyElement(xmlElementPtr elem) {
1611 xmlElementPtr ret;
1612
1613 if (elem == NULL) return(NULL);
1614 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
1615 if (ret == NULL) return(NULL);
1616 if (!recursive) return(ret);
1617 if (elem->properties != NULL)
1618 ret->properties = xmlCopyPropList(elem->properties);
1619
1620 if (elem->nsDef != NULL)
1621 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
1622 if (elem->childs != NULL)
1623 ret->childs = xmlCopyElementList(elem->childs);
1624 return(ret);
1625}
1626 */
1627
1628/**
1629 * xmlCopyDtd:
1630 * @dtd: the dtd
1631 *
1632 * Do a copy of the dtd.
1633 *
1634 * Returns: a new xmlDtdPtr, or NULL in case of error.
1635 */
1636xmlDtdPtr
1637xmlCopyDtd(xmlDtdPtr dtd) {
1638 xmlDtdPtr ret;
1639
1640 if (dtd == NULL) return(NULL);
1641 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
1642 if (ret == NULL) return(NULL);
1643 if (dtd->entities != NULL)
1644 ret->entities = (void *) xmlCopyEntitiesTable(
1645 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001646 if (dtd->notations != NULL)
1647 ret->notations = (void *) xmlCopyNotationTable(
1648 (xmlNotationTablePtr) dtd->notations);
1649 if (dtd->elements != NULL)
1650 ret->elements = (void *) xmlCopyElementTable(
1651 (xmlElementTablePtr) dtd->elements);
1652 if (dtd->attributes != NULL)
1653 ret->attributes = (void *) xmlCopyAttributeTable(
1654 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001655 /*
1656 * TODO: support for Element definitions.
1657 */
1658 return(ret);
1659}
1660
1661/**
1662 * xmlCopyDoc:
1663 * @doc: the document
1664 * @recursive: if 1 do a recursive copy.
1665 *
1666 * Do a copy of the document info. If recursive, the content tree will
1667 * be copied too as well as Dtd, namespaces and entities.
1668 *
1669 * Returns: a new xmlDocPtr, or NULL in case of error.
1670 */
1671xmlDocPtr
1672xmlCopyDoc(xmlDocPtr doc, int recursive) {
1673 xmlDocPtr ret;
1674
1675 if (doc == NULL) return(NULL);
1676 ret = xmlNewDoc(doc->version);
1677 if (ret == NULL) return(NULL);
1678 if (doc->name != NULL)
1679 ret->name = strdup(doc->name);
1680 if (doc->encoding != NULL)
1681 ret->encoding = xmlStrdup(doc->encoding);
1682 ret->compression = doc->compression;
1683 ret->standalone = doc->standalone;
1684 if (!recursive) return(ret);
1685
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001686 if (doc->intSubset != NULL)
1687 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001688 if (doc->oldNs != NULL)
1689 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
1690 if (doc->root != NULL)
1691 ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL);
1692 return(ret);
1693}
1694
1695/************************************************************************
1696 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001697 * Content access functions *
1698 * *
1699 ************************************************************************/
1700
Daniel Veillard97b58771998-10-20 06:14:16 +00001701/**
Daniel Veillard16253641998-10-28 22:58:05 +00001702 * xmlNodeGetContent:
1703 * @cur: the node being read
1704 *
1705 * Read the value of a node, this can be either the text carried
1706 * directly by this node if it's a TEXT node or the aggregate string
1707 * of the values carried by this node child's (TEXT and ENTITY_REF).
1708 * Entity references are substitued.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001709 * Returns a new CHAR * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00001710 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00001711 */
1712CHAR *
1713xmlNodeGetContent(xmlNodePtr cur) {
1714 if (cur == NULL) return(NULL);
1715 switch (cur->type) {
1716 case XML_DOCUMENT_FRAG_NODE:
1717 case XML_ELEMENT_NODE:
1718 return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1719 break;
1720 case XML_ATTRIBUTE_NODE:
1721 case XML_CDATA_SECTION_NODE:
1722 case XML_ENTITY_REF_NODE:
1723 case XML_ENTITY_NODE:
1724 case XML_PI_NODE:
1725 case XML_COMMENT_NODE:
1726 case XML_DOCUMENT_NODE:
1727 case XML_DOCUMENT_TYPE_NODE:
1728 case XML_NOTATION_NODE:
1729 return(NULL);
1730 case XML_TEXT_NODE:
1731 if (cur->content != NULL)
1732 return(xmlStrdup(cur->content));
1733 return(NULL);
1734 }
1735 return(NULL);
1736}
1737
1738/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001739 * xmlNodeSetContent:
1740 * @cur: the node being modified
1741 * @content: the new value of the content
1742 *
1743 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001744 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001745void
1746xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001747 if (cur == NULL) {
1748 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1749 return;
1750 }
Daniel Veillard16253641998-10-28 22:58:05 +00001751 switch (cur->type) {
1752 case XML_DOCUMENT_FRAG_NODE:
1753 case XML_ELEMENT_NODE:
1754 if (cur->content != NULL) {
1755 free(cur->content);
1756 cur->content = NULL;
1757 }
1758 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1759 cur->childs = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001760 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001761 break;
1762 case XML_ATTRIBUTE_NODE:
1763 break;
1764 case XML_TEXT_NODE:
1765 case XML_CDATA_SECTION_NODE:
1766 case XML_ENTITY_REF_NODE:
1767 case XML_ENTITY_NODE:
1768 case XML_PI_NODE:
1769 case XML_COMMENT_NODE:
1770 if (cur->content != NULL) free(cur->content);
1771 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001772 cur->last = cur->childs = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001773 if (content != NULL)
1774 cur->content = xmlStrdup(content);
1775 else
1776 cur->content = NULL;
1777 case XML_DOCUMENT_NODE:
1778 case XML_DOCUMENT_TYPE_NODE:
1779 break;
1780 case XML_NOTATION_NODE:
1781 break;
1782 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001783}
1784
Daniel Veillard97b58771998-10-20 06:14:16 +00001785/**
1786 * xmlNodeSetContentLen:
1787 * @cur: the node being modified
1788 * @content: the new value of the content
1789 * @len: the size of @content
1790 *
1791 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001792 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001793void
1794xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001795 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001796 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001797 return;
1798 }
Daniel Veillard16253641998-10-28 22:58:05 +00001799 switch (cur->type) {
1800 case XML_DOCUMENT_FRAG_NODE:
1801 case XML_ELEMENT_NODE:
1802 if (cur->content != NULL) {
1803 free(cur->content);
1804 cur->content = NULL;
1805 }
1806 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1807 cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001808 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001809 break;
1810 case XML_ATTRIBUTE_NODE:
1811 break;
1812 case XML_TEXT_NODE:
1813 case XML_CDATA_SECTION_NODE:
1814 case XML_ENTITY_REF_NODE:
1815 case XML_ENTITY_NODE:
1816 case XML_PI_NODE:
1817 case XML_COMMENT_NODE:
1818 if (cur->content != NULL) free(cur->content);
1819 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001820 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001821 if (content != NULL)
1822 cur->content = xmlStrndup(content, len);
1823 else
1824 cur->content = NULL;
1825 case XML_DOCUMENT_NODE:
1826 case XML_DOCUMENT_TYPE_NODE:
1827 break;
1828 case XML_NOTATION_NODE:
1829 if (cur->content != NULL) free(cur->content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001830 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1831 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001832 if (content != NULL)
1833 cur->content = xmlStrndup(content, len);
1834 else
1835 cur->content = NULL;
1836 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001837 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001838}
1839
Daniel Veillard97b58771998-10-20 06:14:16 +00001840/**
1841 * xmlNodeAddContentLen:
1842 * @cur: the node being modified
1843 * @content: extra content
1844 * @len: the size of @content
1845 *
1846 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001847 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001848void
1849xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001850 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001851 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1852 return;
1853 }
1854 if (len <= 0) return;
1855 switch (cur->type) {
1856 case XML_DOCUMENT_FRAG_NODE:
1857 case XML_ELEMENT_NODE: {
1858 xmlNodePtr last = NULL, new;
1859
1860 if (cur->childs != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001861 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001862 } else {
1863 if (cur->content != NULL) {
1864 cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001865 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001866 free(cur->content);
1867 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001868 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001869 }
1870 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001871 new = xmlNewTextLen(content, len);
Daniel Veillard16253641998-10-28 22:58:05 +00001872 if (new != NULL) {
1873 xmlAddChild(cur, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001874 if ((last != NULL) && (last->next == new)) {
Daniel Veillard16253641998-10-28 22:58:05 +00001875 xmlTextMerge(last, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001876 }
Daniel Veillard16253641998-10-28 22:58:05 +00001877 }
1878 break;
1879 }
1880 case XML_ATTRIBUTE_NODE:
1881 break;
1882 case XML_TEXT_NODE:
1883 case XML_CDATA_SECTION_NODE:
1884 case XML_ENTITY_REF_NODE:
1885 case XML_ENTITY_NODE:
1886 case XML_PI_NODE:
1887 case XML_COMMENT_NODE:
1888 if (content != NULL)
1889 cur->content = xmlStrncat(cur->content, content, len);
1890 case XML_DOCUMENT_NODE:
1891 case XML_DOCUMENT_TYPE_NODE:
1892 break;
1893 case XML_NOTATION_NODE:
1894 if (content != NULL)
1895 cur->content = xmlStrncat(cur->content, content, len);
1896 break;
1897 }
1898}
1899
1900/**
1901 * xmlNodeAddContent:
1902 * @cur: the node being modified
1903 * @content: extra content
1904 *
1905 * Append the extra substring to the node content.
1906 */
1907void
1908xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1909 int len;
1910
1911 if (cur == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001912 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1913 return;
1914 }
Daniel Veillard16253641998-10-28 22:58:05 +00001915 if (content == NULL) return;
1916 len = xmlStrlen(content);
1917 xmlNodeAddContentLen(cur, content, len);
1918}
1919
1920/**
1921 * xmlTextMerge:
1922 * @first: the first text node
1923 * @second: the second text node being merged
1924 *
1925 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00001926 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00001927 */
1928xmlNodePtr
1929xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1930 if (first == NULL) return(second);
1931 if (second == NULL) return(first);
1932 if (first->type != XML_TEXT_NODE) return(first);
1933 if (second->type != XML_TEXT_NODE) return(first);
1934 xmlNodeAddContent(first, second->content);
1935 xmlUnlinkNode(second);
1936 xmlFreeNode(second);
1937 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001938}
1939
Daniel Veillard97b58771998-10-20 06:14:16 +00001940/**
1941 * xmlSearchNs:
1942 * @doc: the document
1943 * @node: the current node
1944 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00001945 *
Daniel Veillard97b58771998-10-20 06:14:16 +00001946 * Search a Ns registered under a given name space for a document.
1947 * recurse on the parents until it finds the defined namespace
1948 * or return NULL otherwise.
1949 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001950 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001951 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001952xmlNsPtr
1953xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001954 xmlNsPtr cur;
1955
1956 while (node != NULL) {
1957 cur = node->nsDef;
1958 while (cur != NULL) {
1959 if ((cur->prefix == NULL) && (nameSpace == NULL))
1960 return(cur);
1961 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1962 (!xmlStrcmp(cur->prefix, nameSpace)))
1963 return(cur);
1964 cur = cur->next;
1965 }
1966 node = node->parent;
1967 }
1968 if (doc != NULL) {
1969 cur = doc->oldNs;
1970 while (cur != NULL) {
1971 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1972 (!xmlStrcmp(cur->prefix, nameSpace)))
1973 return(cur);
1974 cur = cur->next;
1975 }
1976 }
1977 return(NULL);
1978}
1979
Daniel Veillard97b58771998-10-20 06:14:16 +00001980/**
1981 * xmlSearchNsByHref:
1982 * @doc: the document
1983 * @node: the current node
1984 * @href: the namespace value
1985 *
1986 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1987 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001988 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001989 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001990xmlNsPtr
1991xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001992 xmlNsPtr cur;
1993
1994 while (node != NULL) {
1995 cur = node->nsDef;
1996 while (cur != NULL) {
1997 if ((cur->href != NULL) && (href != NULL) &&
1998 (!xmlStrcmp(cur->href, href)))
1999 return(cur);
2000 cur = cur->next;
2001 }
2002 node = node->parent;
2003 }
2004 if (doc != NULL) {
2005 cur = doc->oldNs;
2006 while (cur != NULL) {
2007 if ((cur->href != NULL) && (href != NULL) &&
2008 (!xmlStrcmp(cur->href, href)))
2009 return(cur);
2010 cur = cur->next;
2011 }
2012 }
2013 return(NULL);
2014}
2015
Daniel Veillard97b58771998-10-20 06:14:16 +00002016/**
2017 * xmlGetProp:
2018 * @node: the node
2019 * @name: the attribute name
2020 *
2021 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00002022 * This does the entity substitution.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002023 * Returns the attribute value or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002024 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002025CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002026 xmlAttrPtr prop = node->properties;
2027
2028 while (prop != NULL) {
Daniel Veillard68178931999-02-08 18:34:36 +00002029 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillard6800ef31999-02-08 18:33:22 +00002030 CHAR *ret;
2031
2032 ret = xmlNodeListGetString(node->doc, prop->val, 1);
2033 if (ret == NULL) return(xmlStrdup(""));
2034 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00002035 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002036 prop = prop->next;
2037 }
2038 return(NULL);
2039}
2040
Daniel Veillard97b58771998-10-20 06:14:16 +00002041/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002042 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00002043 * @node: the node
2044 * @name: the attribute name
2045 * @value: the attribute value
2046 *
2047 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002048 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002049 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002050xmlAttrPtr
2051xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002052 xmlAttrPtr prop = node->properties;
2053
2054 while (prop != NULL) {
2055 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002056 if (prop->val != NULL)
2057 xmlFreeNode(prop->val);
2058 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002059 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00002060 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002061 return(prop);
2062 }
2063 prop = prop->next;
2064 }
2065 prop = xmlNewProp(node, name, value);
2066 return(prop);
2067}
2068
Daniel Veillard97b58771998-10-20 06:14:16 +00002069/**
2070 * xmlNodeIsText:
2071 * @node: the node
2072 *
2073 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00002074 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00002075 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002076int
2077xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002078 if (node == NULL) return(0);
2079
Daniel Veillard0bef1311998-10-14 02:36:47 +00002080 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002081 return(0);
2082}
2083
Daniel Veillard97b58771998-10-20 06:14:16 +00002084/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00002085 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00002086 * @node: the node
2087 * @content: the content
2088 * @len: @content lenght
2089 *
2090 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00002091 */
Daniel Veillard97b58771998-10-20 06:14:16 +00002092
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002093void
2094xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002095 if (node == NULL) return;
2096
Daniel Veillard0bef1311998-10-14 02:36:47 +00002097 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002098 fprintf(stderr, "xmlTextConcat: node is not text\n");
2099 return;
2100 }
2101 node->content = xmlStrncat(node->content, content, len);
2102}
2103
2104/************************************************************************
2105 * *
2106 * Output : to a FILE or in memory *
2107 * *
2108 ************************************************************************/
2109
Daniel Veillard5099ae81999-04-21 20:12:07 +00002110#define BASE_BUFFER_SIZE 4000
2111
2112/**
2113 * xmlBufferCreate:
2114 *
2115 * routine to create an XML buffer.
2116 * returns the new structure.
2117 */
2118xmlBufferPtr
2119xmlBufferCreate(void) {
2120 xmlBufferPtr ret;
2121
2122 ret = (xmlBufferPtr) malloc(sizeof(xmlBuffer));
2123 if (ret == NULL) {
2124 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
2125 return(NULL);
2126 }
2127 ret->use = 0;
2128 ret->size = BASE_BUFFER_SIZE;
2129 ret->content = (CHAR *) malloc(ret->size * sizeof(CHAR));
2130 if (ret->content == NULL) {
2131 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
2132 free(ret);
2133 return(NULL);
2134 }
2135 ret->content[0] = 0;
2136 return(ret);
2137}
2138
2139/**
2140 * xmlBufferFree:
2141 * @buf: the buffer to free
2142 *
2143 * Frees an XML buffer.
2144 */
2145void
2146xmlBufferFree(xmlBufferPtr buf) {
2147 if (buf == NULL) {
2148 fprintf(stderr, "xmlBufferFree: buf == NULL\n");
2149 return;
2150 }
2151 if (buf->content == NULL) {
2152 fprintf(stderr, "xmlBufferFree: buf->content == NULL\n");
2153 } else {
2154 memset(buf->content, -1, BASE_BUFFER_SIZE);
2155 free(buf->content);
2156 }
2157 memset(buf, -1, sizeof(xmlBuffer));
2158 free(buf);
2159}
2160
2161/**
2162 * xmlBufferDump:
2163 * @file: the file output
2164 * @buf: the buffer to dump
2165 *
2166 * Dumps an XML buffer to a FILE *.
2167 * Returns the number of CHAR written
2168 */
2169int
2170xmlBufferDump(FILE *file, xmlBufferPtr buf) {
2171 int ret;
2172
2173 if (buf == NULL) {
2174 fprintf(stderr, "xmlBufferDump: buf == NULL\n");
2175 return(0);
2176 }
2177 if (buf->content == NULL) {
2178 fprintf(stderr, "xmlBufferDump: buf->content == NULL\n");
2179 return(0);
2180 }
2181 if (file == NULL) file = stdout;
2182 ret = fwrite(buf->content, sizeof(CHAR), buf->use, file);
2183 return(ret);
2184}
2185
2186/**
2187 * xmlBufferAdd:
2188 * @buf: the buffer to dump
2189 * @str: the CHAR string
2190 * @len: the number of CHAR to add
2191 *
2192 * Add a string range to an XML buffer.
2193 */
2194void
2195xmlBufferAdd(xmlBufferPtr buf, const CHAR *str, int len) {
2196 const CHAR *cur;
2197
2198 if (str == NULL) {
2199 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2200 return;
2201 }
2202 for (cur = str;(len > 0) && (*cur != 0);cur++, len--) {
2203 if (buf->use + 10 >= buf->size) {
2204 CHAR *rebuf;
2205
2206 buf->size *= 2;
2207 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2208 if (rebuf == NULL) {
2209 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2210 return;
2211 }
2212 buf->content = rebuf;
2213 }
2214 buf->content[buf->use++] = *cur;
2215 }
2216}
2217
2218/**
2219 * xmlBufferCat:
2220 * @buf: the buffer to dump
2221 * @str: the CHAR string
2222 *
2223 * Append a zero terminated string to an XML buffer.
2224 */
2225void
2226xmlBufferCat(xmlBufferPtr buf, const CHAR *str) {
2227 const CHAR *cur;
2228
2229 if (str == NULL) {
2230 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2231 return;
2232 }
2233 for (cur = str;*cur != 0;cur++) {
2234 if (buf->use + 10 >= buf->size) {
2235 CHAR *rebuf;
2236
2237 buf->size *= 2;
2238 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2239 if (rebuf == NULL) {
2240 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2241 return;
2242 }
2243 buf->content = rebuf;
2244 }
2245 buf->content[buf->use++] = *cur;
2246 }
2247}
2248
2249/**
2250 * xmlBufferCCat:
2251 * @buf: the buffer to dump
2252 * @str: the C char string
2253 *
2254 * Append a zero terminated C string to an XML buffer.
2255 */
2256void
2257xmlBufferCCat(xmlBufferPtr buf, const char *str) {
2258 const char *cur;
2259
2260 if (str == NULL) {
2261 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2262 return;
2263 }
2264 for (cur = str;*cur != 0;cur++) {
2265 if (buf->use + 10 >= buf->size) {
2266 CHAR *rebuf;
2267
2268 buf->size *= 2;
2269 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2270 if (rebuf == NULL) {
2271 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2272 return;
2273 }
2274 buf->content = rebuf;
2275 }
2276 buf->content[buf->use++] = *cur;
2277 }
2278}
Daniel Veillard260a68f1998-08-13 03:39:55 +00002279
Daniel Veillard97b58771998-10-20 06:14:16 +00002280/**
2281 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002282 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00002283 * @string: the string to add
2284 *
2285 * routine which manage and grows an output buffer. This one add
Daniel Veillard5099ae81999-04-21 20:12:07 +00002286 * CHARs at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00002287 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002288void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002289xmlBufferWriteCHAR(xmlBufferPtr buf, const CHAR *string) {
2290 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002291}
2292
Daniel Veillard97b58771998-10-20 06:14:16 +00002293/**
2294 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002295 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002296 * @string: the string to add
2297 *
2298 * routine which manage and grows an output buffer. This one add
2299 * C chars at the end of the array.
2300 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002301void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002302xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
2303 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002304}
2305
Daniel Veillard5099ae81999-04-21 20:12:07 +00002306
Daniel Veillard97b58771998-10-20 06:14:16 +00002307/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00002308 * xmlBufferWriteQuotedString:
2309 * @buf: the XML buffer output
2310 * @string: the string to add
2311 *
2312 * routine which manage and grows an output buffer. This one writes
2313 * a quoted or double quoted CHAR string, checking first if it holds
2314 * quote or double-quotes internally
2315 */
2316void
2317xmlBufferWriteQuotedString(xmlBufferPtr buf, const CHAR *string) {
2318 /*
2319 * TODO: fix strchr by xmlStrchr to work coreectly on UTF-8 !!!
2320 */
2321 if (strchr(string, '"')) {
2322 if (strchr(string, '\'')) {
2323 fprintf(stderr,
2324 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
2325 }
2326 xmlBufferCCat(buf, "'");
2327 xmlBufferCat(buf, string);
2328 xmlBufferCCat(buf, "'");
2329 } else {
2330 xmlBufferCCat(buf, "\"");
2331 xmlBufferCat(buf, string);
2332 xmlBufferCCat(buf, "\"");
2333 }
2334}
2335
2336
2337/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002338 * xmlGlobalNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002339 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002340 * @cur: a namespace
2341 *
2342 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002343 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002344static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002345xmlGlobalNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002346 if (cur == NULL) {
2347 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
2348 return;
2349 }
2350 if (cur->type == XML_GLOBAL_NAMESPACE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002351 xmlBufferWriteChar(buf, "<?namespace");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002352 if (cur->href != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002353 xmlBufferWriteChar(buf, " href=");
2354 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002355 }
2356 if (cur->prefix != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002357 xmlBufferWriteChar(buf, " AS=");
2358 xmlBufferWriteQuotedString(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002359 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002360 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002361 }
2362}
2363
Daniel Veillard97b58771998-10-20 06:14:16 +00002364/**
2365 * xmlGlobalNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002366 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002367 * @cur: the first namespace
2368 *
2369 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002370 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002371static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002372xmlGlobalNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002373 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002374 xmlGlobalNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002375 cur = cur->next;
2376 }
2377}
2378
Daniel Veillard97b58771998-10-20 06:14:16 +00002379/**
2380 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002381 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002382 * @cur: a namespace
2383 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002384 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00002385 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002386 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002387static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002388xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002389 if (cur == NULL) {
2390 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
2391 return;
2392 }
2393 if (cur->type == XML_LOCAL_NAMESPACE) {
2394 /* Within the context of an element attributes */
2395 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002396 xmlBufferWriteChar(buf, " xmlns:");
2397 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002398 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00002399 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00002400 xmlBufferWriteChar(buf, "=");
2401 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002402 }
2403}
2404
Daniel Veillard97b58771998-10-20 06:14:16 +00002405/**
2406 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002407 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002408 * @cur: the first namespace
2409 *
2410 * Dump a list of local Namespace definitions.
2411 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002412 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002413static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002414xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002415 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002416 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002417 cur = cur->next;
2418 }
2419}
2420
Daniel Veillard97b58771998-10-20 06:14:16 +00002421/**
2422 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002423 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002424 * @doc: the document
2425 *
2426 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002427 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002428static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002429xmlDtdDump(xmlBufferPtr buf, xmlDocPtr doc) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002430 xmlDtdPtr cur = doc->intSubset;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002431
2432 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002433 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002434 return;
2435 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002436 xmlBufferWriteChar(buf, "<!DOCTYPE ");
2437 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002438 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002439 xmlBufferWriteChar(buf, " PUBLIC ");
2440 xmlBufferWriteQuotedString(buf, cur->ExternalID);
2441 xmlBufferWriteChar(buf, " ");
2442 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002443 } else if (cur->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002444 xmlBufferWriteChar(buf, " SYSTEM ");
2445 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002446 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002447 if ((cur->entities == NULL) && (cur->elements == NULL) &&
2448 (cur->attributes == NULL) && (cur->notations == NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002449 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002450 return;
2451 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002452 xmlBufferWriteChar(buf, " [\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002453 if (cur->entities != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002454 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) cur->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002455 if (cur->notations != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002456 xmlDumpNotationTable(buf, (xmlNotationTablePtr) cur->notations);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002457 if (cur->elements != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002458 xmlDumpElementTable(buf, (xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002459 if (cur->attributes != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002460 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) cur->attributes);
2461 xmlBufferWriteChar(buf, "]");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002462
2463 /* TODO !!! a lot more things to dump ... */
Daniel Veillard5099ae81999-04-21 20:12:07 +00002464 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002465}
2466
Daniel Veillard97b58771998-10-20 06:14:16 +00002467/**
2468 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002469 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002470 * @doc: the document
2471 * @cur: the attribute pointer
2472 *
2473 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00002474 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002475static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002476xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002477 CHAR *value;
2478
Daniel Veillard260a68f1998-08-13 03:39:55 +00002479 if (cur == NULL) {
2480 fprintf(stderr, "xmlAttrDump : property == NULL\n");
2481 return;
2482 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002483 xmlBufferWriteChar(buf, " ");
2484 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002485 value = xmlNodeListGetString(doc, cur->val, 0);
2486 if (value) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002487 xmlBufferWriteChar(buf, "=");
2488 xmlBufferWriteQuotedString(buf, value);
Daniel Veillardccb09631998-10-27 06:21:04 +00002489 free(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00002490 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002491 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002492 }
2493}
2494
Daniel Veillard97b58771998-10-20 06:14:16 +00002495/**
2496 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002497 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002498 * @doc: the document
2499 * @cur: the first attribute pointer
2500 *
2501 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00002502 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002503static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002504xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002505 if (cur == NULL) {
2506 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
2507 return;
2508 }
2509 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002510 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002511 cur = cur->next;
2512 }
2513}
2514
Daniel Veillard260a68f1998-08-13 03:39:55 +00002515
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002516static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002517xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00002518/**
2519 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002520 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002521 * @doc: the document
2522 * @cur: the first node
2523 * @level: the imbrication level for indenting
2524 *
2525 * Dump an XML node list, recursive behaviour,children are printed too.
2526 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002527static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002528xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002529 int needIndent = 0, i;
2530
Daniel Veillard260a68f1998-08-13 03:39:55 +00002531 if (cur == NULL) {
2532 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
2533 return;
2534 }
2535 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002536 if ((cur->type != XML_TEXT_NODE) &&
2537 (cur->type != XML_ENTITY_REF_NODE)) {
2538 if (!needIndent) {
2539 needIndent = 1;
Daniel Veillard5099ae81999-04-21 20:12:07 +00002540 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00002541 }
2542 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002543 xmlNodeDump(buf, doc, cur, level);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002544 cur = cur->next;
2545 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002546 if ((xmlIndentTreeOutput) && (needIndent))
2547 for (i = 1;i < level;i++)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002548 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002549}
2550
Daniel Veillard97b58771998-10-20 06:14:16 +00002551/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002552 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002553 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002554 * @doc: the document
2555 * @cur: the current node
2556 * @level: the imbrication level for indenting
2557 *
2558 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002559 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002560static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002561xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002562 int i;
2563
2564 if (cur == NULL) {
2565 fprintf(stderr, "xmlNodeDump : node == NULL\n");
2566 return;
2567 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002568 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002569 if (cur->content != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002570 xmlBufferWriteCHAR(buf, xmlEncodeEntities(doc, cur->content));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002571 return;
2572 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002573 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002574 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002575 xmlBufferWriteChar(buf, "<!--");
2576 xmlBufferWriteCHAR(buf, cur->content);
2577 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002578 }
2579 return;
2580 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002581 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002582 xmlBufferWriteChar(buf, "&");
2583 xmlBufferWriteCHAR(buf, cur->name);
2584 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00002585 return;
2586 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002587 if (xmlIndentTreeOutput)
2588 for (i = 0;i < level;i++)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002589 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002590
Daniel Veillard5099ae81999-04-21 20:12:07 +00002591 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002592 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002593 xmlBufferWriteCHAR(buf, cur->ns->prefix);
2594 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002595 }
2596
Daniel Veillard5099ae81999-04-21 20:12:07 +00002597 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002598 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002599 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002600 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002601 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002602
2603 if ((cur->content == NULL) && (cur->childs == NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002604 xmlBufferWriteChar(buf, "/>\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002605 return;
2606 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002607 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002608 if (cur->content != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002609 xmlBufferWriteCHAR(buf, xmlEncodeEntities(doc, cur->content));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002610 if (cur->childs != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002611 xmlNodeListDump(buf, doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002612 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002613 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002614 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002615 xmlBufferWriteCHAR(buf, cur->ns->prefix);
2616 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002617 }
2618
Daniel Veillard5099ae81999-04-21 20:12:07 +00002619 xmlBufferWriteCHAR(buf, cur->name);
2620 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002621}
2622
Daniel Veillard97b58771998-10-20 06:14:16 +00002623/**
2624 * xmlDocContentDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002625 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002626 * @cur: the document
2627 *
2628 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002629 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002630static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002631xmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002632 if (oldXMLWDcompatibility)
Daniel Veillard011b63c1999-06-02 17:44:04 +00002633 xmlBufferWriteChar(buf, "<?XML version=");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002634 else
Daniel Veillard011b63c1999-06-02 17:44:04 +00002635 xmlBufferWriteChar(buf, "<?xml version=");
2636 xmlBufferWriteQuotedString(buf, cur->version);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002637 if (cur->encoding != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002638 xmlBufferWriteChar(buf, " encoding=");
2639 xmlBufferWriteQuotedString(buf, cur->encoding);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002640 }
2641 switch (cur->standalone) {
2642 case 0:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002643 xmlBufferWriteChar(buf, " standalone=\"no\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002644 break;
2645 case 1:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002646 xmlBufferWriteChar(buf, " standalone=\"yes\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002647 break;
2648 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002649 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002650 if (cur->intSubset != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002651 xmlDtdDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002652 if (cur->root != NULL) {
2653 /* global namespace definitions, the old way */
2654 if (oldXMLWDcompatibility)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002655 xmlGlobalNsListDump(buf, cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002656 else
2657 xmlUpgradeOldNs(cur);
Daniel Veillard5099ae81999-04-21 20:12:07 +00002658 xmlNodeDump(buf, cur, cur->root, 0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002659 }
2660}
2661
Daniel Veillard97b58771998-10-20 06:14:16 +00002662/**
2663 * xmlDocDumpMemory:
2664 * @cur: the document
2665 * @mem: OUT: the memory pointer
2666 * @size: OUT: the memory lenght
2667 *
2668 * Dump an XML document in memory and return the CHAR * and it's size.
2669 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002670 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002671void
2672xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002673 xmlBufferPtr buf;
2674
Daniel Veillard260a68f1998-08-13 03:39:55 +00002675 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002676#ifdef DEBUG_TREE
2677 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
2678#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002679 *mem = NULL;
2680 *size = 0;
2681 return;
2682 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002683 buf = xmlBufferCreate();
2684 if (buf == NULL) {
2685 *mem = NULL;
2686 *size = 0;
2687 return;
2688 }
2689 xmlDocContentDump(buf, cur);
2690 *mem = buf->content;
2691 *size = buf->use;
2692 memset(buf, -1, sizeof(xmlBuffer));
2693 free(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002694}
2695
Daniel Veillard97b58771998-10-20 06:14:16 +00002696/**
2697 * xmlGetDocCompressMode:
2698 * @doc: the document
2699 *
2700 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00002701 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002702 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002703int
2704 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002705 if (doc == NULL) return(-1);
2706 return(doc->compression);
2707}
2708
Daniel Veillard97b58771998-10-20 06:14:16 +00002709/**
2710 * xmlSetDocCompressMode:
2711 * @doc: the document
2712 * @mode: the compression ratio
2713 *
2714 * set the compression ratio for a document, ZLIB based
2715 * Correct values: 0 (uncompressed) to 9 (max compression)
2716 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002717void
2718xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002719 if (doc == NULL) return;
2720 if (mode < 0) doc->compression = 0;
2721 else if (mode > 9) doc->compression = 9;
2722 else doc->compression = mode;
2723}
2724
Daniel Veillard97b58771998-10-20 06:14:16 +00002725/**
2726 * xmlGetCompressMode:
2727 *
2728 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002729 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002730 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002731int
2732 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002733 return(xmlCompressMode);
2734}
Daniel Veillard97b58771998-10-20 06:14:16 +00002735
2736/**
2737 * xmlSetCompressMode:
2738 * @mode: the compression ratio
2739 *
2740 * set the default compression mode used, ZLIB based
2741 * Correct values: 0 (uncompressed) to 9 (max compression)
2742 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002743void
2744xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002745 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002746 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002747 else xmlCompressMode = mode;
2748}
2749
Daniel Veillard97b58771998-10-20 06:14:16 +00002750/**
2751 * xmlDocDump:
2752 * @f: the FILE*
2753 * @cur: the document
2754 *
2755 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002756 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002757void
2758xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002759 xmlBufferPtr buf;
2760
Daniel Veillard260a68f1998-08-13 03:39:55 +00002761 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002762#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002763 fprintf(stderr, "xmlDocDump : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002764#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002765 return;
2766 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002767 buf = xmlBufferCreate();
2768 if (buf == NULL) return;
2769 xmlDocContentDump(buf, cur);
2770 xmlBufferDump(f, buf);
2771 xmlBufferFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002772}
2773
Daniel Veillard97b58771998-10-20 06:14:16 +00002774/**
2775 * xmlSaveFile:
2776 * @filename: the filename
2777 * @cur: the document
2778 *
2779 * Dump an XML document to a file. Will use compression if
2780 * compiled in and enabled.
2781 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002782 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002783int
2784xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002785 xmlBufferPtr buf;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002786#ifdef HAVE_ZLIB_H
2787 gzFile zoutput = NULL;
2788 char mode[15];
2789#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002790 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002791 int ret;
2792
Daniel Veillard5099ae81999-04-21 20:12:07 +00002793 /*
2794 * save the content to a temp buffer.
2795 */
2796 buf = xmlBufferCreate();
2797 if (buf == NULL) return(0);
2798 xmlDocContentDump(buf, cur);
2799
Daniel Veillard151b1b01998-09-23 00:49:46 +00002800#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002801 if ((cur->compression > 0) && (cur->compression <= 9)) {
2802 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002803 zoutput = gzopen(filename, mode);
2804 }
2805 if (zoutput == NULL) {
2806#endif
2807 output = fopen(filename, "w");
2808 if (output == NULL) return(-1);
2809#ifdef HAVE_ZLIB_H
2810 }
Daniel Veillard151b1b01998-09-23 00:49:46 +00002811
Daniel Veillard151b1b01998-09-23 00:49:46 +00002812 if (zoutput != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002813 ret = gzwrite(zoutput, buf->content, sizeof(CHAR) * buf->use);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002814 gzclose(zoutput);
Daniel Veillard5099ae81999-04-21 20:12:07 +00002815 } else {
2816#endif
2817 ret = xmlBufferDump(output, buf);
2818 fclose(output);
2819#ifdef HAVE_ZLIB_H
Daniel Veillard151b1b01998-09-23 00:49:46 +00002820 }
2821#endif
Manish Vachharajani5e60f5a1999-05-29 03:04:30 +00002822 xmlBufferFree(buf);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002823 return(ret * sizeof(CHAR));
2824}
2825