blob: 76a70c1748c677766bc114074d538b51b92a9bbe [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);
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000390 cur->ID = NULL;
391 cur->DTD = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000392 cur->name = NULL;
393 cur->root = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000394 cur->intSubset = NULL;
395 cur->extSubset = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000396 cur->oldNs = NULL;
397 cur->encoding = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000398 cur->standalone = -1;
Daniel Veillard15a8df41998-09-24 19:15:06 +0000399 cur->compression = xmlCompressMode;
Daniel Veillard27d88741999-05-29 11:51:49 +0000400#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000401 cur->_private = NULL;
402 cur->vepv = NULL;
403#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000404 return(cur);
405}
406
Daniel Veillard97b58771998-10-20 06:14:16 +0000407/**
408 * xmlFreeDoc:
409 * @cur: pointer to the document
410 * @:
411 *
412 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000413 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000414void
415xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000416 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000417#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000418 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000419#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000420 return;
421 }
422 free((char *) cur->version);
423 if (cur->name != NULL) free((char *) cur->name);
424 if (cur->encoding != NULL) free((char *) cur->encoding);
425 if (cur->root != NULL) xmlFreeNode(cur->root);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000426 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
427 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000428 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000429 memset(cur, -1, sizeof(xmlDoc));
430 free(cur);
431}
432
Daniel Veillard97b58771998-10-20 06:14:16 +0000433/**
Daniel Veillard16253641998-10-28 22:58:05 +0000434 * xmlStringLenGetNodeList:
435 * @doc: the document
436 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000437 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000438 *
439 * Parse the value string and build the node list associated. Should
440 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000441 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000442 */
443xmlNodePtr
444xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
445 xmlNodePtr ret = NULL, last = NULL;
446 xmlNodePtr node;
447 CHAR *val;
448 const CHAR *cur = value;
449 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000450 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000451
452 if (value == NULL) return(NULL);
453
454 q = cur;
455 while ((*cur != 0) && (cur - value < len)) {
456 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000457 /*
458 * Save the current text.
459 */
Daniel Veillard16253641998-10-28 22:58:05 +0000460 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000461 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
462 xmlNodeAddContentLen(last, q, cur - q);
463 } else {
464 node = xmlNewDocTextLen(doc, q, cur - q);
465 if (node == NULL) return(ret);
466 if (last == NULL)
467 last = ret = node;
468 else {
469 last->next = node;
470 node->prev = last;
471 last = node;
472 }
Daniel Veillard16253641998-10-28 22:58:05 +0000473 }
474 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000475 /*
476 * Read the entity string
477 */
Daniel Veillard16253641998-10-28 22:58:05 +0000478 cur++;
479 q = cur;
480 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
481 if ((*cur == 0) || (cur - value >= len)) {
482 fprintf(stderr,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000483 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillard16253641998-10-28 22:58:05 +0000484 return(ret);
485 }
486 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000487 /*
488 * Predefined entities don't generate nodes
489 */
Daniel Veillard16253641998-10-28 22:58:05 +0000490 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000491 ent = xmlGetDocEntity(doc, val);
492 if ((ent != NULL) &&
493 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
494 if (last == NULL) {
495 node = xmlNewDocText(doc, ent->content);
496 last = ret = node;
497 } else
498 xmlNodeAddContent(last, ent->content);
499
500 } else {
501 /*
502 * Create a new REFERENCE_REF node
503 */
504 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000505 if (node == NULL) {
506 if (val != NULL) free(val);
507 return(ret);
508 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000509 if (last == NULL)
510 last = ret = node;
511 else {
512 last->next = node;
513 node->prev = last;
514 last = node;
515 }
Daniel Veillard16253641998-10-28 22:58:05 +0000516 }
517 free(val);
518 }
519 cur++;
520 q = cur;
521 } else
522 cur++;
523 }
524 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000525 /*
526 * Handle the last piece of text.
527 */
528 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
529 xmlNodeAddContentLen(last, q, cur - q);
530 } else {
531 node = xmlNewDocTextLen(doc, q, cur - q);
532 if (node == NULL) return(ret);
533 if (last == NULL)
534 last = ret = node;
535 else {
536 last->next = node;
537 node->prev = last;
538 last = node;
539 }
Daniel Veillard16253641998-10-28 22:58:05 +0000540 }
541 }
542 return(ret);
543}
544
545/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000546 * xmlStringGetNodeList:
547 * @doc: the document
548 * @value: the value of the attribute
549 *
550 * Parse the value string and build the node list associated. Should
551 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000552 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000553 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000554xmlNodePtr
555xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000556 xmlNodePtr ret = NULL, last = NULL;
557 xmlNodePtr node;
558 CHAR *val;
559 const CHAR *cur = value;
560 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000561 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000562
563 if (value == NULL) return(NULL);
564
565 q = cur;
566 while (*cur != 0) {
567 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000568 /*
569 * Save the current text.
570 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000571 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000572 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
573 xmlNodeAddContentLen(last, q, cur - q);
574 } else {
575 node = xmlNewDocTextLen(doc, q, cur - q);
576 if (node == NULL) return(ret);
577 if (last == NULL)
578 last = ret = node;
579 else {
580 last->next = node;
581 node->prev = last;
582 last = node;
583 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000584 }
585 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000586 /*
587 * Read the entity string
588 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000589 cur++;
590 q = cur;
591 while ((*cur != 0) && (*cur != ';')) cur++;
592 if (*cur == 0) {
593 fprintf(stderr,
594 "xmlStringGetNodeList: unterminated entity %30s\n", q);
595 return(ret);
596 }
597 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000598 /*
599 * Predefined entities don't generate nodes
600 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000601 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000602 ent = xmlGetDocEntity(doc, val);
603 if ((ent != NULL) &&
604 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
605 if (last == NULL) {
606 node = xmlNewDocText(doc, ent->content);
607 last = ret = node;
608 } else
609 xmlNodeAddContent(last, ent->content);
610
611 } else {
612 /*
613 * Create a new REFERENCE_REF node
614 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000615 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000616 if (node == NULL) {
617 if (val != NULL) free(val);
618 return(ret);
619 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000620 if (last == NULL)
621 last = ret = node;
622 else {
623 last->next = node;
624 node->prev = last;
625 last = node;
626 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000627 }
628 free(val);
629 }
630 cur++;
631 q = cur;
632 } else
633 cur++;
634 }
635 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000636 /*
637 * Handle the last piece of text.
638 */
639 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
640 xmlNodeAddContentLen(last, q, cur - q);
641 } else {
642 node = xmlNewDocTextLen(doc, q, cur - q);
643 if (node == NULL) return(ret);
644 if (last == NULL)
645 last = ret = node;
646 else {
647 last->next = node;
648 node->prev = last;
649 last = node;
650 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000651 }
652 }
653 return(ret);
654}
655
656/**
657 * xmlNodeListGetString:
658 * @doc: the document
659 * @list: a Node list
660 * @inLine: should we replace entity contents or show their external form
661 *
662 * Returns the string equivalent to the text contained in the Node list
663 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000664 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000665 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000666CHAR *
667xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000668 xmlNodePtr node = list;
669 CHAR *ret = NULL;
670 xmlEntityPtr ent;
671
672 if (list == NULL) return(NULL);
673
674 while (node != NULL) {
675 if (node->type == XML_TEXT_NODE) {
676 if (inLine)
677 ret = xmlStrcat(ret, node->content);
Daniel Veillard14fff061999-06-22 21:49:07 +0000678 else {
679 CHAR *buffer;
680
681 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
682 if (buffer != NULL) {
683 ret = xmlStrcat(ret, buffer);
684 free(buffer);
685 }
686 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000687 } else if (node->type == XML_ENTITY_REF_NODE) {
688 if (inLine) {
689 ent = xmlGetDocEntity(doc, node->name);
690 if (ent != NULL)
691 ret = xmlStrcat(ret, ent->content);
692 else
693 ret = xmlStrcat(ret, node->content);
694 } else {
695 CHAR buf[2];
696 buf[0] = '&'; buf[1] = 0;
697 ret = xmlStrncat(ret, buf, 1);
698 ret = xmlStrcat(ret, node->name);
699 buf[0] = ';'; buf[1] = 0;
700 ret = xmlStrncat(ret, buf, 1);
701 }
702 }
703#if 0
704 else {
705 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
706 node->type);
707 }
708#endif
709 node = node->next;
710 }
711 return(ret);
712}
713
714/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000715 * xmlNewProp:
716 * @node: the holding node
717 * @name: the name of the attribute
718 * @value: the value of the attribute
719 *
720 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000721 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000722 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000723xmlAttrPtr
724xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000725 xmlAttrPtr cur;
726
727 if (name == NULL) {
728 fprintf(stderr, "xmlNewProp : name == NULL\n");
729 return(NULL);
730 }
731
732 /*
733 * Allocate a new property and fill the fields.
734 */
735 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
736 if (cur == NULL) {
737 fprintf(stderr, "xmlNewProp : malloc failed\n");
738 return(NULL);
739 }
740
Daniel Veillard33942841998-10-18 19:12:41 +0000741 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000742 cur->node = node;
743 cur->name = xmlStrdup(name);
744 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +0000745 cur->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000746 else
Daniel Veillardccb09631998-10-27 06:21:04 +0000747 cur->val = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000748#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000749 cur->_private = NULL;
750 cur->vepv = NULL;
751#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000752
753 /*
754 * Add it at the end to preserve parsing order ...
755 */
756 cur->next = NULL;
757 if (node != NULL) {
758 if (node->properties == NULL) {
759 node->properties = cur;
760 } else {
761 xmlAttrPtr prev = node->properties;
762
763 while (prev->next != NULL) prev = prev->next;
764 prev->next = cur;
765 }
766 }
767 return(cur);
768}
769
Daniel Veillard97b58771998-10-20 06:14:16 +0000770/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000771 * xmlNewDocProp:
772 * @doc: the document
773 * @name: the name of the attribute
774 * @value: the value of the attribute
775 *
776 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000777 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +0000778 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000779xmlAttrPtr
780xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000781 xmlAttrPtr cur;
782
783 if (name == NULL) {
784 fprintf(stderr, "xmlNewProp : name == NULL\n");
785 return(NULL);
786 }
787
788 /*
789 * Allocate a new property and fill the fields.
790 */
791 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
792 if (cur == NULL) {
793 fprintf(stderr, "xmlNewProp : malloc failed\n");
794 return(NULL);
795 }
796
797 cur->type = XML_ATTRIBUTE_NODE;
798 cur->node = NULL;
799 cur->name = xmlStrdup(name);
800 if (value != NULL)
801 cur->val = xmlStringGetNodeList(doc, value);
802 else
803 cur->val = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000804#ifndef XML_WITHOUT_CORBA
Daniel Veillardccb09631998-10-27 06:21:04 +0000805 cur->_private = NULL;
806 cur->vepv = NULL;
807#endif
808
809 cur->next = NULL;
810 return(cur);
811}
812
813/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000814 * xmlFreePropList:
815 * @cur: the first property in the list
816 *
817 * Free a property and all its siblings, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000818 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000819void
820xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000821 xmlAttrPtr next;
822 if (cur == NULL) {
823 fprintf(stderr, "xmlFreePropList : property == NULL\n");
824 return;
825 }
826 while (cur != NULL) {
827 next = cur->next;
828 xmlFreeProp(cur);
829 cur = next;
830 }
831}
832
Daniel Veillard97b58771998-10-20 06:14:16 +0000833/**
834 * xmlFreeProp:
835 * @cur: the first property in the list
836 *
837 * Free one property, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000838 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000839void
840xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000841 if (cur == NULL) {
842 fprintf(stderr, "xmlFreeProp : property == NULL\n");
843 return;
844 }
845 if (cur->name != NULL) free((char *) cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +0000846 if (cur->val != NULL) xmlFreeNodeList(cur->val);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000847 memset(cur, -1, sizeof(xmlAttr));
848 free(cur);
849}
850
Daniel Veillard97b58771998-10-20 06:14:16 +0000851/**
852 * xmlNewNode:
853 * @ns: namespace if any
854 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +0000855 *
856 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +0000857 * If content is non NULL, a child list containing the TEXTs and
858 * ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000859 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000860 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000861xmlNodePtr
862xmlNewNode(xmlNsPtr ns, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000863 xmlNodePtr cur;
864
865 if (name == NULL) {
866 fprintf(stderr, "xmlNewNode : name == NULL\n");
867 return(NULL);
868 }
869
870 /*
871 * Allocate a new node and fill the fields.
872 */
873 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
874 if (cur == NULL) {
875 fprintf(stderr, "xmlNewNode : malloc failed\n");
876 return(NULL);
877 }
878
Daniel Veillard33942841998-10-18 19:12:41 +0000879 cur->type = XML_ELEMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000880 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000881 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000882 cur->next = NULL;
883 cur->prev = NULL;
884 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000885 cur->last = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000886 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000887 cur->name = xmlStrdup(name);
888 cur->ns = ns;
889 cur->nsDef = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000890 cur->content = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000891#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000892 cur->_private = NULL;
893 cur->vepv = NULL;
894#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000895 return(cur);
896}
897
Daniel Veillard97b58771998-10-20 06:14:16 +0000898/**
899 * xmlNewDocNode:
900 * @doc: the document
901 * @ns: namespace if any
902 * @name: the node name
903 * @content: the text content if any
904 *
905 * Creation of a new node element within a document. @ns and @content
906 * are optionnal (NULL).
Daniel Veillard1e346af1999-02-22 10:33:01 +0000907 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +0000908 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000909xmlNodePtr
910xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard0bef1311998-10-14 02:36:47 +0000911 const CHAR *name, CHAR *content) {
912 xmlNodePtr cur;
913
Daniel Veillardccb09631998-10-27 06:21:04 +0000914 cur = xmlNewNode(ns, name);
915 if (cur != NULL) {
916 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000917 if (content != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000918 cur->childs = xmlStringGetNodeList(doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000919 UPDATE_LAST_CHILD(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000920 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000921 }
Daniel Veillard0bef1311998-10-14 02:36:47 +0000922 return(cur);
923}
924
925
Daniel Veillard97b58771998-10-20 06:14:16 +0000926/**
927 * xmlNewText:
928 * @content: the text content
929 *
930 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000931 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000932 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000933xmlNodePtr
934xmlNewText(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000935 xmlNodePtr cur;
936
937 /*
938 * Allocate a new node and fill the fields.
939 */
940 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
941 if (cur == NULL) {
942 fprintf(stderr, "xmlNewText : malloc failed\n");
943 return(NULL);
944 }
945
Daniel Veillard33942841998-10-18 19:12:41 +0000946 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000947 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000948 cur->parent = NULL;
949 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000950 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000951 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000952 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000953 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000954 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000955 cur->name = xmlStrdup(xmlStringText);
956 cur->ns = NULL;
957 cur->nsDef = NULL;
958 if (content != NULL)
959 cur->content = xmlStrdup(content);
960 else
961 cur->content = NULL;
962 return(cur);
963}
964
Daniel Veillard97b58771998-10-20 06:14:16 +0000965/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000966 * xmlNewReference:
967 * @doc: the document
968 * @name: the reference name, or the reference string with & and ;
969 *
970 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000971 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +0000972 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000973xmlNodePtr
974xmlNewReference(xmlDocPtr doc, const CHAR *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000975 xmlNodePtr cur;
976 xmlEntityPtr ent;
977
978 /*
979 * Allocate a new node and fill the fields.
980 */
981 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
982 if (cur == NULL) {
983 fprintf(stderr, "xmlNewText : malloc failed\n");
984 return(NULL);
985 }
986
987 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillard10c6a8f1998-10-28 01:00:12 +0000988 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +0000989 cur->parent = NULL;
990 cur->next = NULL;
991 cur->prev = NULL;
992 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000993 cur->last = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000994 cur->properties = NULL;
995 if (name[0] == '&') {
996 int len;
997 name++;
998 len = xmlStrlen(name);
999 if (name[len - 1] == ';')
1000 cur->name = xmlStrndup(name, len - 1);
1001 else
1002 cur->name = xmlStrndup(name, len);
1003 } else
1004 cur->name = xmlStrdup(name);
1005 cur->ns = NULL;
1006 cur->nsDef = NULL;
1007
1008 ent = xmlGetDocEntity(doc, cur->name);
1009 if (ent != NULL)
1010 cur->content = ent->content;
1011 else
1012 cur->content = NULL;
1013 return(cur);
1014}
1015
1016/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001017 * xmlNewDocText:
1018 * @doc: the document
1019 * @content: the text content
1020 *
1021 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001022 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001023 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001024xmlNodePtr
1025xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001026 xmlNodePtr cur;
1027
1028 cur = xmlNewText(content);
1029 if (cur != NULL) cur->doc = doc;
1030 return(cur);
1031}
1032
Daniel Veillard97b58771998-10-20 06:14:16 +00001033/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001034 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001035 * @content: the text content
1036 * @len: the text len.
1037 *
1038 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001039 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001040 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001041xmlNodePtr
1042xmlNewTextLen(const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001043 xmlNodePtr cur;
1044
1045 /*
1046 * Allocate a new node and fill the fields.
1047 */
1048 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1049 if (cur == NULL) {
1050 fprintf(stderr, "xmlNewText : malloc failed\n");
1051 return(NULL);
1052 }
1053
Daniel Veillard33942841998-10-18 19:12:41 +00001054 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001055 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001056 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001057 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001058 cur->next = NULL;
1059 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001060 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001061 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001062 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001063 cur->name = xmlStrdup(xmlStringText);
1064 cur->ns = NULL;
1065 cur->nsDef = NULL;
1066 if (content != NULL)
1067 cur->content = xmlStrndup(content, len);
1068 else
1069 cur->content = NULL;
1070 return(cur);
1071}
1072
Daniel Veillard97b58771998-10-20 06:14:16 +00001073/**
1074 * xmlNewDocTextLen:
1075 * @doc: the document
1076 * @content: the text content
1077 * @len: the text len.
1078 *
1079 * Creation of a new text node with an extra content lenght parameter. The
1080 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001081 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001082 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001083xmlNodePtr
1084xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001085 xmlNodePtr cur;
1086
1087 cur = xmlNewTextLen(content, len);
1088 if (cur != NULL) cur->doc = doc;
1089 return(cur);
1090}
1091
Daniel Veillard97b58771998-10-20 06:14:16 +00001092/**
1093 * xmlNewComment:
1094 * @content: the comment content
1095 *
1096 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001097 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001098 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001099xmlNodePtr
Daniel Veillard517752b1999-04-05 12:20:10 +00001100xmlNewComment(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001101 xmlNodePtr cur;
1102
1103 /*
1104 * Allocate a new node and fill the fields.
1105 */
1106 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1107 if (cur == NULL) {
1108 fprintf(stderr, "xmlNewComment : malloc failed\n");
1109 return(NULL);
1110 }
1111
Daniel Veillard33942841998-10-18 19:12:41 +00001112 cur->type = XML_COMMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001113 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001114 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001115 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001116 cur->next = NULL;
1117 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001118 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001119 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001120 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001121 cur->name = xmlStrdup(xmlStringText);
1122 cur->ns = NULL;
1123 cur->nsDef = NULL;
1124 if (content != NULL)
1125 cur->content = xmlStrdup(content);
1126 else
1127 cur->content = NULL;
1128 return(cur);
1129}
1130
Daniel Veillard97b58771998-10-20 06:14:16 +00001131/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001132 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001133 * @doc: the document
1134 * @content: the comment content
1135 *
1136 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001137 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001138 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001139xmlNodePtr
Daniel Veillard517752b1999-04-05 12:20:10 +00001140xmlNewDocComment(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001141 xmlNodePtr cur;
1142
1143 cur = xmlNewComment(content);
1144 if (cur != NULL) cur->doc = doc;
1145 return(cur);
1146}
1147
Daniel Veillard97b58771998-10-20 06:14:16 +00001148/**
1149 * xmlNewChild:
1150 * @parent: the parent node
1151 * @ns: a namespace if any
1152 * @name: the name of the child
1153 * @content: the content of the child if any.
1154 *
1155 *
1156 * Creation of a new child element, added at the end of @parent childs list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001157 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1158 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001159 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001160 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001161xmlNodePtr
1162xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001163 const CHAR *name, CHAR *content) {
1164 xmlNodePtr cur, prev;
1165
1166 if (parent == NULL) {
1167 fprintf(stderr, "xmlNewChild : parent == NULL\n");
1168 return(NULL);
1169 }
1170
1171 if (name == NULL) {
1172 fprintf(stderr, "xmlNewChild : name == NULL\n");
1173 return(NULL);
1174 }
1175
1176 /*
1177 * Allocate a new node
1178 */
1179 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001180 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001181 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001182 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001183 if (cur == NULL) return(NULL);
1184
1185 /*
1186 * add the new element at the end of the childs list.
1187 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001188 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001189 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001190 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001191 if (parent->childs == NULL) {
1192 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001193 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001194 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001195 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001196 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001197 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001198 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001199 }
1200
1201 return(cur);
1202}
1203
Daniel Veillard97b58771998-10-20 06:14:16 +00001204/**
1205 * xmlAddChild:
1206 * @parent: the parent node
1207 * @cur: the child node
1208 *
1209 * Add a new child element, to @parent, at the end of the child list.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001210 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001211 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001212xmlNodePtr
1213xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001214 xmlNodePtr prev;
1215
1216 if (parent == NULL) {
1217 fprintf(stderr, "xmladdChild : parent == NULL\n");
1218 return(NULL);
1219 }
1220
1221 if (cur == NULL) {
1222 fprintf(stderr, "xmladdChild : child == NULL\n");
1223 return(NULL);
1224 }
1225
Daniel Veillard0bef1311998-10-14 02:36:47 +00001226 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1227 (cur->doc != parent->doc)) {
1228 fprintf(stderr, "Elements moved to a different document\n");
1229 }
1230
Daniel Veillard260a68f1998-08-13 03:39:55 +00001231 /*
1232 * add the new element at the end of the childs list.
1233 */
1234 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001235 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001236
Daniel Veillardccb09631998-10-27 06:21:04 +00001237 /*
1238 * Handle the case where parent->content != NULL, in that case it will
1239 * create a intermediate TEXT node.
1240 */
1241 if (parent->content != NULL) {
1242 xmlNodePtr text;
1243
1244 text = xmlNewDocText(parent->doc, parent->content);
1245 if (text != NULL) {
1246 text->next = parent->childs;
1247 if (text->next != NULL)
1248 text->next->prev = text;
1249 parent->childs = text;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001250 UPDATE_LAST_CHILD(parent)
Daniel Veillardccb09631998-10-27 06:21:04 +00001251 free(parent->content);
1252 parent->content = NULL;
1253 }
1254 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001255 if (parent->childs == NULL) {
1256 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001257 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001258 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001259 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001260 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001261 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001262 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001263 }
1264
1265 return(cur);
1266}
1267
Daniel Veillard97b58771998-10-20 06:14:16 +00001268/**
1269 * xmlGetLastChild:
1270 * @parent: the parent node
1271 *
1272 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001273 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001274 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001275xmlNodePtr
1276xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001277 if (parent == NULL) {
1278 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1279 return(NULL);
1280 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001281 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001282}
1283
Daniel Veillard97b58771998-10-20 06:14:16 +00001284/**
1285 * xmlFreeNodeList:
1286 * @cur: the first node in the list
1287 *
1288 * Free a node and all its siblings, this is a recursive behaviour, all
1289 * the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001290 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001291void
1292xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001293 xmlNodePtr next;
1294 if (cur == NULL) {
1295 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1296 return;
1297 }
1298 while (cur != NULL) {
1299 next = cur->next;
1300 xmlFreeNode(cur);
1301 cur = next;
1302 }
1303}
1304
Daniel Veillard97b58771998-10-20 06:14:16 +00001305/**
1306 * xmlFreeNode:
1307 * @cur: the node
1308 *
1309 * Free a node, this is a recursive behaviour, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001310 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001311void
1312xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001313 if (cur == NULL) {
1314 fprintf(stderr, "xmlFreeNode : node == NULL\n");
1315 return;
1316 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001317 cur->doc = NULL;
1318 cur->parent = NULL;
1319 cur->next = NULL;
1320 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001321 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
Daniel Veillardccb09631998-10-27 06:21:04 +00001322 if (cur->properties != NULL) xmlFreePropList(cur->properties);
1323 if (cur->type != XML_ENTITY_REF_NODE)
1324 if (cur->content != NULL) free(cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001325 if (cur->name != NULL) free((char *) cur->name);
1326 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1327 memset(cur, -1, sizeof(xmlNode));
1328 free(cur);
1329}
1330
Daniel Veillard16253641998-10-28 22:58:05 +00001331/**
1332 * xmlUnlinkNode:
1333 * @cur: the node
1334 *
1335 * Unlink a node from it's current context, the node is not freed
1336 */
1337void
1338xmlUnlinkNode(xmlNodePtr cur) {
1339 if (cur == NULL) {
1340 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1341 return;
1342 }
1343 if ((cur->parent != NULL) && (cur->parent->childs == cur))
1344 cur->parent->childs = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001345 if ((cur->parent != NULL) && (cur->parent->last == cur))
1346 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00001347 if (cur->next != NULL)
1348 cur->next->prev = cur->prev;
1349 if (cur->prev != NULL)
1350 cur->prev->next = cur->next;
1351 cur->next = cur->prev = NULL;
1352 cur->parent = NULL;
1353}
1354
Daniel Veillard260a68f1998-08-13 03:39:55 +00001355/************************************************************************
1356 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001357 * Copy operations *
1358 * *
1359 ************************************************************************/
1360
1361/**
1362 * xmlCopyNamespace:
1363 * @cur: the namespace
1364 *
1365 * Do a copy of the namespace.
1366 *
1367 * Returns: a new xmlNsPtr, or NULL in case of error.
1368 */
1369xmlNsPtr
1370xmlCopyNamespace(xmlNsPtr cur) {
1371 xmlNsPtr ret;
1372
1373 if (cur == NULL) return(NULL);
1374 switch (cur->type) {
1375 case XML_GLOBAL_NAMESPACE:
1376 ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
1377 break;
1378 case XML_LOCAL_NAMESPACE:
1379 ret = xmlNewNs(NULL, cur->href, cur->prefix);
1380 break;
1381 default:
1382 fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
1383 return(NULL);
1384 }
1385 return(ret);
1386}
1387
1388/**
1389 * xmlCopyNamespaceList:
1390 * @cur: the first namespace
1391 *
1392 * Do a copy of an namespace list.
1393 *
1394 * Returns: a new xmlNsPtr, or NULL in case of error.
1395 */
1396xmlNsPtr
1397xmlCopyNamespaceList(xmlNsPtr cur) {
1398 xmlNsPtr ret = NULL;
1399 xmlNsPtr p = NULL,q;
1400
1401 while (cur != NULL) {
1402 q = xmlCopyNamespace(cur);
1403 if (p == NULL) {
1404 ret = p = q;
1405 } else {
1406 p->next = q;
1407 p = q;
1408 }
1409 cur = cur->next;
1410 }
1411 return(ret);
1412}
1413
1414/**
1415 * xmlCopyProp:
1416 * @cur: the attribute
1417 *
1418 * Do a copy of the attribute.
1419 *
1420 * Returns: a new xmlAttrPtr, or NULL in case of error.
1421 */
1422xmlAttrPtr
1423xmlCopyProp(xmlAttrPtr cur) {
1424 xmlAttrPtr ret;
1425
1426 if (cur == NULL) return(NULL);
1427 if (cur->val != NULL)
1428 ret = xmlNewDocProp(cur->val->doc, cur->name, NULL);
1429 else
1430 ret = xmlNewDocProp(NULL, cur->name, NULL);
1431 if (ret == NULL) return(NULL);
1432 if (cur->val != NULL)
1433 ret->val = xmlCopyNodeList(cur->val);
1434 return(ret);
1435}
1436
1437/**
1438 * xmlCopyPropList:
1439 * @cur: the first attribute
1440 *
1441 * Do a copy of an attribute list.
1442 *
1443 * Returns: a new xmlAttrPtr, or NULL in case of error.
1444 */
1445xmlAttrPtr
1446xmlCopyPropList(xmlAttrPtr cur) {
1447 xmlAttrPtr ret = NULL;
1448 xmlAttrPtr p = NULL,q;
1449
1450 while (cur != NULL) {
1451 q = xmlCopyProp(cur);
1452 if (p == NULL) {
1453 ret = p = q;
1454 } else {
1455 p->next = q;
1456 p = q;
1457 }
1458 cur = cur->next;
1459 }
1460 return(ret);
1461}
1462
1463/*
1464 * NOTE about the CopyNode operations !
1465 *
1466 * They are splitted into external and internal parts for one
1467 * tricky reason: namespaces. Doing a direct copy of a node
1468 * say RPM:Copyright without changing the namespace pointer to
1469 * something else can produce stale links. One way to do it is
1470 * to keep a reference counter but this doesn't work as soon
1471 * as one move the element or the subtree out of the scope of
1472 * the existing namespace. The actual solution seems to add
1473 * a copy of the namespace at the top of the copied tree if
1474 * not available in the subtree.
1475 * Hence two functions, the public front-end call the inner ones
1476 */
1477
1478static xmlNodePtr
1479xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
1480
1481static xmlNodePtr
1482xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
1483 int recursive) {
1484 xmlNodePtr ret;
1485
1486 if (node == NULL) return(NULL);
1487 /*
1488 * Allocate a new node and fill the fields.
1489 */
1490 ret = (xmlNodePtr) malloc(sizeof(xmlNode));
1491 if (ret == NULL) {
1492 fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
1493 return(NULL);
1494 }
1495
1496 ret->type = node->type;
1497 ret->doc = doc;
1498 ret->parent = parent;
1499 ret->next = NULL;
1500 ret->prev = NULL;
1501 ret->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001502 ret->last = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001503 ret->properties = NULL;
1504 if (node->name != NULL)
1505 ret->name = xmlStrdup(node->name);
1506 else
1507 ret->name = NULL;
1508 ret->ns = NULL;
1509 ret->nsDef = NULL;
1510 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE))
1511 ret->content = xmlStrdup(node->content);
1512 else
1513 ret->content = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +00001514#ifndef XML_WITHOUT_CORBA
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001515 ret->_private = NULL;
1516 ret->vepv = NULL;
1517#endif
1518 if (parent != NULL)
1519 xmlAddChild(parent, ret);
1520
1521 if (!recursive) return(ret);
1522 if (node->properties != NULL)
1523 ret->properties = xmlCopyPropList(node->properties);
1524 if (node->nsDef != NULL)
1525 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
1526
1527 if (node->ns != NULL) {
1528 xmlNsPtr ns;
1529
1530 ns = xmlSearchNs(doc, ret, node->ns->prefix);
1531 if (ns == NULL) {
1532 /*
1533 * Humm, we are copying an element whose namespace is defined
1534 * out of the new tree scope. Search it in the original tree
1535 * and add it at the top of the new tree
1536 */
1537 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
1538 if (ns != NULL) {
1539 xmlNodePtr root = ret;
1540
1541 while (root->parent != NULL) root = root->parent;
1542 xmlNewNs(root, ns->href, ns->prefix);
1543 }
1544 } else {
1545 /*
1546 * reference the existing namespace definition in our own tree.
1547 */
1548 ret->ns = ns;
1549 }
1550 }
1551 if (node->childs != NULL)
1552 ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001553 UPDATE_LAST_CHILD(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001554 return(ret);
1555}
1556
1557static xmlNodePtr
1558xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
1559 xmlNodePtr ret = NULL;
1560 xmlNodePtr p = NULL,q;
1561
1562 while (node != NULL) {
1563 q = xmlStaticCopyNode(node, doc, parent, 1);
1564 if (parent == NULL) {
1565 if (ret == NULL) ret = q;
1566 } else {
1567 if (ret == NULL) {
1568 q->prev = NULL;
1569 ret = p = q;
1570 } else {
1571 p->next = q;
1572 q->prev = p;
1573 p = q;
1574 }
1575 }
1576 node = node->next;
1577 }
1578 return(ret);
1579}
1580
1581/**
1582 * xmlCopyNode:
1583 * @node: the node
1584 * @recursive: if 1 do a recursive copy.
1585 *
1586 * Do a copy of the node.
1587 *
1588 * Returns: a new xmlNodePtr, or NULL in case of error.
1589 */
1590xmlNodePtr
1591xmlCopyNode(xmlNodePtr node, int recursive) {
1592 xmlNodePtr ret;
1593
1594 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
1595 return(ret);
1596}
1597
1598/**
1599 * xmlCopyNodeList:
1600 * @node: the first node in the list.
1601 *
1602 * Do a recursive copy of the node list.
1603 *
1604 * Returns: a new xmlNodePtr, or NULL in case of error.
1605 */
1606xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
1607 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
1608 return(ret);
1609}
1610
1611/**
1612 * xmlCopyElement:
1613 * @elem: the element
1614 *
1615 * Do a copy of the element definition.
1616 *
1617 * Returns: a new xmlElementPtr, or NULL in case of error.
1618xmlElementPtr
1619xmlCopyElement(xmlElementPtr elem) {
1620 xmlElementPtr ret;
1621
1622 if (elem == NULL) return(NULL);
1623 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
1624 if (ret == NULL) return(NULL);
1625 if (!recursive) return(ret);
1626 if (elem->properties != NULL)
1627 ret->properties = xmlCopyPropList(elem->properties);
1628
1629 if (elem->nsDef != NULL)
1630 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
1631 if (elem->childs != NULL)
1632 ret->childs = xmlCopyElementList(elem->childs);
1633 return(ret);
1634}
1635 */
1636
1637/**
1638 * xmlCopyDtd:
1639 * @dtd: the dtd
1640 *
1641 * Do a copy of the dtd.
1642 *
1643 * Returns: a new xmlDtdPtr, or NULL in case of error.
1644 */
1645xmlDtdPtr
1646xmlCopyDtd(xmlDtdPtr dtd) {
1647 xmlDtdPtr ret;
1648
1649 if (dtd == NULL) return(NULL);
1650 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
1651 if (ret == NULL) return(NULL);
1652 if (dtd->entities != NULL)
1653 ret->entities = (void *) xmlCopyEntitiesTable(
1654 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001655 if (dtd->notations != NULL)
1656 ret->notations = (void *) xmlCopyNotationTable(
1657 (xmlNotationTablePtr) dtd->notations);
1658 if (dtd->elements != NULL)
1659 ret->elements = (void *) xmlCopyElementTable(
1660 (xmlElementTablePtr) dtd->elements);
1661 if (dtd->attributes != NULL)
1662 ret->attributes = (void *) xmlCopyAttributeTable(
1663 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001664 /*
1665 * TODO: support for Element definitions.
1666 */
1667 return(ret);
1668}
1669
1670/**
1671 * xmlCopyDoc:
1672 * @doc: the document
1673 * @recursive: if 1 do a recursive copy.
1674 *
1675 * Do a copy of the document info. If recursive, the content tree will
1676 * be copied too as well as Dtd, namespaces and entities.
1677 *
1678 * Returns: a new xmlDocPtr, or NULL in case of error.
1679 */
1680xmlDocPtr
1681xmlCopyDoc(xmlDocPtr doc, int recursive) {
1682 xmlDocPtr ret;
1683
1684 if (doc == NULL) return(NULL);
1685 ret = xmlNewDoc(doc->version);
1686 if (ret == NULL) return(NULL);
1687 if (doc->name != NULL)
1688 ret->name = strdup(doc->name);
1689 if (doc->encoding != NULL)
1690 ret->encoding = xmlStrdup(doc->encoding);
1691 ret->compression = doc->compression;
1692 ret->standalone = doc->standalone;
1693 if (!recursive) return(ret);
1694
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001695 if (doc->intSubset != NULL)
1696 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001697 if (doc->oldNs != NULL)
1698 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
1699 if (doc->root != NULL)
1700 ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL);
1701 return(ret);
1702}
1703
1704/************************************************************************
1705 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001706 * Content access functions *
1707 * *
1708 ************************************************************************/
1709
Daniel Veillard97b58771998-10-20 06:14:16 +00001710/**
Daniel Veillard16253641998-10-28 22:58:05 +00001711 * xmlNodeGetContent:
1712 * @cur: the node being read
1713 *
1714 * Read the value of a node, this can be either the text carried
1715 * directly by this node if it's a TEXT node or the aggregate string
1716 * of the values carried by this node child's (TEXT and ENTITY_REF).
1717 * Entity references are substitued.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001718 * Returns a new CHAR * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00001719 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00001720 */
1721CHAR *
1722xmlNodeGetContent(xmlNodePtr cur) {
1723 if (cur == NULL) return(NULL);
1724 switch (cur->type) {
1725 case XML_DOCUMENT_FRAG_NODE:
1726 case XML_ELEMENT_NODE:
1727 return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1728 break;
1729 case XML_ATTRIBUTE_NODE:
1730 case XML_CDATA_SECTION_NODE:
1731 case XML_ENTITY_REF_NODE:
1732 case XML_ENTITY_NODE:
1733 case XML_PI_NODE:
1734 case XML_COMMENT_NODE:
1735 case XML_DOCUMENT_NODE:
1736 case XML_DOCUMENT_TYPE_NODE:
1737 case XML_NOTATION_NODE:
1738 return(NULL);
1739 case XML_TEXT_NODE:
1740 if (cur->content != NULL)
1741 return(xmlStrdup(cur->content));
1742 return(NULL);
1743 }
1744 return(NULL);
1745}
1746
1747/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001748 * xmlNodeSetContent:
1749 * @cur: the node being modified
1750 * @content: the new value of the content
1751 *
1752 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001753 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001754void
1755xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001756 if (cur == NULL) {
1757 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1758 return;
1759 }
Daniel Veillard16253641998-10-28 22:58:05 +00001760 switch (cur->type) {
1761 case XML_DOCUMENT_FRAG_NODE:
1762 case XML_ELEMENT_NODE:
1763 if (cur->content != NULL) {
1764 free(cur->content);
1765 cur->content = NULL;
1766 }
1767 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1768 cur->childs = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001769 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001770 break;
1771 case XML_ATTRIBUTE_NODE:
1772 break;
1773 case XML_TEXT_NODE:
1774 case XML_CDATA_SECTION_NODE:
1775 case XML_ENTITY_REF_NODE:
1776 case XML_ENTITY_NODE:
1777 case XML_PI_NODE:
1778 case XML_COMMENT_NODE:
1779 if (cur->content != NULL) free(cur->content);
1780 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001781 cur->last = cur->childs = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001782 if (content != NULL)
1783 cur->content = xmlStrdup(content);
1784 else
1785 cur->content = NULL;
1786 case XML_DOCUMENT_NODE:
1787 case XML_DOCUMENT_TYPE_NODE:
1788 break;
1789 case XML_NOTATION_NODE:
1790 break;
1791 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001792}
1793
Daniel Veillard97b58771998-10-20 06:14:16 +00001794/**
1795 * xmlNodeSetContentLen:
1796 * @cur: the node being modified
1797 * @content: the new value of the content
1798 * @len: the size of @content
1799 *
1800 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001801 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001802void
1803xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001804 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001805 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001806 return;
1807 }
Daniel Veillard16253641998-10-28 22:58:05 +00001808 switch (cur->type) {
1809 case XML_DOCUMENT_FRAG_NODE:
1810 case XML_ELEMENT_NODE:
1811 if (cur->content != NULL) {
1812 free(cur->content);
1813 cur->content = NULL;
1814 }
1815 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1816 cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001817 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001818 break;
1819 case XML_ATTRIBUTE_NODE:
1820 break;
1821 case XML_TEXT_NODE:
1822 case XML_CDATA_SECTION_NODE:
1823 case XML_ENTITY_REF_NODE:
1824 case XML_ENTITY_NODE:
1825 case XML_PI_NODE:
1826 case XML_COMMENT_NODE:
1827 if (cur->content != NULL) free(cur->content);
1828 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001829 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001830 if (content != NULL)
1831 cur->content = xmlStrndup(content, len);
1832 else
1833 cur->content = NULL;
1834 case XML_DOCUMENT_NODE:
1835 case XML_DOCUMENT_TYPE_NODE:
1836 break;
1837 case XML_NOTATION_NODE:
1838 if (cur->content != NULL) free(cur->content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001839 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1840 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001841 if (content != NULL)
1842 cur->content = xmlStrndup(content, len);
1843 else
1844 cur->content = NULL;
1845 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001846 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001847}
1848
Daniel Veillard97b58771998-10-20 06:14:16 +00001849/**
1850 * xmlNodeAddContentLen:
1851 * @cur: the node being modified
1852 * @content: extra content
1853 * @len: the size of @content
1854 *
1855 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001856 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001857void
1858xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001859 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001860 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1861 return;
1862 }
1863 if (len <= 0) return;
1864 switch (cur->type) {
1865 case XML_DOCUMENT_FRAG_NODE:
1866 case XML_ELEMENT_NODE: {
1867 xmlNodePtr last = NULL, new;
1868
1869 if (cur->childs != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001870 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001871 } else {
1872 if (cur->content != NULL) {
1873 cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001874 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001875 free(cur->content);
1876 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001877 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001878 }
1879 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001880 new = xmlNewTextLen(content, len);
Daniel Veillard16253641998-10-28 22:58:05 +00001881 if (new != NULL) {
1882 xmlAddChild(cur, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001883 if ((last != NULL) && (last->next == new)) {
Daniel Veillard16253641998-10-28 22:58:05 +00001884 xmlTextMerge(last, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001885 }
Daniel Veillard16253641998-10-28 22:58:05 +00001886 }
1887 break;
1888 }
1889 case XML_ATTRIBUTE_NODE:
1890 break;
1891 case XML_TEXT_NODE:
1892 case XML_CDATA_SECTION_NODE:
1893 case XML_ENTITY_REF_NODE:
1894 case XML_ENTITY_NODE:
1895 case XML_PI_NODE:
1896 case XML_COMMENT_NODE:
1897 if (content != NULL)
1898 cur->content = xmlStrncat(cur->content, content, len);
1899 case XML_DOCUMENT_NODE:
1900 case XML_DOCUMENT_TYPE_NODE:
1901 break;
1902 case XML_NOTATION_NODE:
1903 if (content != NULL)
1904 cur->content = xmlStrncat(cur->content, content, len);
1905 break;
1906 }
1907}
1908
1909/**
1910 * xmlNodeAddContent:
1911 * @cur: the node being modified
1912 * @content: extra content
1913 *
1914 * Append the extra substring to the node content.
1915 */
1916void
1917xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1918 int len;
1919
1920 if (cur == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001921 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1922 return;
1923 }
Daniel Veillard16253641998-10-28 22:58:05 +00001924 if (content == NULL) return;
1925 len = xmlStrlen(content);
1926 xmlNodeAddContentLen(cur, content, len);
1927}
1928
1929/**
1930 * xmlTextMerge:
1931 * @first: the first text node
1932 * @second: the second text node being merged
1933 *
1934 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00001935 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00001936 */
1937xmlNodePtr
1938xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1939 if (first == NULL) return(second);
1940 if (second == NULL) return(first);
1941 if (first->type != XML_TEXT_NODE) return(first);
1942 if (second->type != XML_TEXT_NODE) return(first);
1943 xmlNodeAddContent(first, second->content);
1944 xmlUnlinkNode(second);
1945 xmlFreeNode(second);
1946 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001947}
1948
Daniel Veillard97b58771998-10-20 06:14:16 +00001949/**
1950 * xmlSearchNs:
1951 * @doc: the document
1952 * @node: the current node
1953 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00001954 *
Daniel Veillard97b58771998-10-20 06:14:16 +00001955 * Search a Ns registered under a given name space for a document.
1956 * recurse on the parents until it finds the defined namespace
1957 * or return NULL otherwise.
1958 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001959 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001960 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001961xmlNsPtr
1962xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001963 xmlNsPtr cur;
1964
1965 while (node != NULL) {
1966 cur = node->nsDef;
1967 while (cur != NULL) {
1968 if ((cur->prefix == NULL) && (nameSpace == NULL))
1969 return(cur);
1970 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1971 (!xmlStrcmp(cur->prefix, nameSpace)))
1972 return(cur);
1973 cur = cur->next;
1974 }
1975 node = node->parent;
1976 }
1977 if (doc != NULL) {
1978 cur = doc->oldNs;
1979 while (cur != NULL) {
1980 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1981 (!xmlStrcmp(cur->prefix, nameSpace)))
1982 return(cur);
1983 cur = cur->next;
1984 }
1985 }
1986 return(NULL);
1987}
1988
Daniel Veillard97b58771998-10-20 06:14:16 +00001989/**
1990 * xmlSearchNsByHref:
1991 * @doc: the document
1992 * @node: the current node
1993 * @href: the namespace value
1994 *
1995 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1996 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001997 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001998 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001999xmlNsPtr
2000xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002001 xmlNsPtr cur;
2002
2003 while (node != NULL) {
2004 cur = node->nsDef;
2005 while (cur != NULL) {
2006 if ((cur->href != NULL) && (href != NULL) &&
2007 (!xmlStrcmp(cur->href, href)))
2008 return(cur);
2009 cur = cur->next;
2010 }
2011 node = node->parent;
2012 }
2013 if (doc != NULL) {
2014 cur = doc->oldNs;
2015 while (cur != NULL) {
2016 if ((cur->href != NULL) && (href != NULL) &&
2017 (!xmlStrcmp(cur->href, href)))
2018 return(cur);
2019 cur = cur->next;
2020 }
2021 }
2022 return(NULL);
2023}
2024
Daniel Veillard97b58771998-10-20 06:14:16 +00002025/**
2026 * xmlGetProp:
2027 * @node: the node
2028 * @name: the attribute name
2029 *
2030 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00002031 * This does the entity substitution.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002032 * Returns the attribute value or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002033 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002034CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002035 xmlAttrPtr prop = node->properties;
2036
2037 while (prop != NULL) {
Daniel Veillard68178931999-02-08 18:34:36 +00002038 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillard6800ef31999-02-08 18:33:22 +00002039 CHAR *ret;
2040
2041 ret = xmlNodeListGetString(node->doc, prop->val, 1);
2042 if (ret == NULL) return(xmlStrdup(""));
2043 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00002044 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002045 prop = prop->next;
2046 }
2047 return(NULL);
2048}
2049
Daniel Veillard97b58771998-10-20 06:14:16 +00002050/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002051 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00002052 * @node: the node
2053 * @name: the attribute name
2054 * @value: the attribute value
2055 *
2056 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002057 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002058 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002059xmlAttrPtr
2060xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002061 xmlAttrPtr prop = node->properties;
2062
2063 while (prop != NULL) {
2064 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002065 if (prop->val != NULL)
2066 xmlFreeNode(prop->val);
2067 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002068 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00002069 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002070 return(prop);
2071 }
2072 prop = prop->next;
2073 }
2074 prop = xmlNewProp(node, name, value);
2075 return(prop);
2076}
2077
Daniel Veillard97b58771998-10-20 06:14:16 +00002078/**
2079 * xmlNodeIsText:
2080 * @node: the node
2081 *
2082 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00002083 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00002084 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002085int
2086xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002087 if (node == NULL) return(0);
2088
Daniel Veillard0bef1311998-10-14 02:36:47 +00002089 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002090 return(0);
2091}
2092
Daniel Veillard97b58771998-10-20 06:14:16 +00002093/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00002094 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00002095 * @node: the node
2096 * @content: the content
2097 * @len: @content lenght
2098 *
2099 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00002100 */
Daniel Veillard97b58771998-10-20 06:14:16 +00002101
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002102void
2103xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002104 if (node == NULL) return;
2105
Daniel Veillard0bef1311998-10-14 02:36:47 +00002106 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002107 fprintf(stderr, "xmlTextConcat: node is not text\n");
2108 return;
2109 }
2110 node->content = xmlStrncat(node->content, content, len);
2111}
2112
2113/************************************************************************
2114 * *
2115 * Output : to a FILE or in memory *
2116 * *
2117 ************************************************************************/
2118
Daniel Veillard5099ae81999-04-21 20:12:07 +00002119#define BASE_BUFFER_SIZE 4000
2120
2121/**
2122 * xmlBufferCreate:
2123 *
2124 * routine to create an XML buffer.
2125 * returns the new structure.
2126 */
2127xmlBufferPtr
2128xmlBufferCreate(void) {
2129 xmlBufferPtr ret;
2130
2131 ret = (xmlBufferPtr) malloc(sizeof(xmlBuffer));
2132 if (ret == NULL) {
2133 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
2134 return(NULL);
2135 }
2136 ret->use = 0;
2137 ret->size = BASE_BUFFER_SIZE;
2138 ret->content = (CHAR *) malloc(ret->size * sizeof(CHAR));
2139 if (ret->content == NULL) {
2140 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
2141 free(ret);
2142 return(NULL);
2143 }
2144 ret->content[0] = 0;
2145 return(ret);
2146}
2147
2148/**
2149 * xmlBufferFree:
2150 * @buf: the buffer to free
2151 *
2152 * Frees an XML buffer.
2153 */
2154void
2155xmlBufferFree(xmlBufferPtr buf) {
2156 if (buf == NULL) {
2157 fprintf(stderr, "xmlBufferFree: buf == NULL\n");
2158 return;
2159 }
2160 if (buf->content == NULL) {
2161 fprintf(stderr, "xmlBufferFree: buf->content == NULL\n");
2162 } else {
2163 memset(buf->content, -1, BASE_BUFFER_SIZE);
2164 free(buf->content);
2165 }
2166 memset(buf, -1, sizeof(xmlBuffer));
2167 free(buf);
2168}
2169
2170/**
2171 * xmlBufferDump:
2172 * @file: the file output
2173 * @buf: the buffer to dump
2174 *
2175 * Dumps an XML buffer to a FILE *.
2176 * Returns the number of CHAR written
2177 */
2178int
2179xmlBufferDump(FILE *file, xmlBufferPtr buf) {
2180 int ret;
2181
2182 if (buf == NULL) {
2183 fprintf(stderr, "xmlBufferDump: buf == NULL\n");
2184 return(0);
2185 }
2186 if (buf->content == NULL) {
2187 fprintf(stderr, "xmlBufferDump: buf->content == NULL\n");
2188 return(0);
2189 }
2190 if (file == NULL) file = stdout;
2191 ret = fwrite(buf->content, sizeof(CHAR), buf->use, file);
2192 return(ret);
2193}
2194
2195/**
2196 * xmlBufferAdd:
2197 * @buf: the buffer to dump
2198 * @str: the CHAR string
2199 * @len: the number of CHAR to add
2200 *
2201 * Add a string range to an XML buffer.
2202 */
2203void
2204xmlBufferAdd(xmlBufferPtr buf, const CHAR *str, int len) {
2205 const CHAR *cur;
2206
2207 if (str == NULL) {
2208 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2209 return;
2210 }
2211 for (cur = str;(len > 0) && (*cur != 0);cur++, len--) {
2212 if (buf->use + 10 >= buf->size) {
2213 CHAR *rebuf;
2214
2215 buf->size *= 2;
2216 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2217 if (rebuf == NULL) {
2218 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2219 return;
2220 }
2221 buf->content = rebuf;
2222 }
2223 buf->content[buf->use++] = *cur;
2224 }
2225}
2226
2227/**
2228 * xmlBufferCat:
2229 * @buf: the buffer to dump
2230 * @str: the CHAR string
2231 *
2232 * Append a zero terminated string to an XML buffer.
2233 */
2234void
2235xmlBufferCat(xmlBufferPtr buf, const CHAR *str) {
2236 const CHAR *cur;
2237
2238 if (str == NULL) {
2239 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2240 return;
2241 }
2242 for (cur = str;*cur != 0;cur++) {
2243 if (buf->use + 10 >= buf->size) {
2244 CHAR *rebuf;
2245
2246 buf->size *= 2;
2247 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2248 if (rebuf == NULL) {
2249 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2250 return;
2251 }
2252 buf->content = rebuf;
2253 }
2254 buf->content[buf->use++] = *cur;
2255 }
2256}
2257
2258/**
2259 * xmlBufferCCat:
2260 * @buf: the buffer to dump
2261 * @str: the C char string
2262 *
2263 * Append a zero terminated C string to an XML buffer.
2264 */
2265void
2266xmlBufferCCat(xmlBufferPtr buf, const char *str) {
2267 const char *cur;
2268
2269 if (str == NULL) {
2270 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2271 return;
2272 }
2273 for (cur = str;*cur != 0;cur++) {
2274 if (buf->use + 10 >= buf->size) {
2275 CHAR *rebuf;
2276
2277 buf->size *= 2;
2278 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2279 if (rebuf == NULL) {
2280 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2281 return;
2282 }
2283 buf->content = rebuf;
2284 }
2285 buf->content[buf->use++] = *cur;
2286 }
2287}
Daniel Veillard260a68f1998-08-13 03:39:55 +00002288
Daniel Veillard97b58771998-10-20 06:14:16 +00002289/**
2290 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002291 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00002292 * @string: the string to add
2293 *
2294 * routine which manage and grows an output buffer. This one add
Daniel Veillard5099ae81999-04-21 20:12:07 +00002295 * CHARs at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00002296 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002297void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002298xmlBufferWriteCHAR(xmlBufferPtr buf, const CHAR *string) {
2299 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002300}
2301
Daniel Veillard97b58771998-10-20 06:14:16 +00002302/**
2303 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002304 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002305 * @string: the string to add
2306 *
2307 * routine which manage and grows an output buffer. This one add
2308 * C chars at the end of the array.
2309 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002310void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002311xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
2312 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002313}
2314
Daniel Veillard5099ae81999-04-21 20:12:07 +00002315
Daniel Veillard97b58771998-10-20 06:14:16 +00002316/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00002317 * xmlBufferWriteQuotedString:
2318 * @buf: the XML buffer output
2319 * @string: the string to add
2320 *
2321 * routine which manage and grows an output buffer. This one writes
2322 * a quoted or double quoted CHAR string, checking first if it holds
2323 * quote or double-quotes internally
2324 */
2325void
2326xmlBufferWriteQuotedString(xmlBufferPtr buf, const CHAR *string) {
2327 /*
2328 * TODO: fix strchr by xmlStrchr to work coreectly on UTF-8 !!!
2329 */
2330 if (strchr(string, '"')) {
2331 if (strchr(string, '\'')) {
2332 fprintf(stderr,
2333 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
2334 }
2335 xmlBufferCCat(buf, "'");
2336 xmlBufferCat(buf, string);
2337 xmlBufferCCat(buf, "'");
2338 } else {
2339 xmlBufferCCat(buf, "\"");
2340 xmlBufferCat(buf, string);
2341 xmlBufferCCat(buf, "\"");
2342 }
2343}
2344
2345
2346/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002347 * xmlGlobalNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002348 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002349 * @cur: a namespace
2350 *
2351 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002352 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002353static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002354xmlGlobalNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002355 if (cur == NULL) {
2356 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
2357 return;
2358 }
2359 if (cur->type == XML_GLOBAL_NAMESPACE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002360 xmlBufferWriteChar(buf, "<?namespace");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002361 if (cur->href != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002362 xmlBufferWriteChar(buf, " href=");
2363 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002364 }
2365 if (cur->prefix != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002366 xmlBufferWriteChar(buf, " AS=");
2367 xmlBufferWriteQuotedString(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002368 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002369 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002370 }
2371}
2372
Daniel Veillard97b58771998-10-20 06:14:16 +00002373/**
2374 * xmlGlobalNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002375 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002376 * @cur: the first namespace
2377 *
2378 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002379 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002380static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002381xmlGlobalNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002382 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002383 xmlGlobalNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002384 cur = cur->next;
2385 }
2386}
2387
Daniel Veillard97b58771998-10-20 06:14:16 +00002388/**
2389 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002390 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002391 * @cur: a namespace
2392 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002393 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00002394 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002395 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002396static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002397xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002398 if (cur == NULL) {
2399 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
2400 return;
2401 }
2402 if (cur->type == XML_LOCAL_NAMESPACE) {
2403 /* Within the context of an element attributes */
2404 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002405 xmlBufferWriteChar(buf, " xmlns:");
2406 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002407 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00002408 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00002409 xmlBufferWriteChar(buf, "=");
2410 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002411 }
2412}
2413
Daniel Veillard97b58771998-10-20 06:14:16 +00002414/**
2415 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002416 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002417 * @cur: the first namespace
2418 *
2419 * Dump a list of local Namespace definitions.
2420 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002421 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002422static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002423xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002424 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002425 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002426 cur = cur->next;
2427 }
2428}
2429
Daniel Veillard97b58771998-10-20 06:14:16 +00002430/**
2431 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002432 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002433 * @doc: the document
2434 *
2435 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002436 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002437static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002438xmlDtdDump(xmlBufferPtr buf, xmlDocPtr doc) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002439 xmlDtdPtr cur = doc->intSubset;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002440
2441 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002442 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002443 return;
2444 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002445 xmlBufferWriteChar(buf, "<!DOCTYPE ");
2446 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002447 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002448 xmlBufferWriteChar(buf, " PUBLIC ");
2449 xmlBufferWriteQuotedString(buf, cur->ExternalID);
2450 xmlBufferWriteChar(buf, " ");
2451 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002452 } else if (cur->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002453 xmlBufferWriteChar(buf, " SYSTEM ");
2454 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002455 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002456 if ((cur->entities == NULL) && (cur->elements == NULL) &&
2457 (cur->attributes == NULL) && (cur->notations == NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002458 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002459 return;
2460 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002461 xmlBufferWriteChar(buf, " [\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002462 if (cur->entities != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002463 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) cur->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002464 if (cur->notations != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002465 xmlDumpNotationTable(buf, (xmlNotationTablePtr) cur->notations);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002466 if (cur->elements != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002467 xmlDumpElementTable(buf, (xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002468 if (cur->attributes != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002469 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) cur->attributes);
2470 xmlBufferWriteChar(buf, "]");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002471
2472 /* TODO !!! a lot more things to dump ... */
Daniel Veillard5099ae81999-04-21 20:12:07 +00002473 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002474}
2475
Daniel Veillard97b58771998-10-20 06:14:16 +00002476/**
2477 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002478 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002479 * @doc: the document
2480 * @cur: the attribute pointer
2481 *
2482 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00002483 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002484static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002485xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002486 CHAR *value;
2487
Daniel Veillard260a68f1998-08-13 03:39:55 +00002488 if (cur == NULL) {
2489 fprintf(stderr, "xmlAttrDump : property == NULL\n");
2490 return;
2491 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002492 xmlBufferWriteChar(buf, " ");
2493 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002494 value = xmlNodeListGetString(doc, cur->val, 0);
2495 if (value) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002496 xmlBufferWriteChar(buf, "=");
2497 xmlBufferWriteQuotedString(buf, value);
Daniel Veillardccb09631998-10-27 06:21:04 +00002498 free(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00002499 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002500 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002501 }
2502}
2503
Daniel Veillard97b58771998-10-20 06:14:16 +00002504/**
2505 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002506 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002507 * @doc: the document
2508 * @cur: the first attribute pointer
2509 *
2510 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00002511 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002512static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002513xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002514 if (cur == NULL) {
2515 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
2516 return;
2517 }
2518 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002519 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002520 cur = cur->next;
2521 }
2522}
2523
Daniel Veillard260a68f1998-08-13 03:39:55 +00002524
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002525static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002526xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00002527/**
2528 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002529 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002530 * @doc: the document
2531 * @cur: the first node
2532 * @level: the imbrication level for indenting
2533 *
2534 * Dump an XML node list, recursive behaviour,children are printed too.
2535 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002536static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002537xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002538 int needIndent = 0, i;
2539
Daniel Veillard260a68f1998-08-13 03:39:55 +00002540 if (cur == NULL) {
2541 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
2542 return;
2543 }
2544 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002545 if ((cur->type != XML_TEXT_NODE) &&
2546 (cur->type != XML_ENTITY_REF_NODE)) {
2547 if (!needIndent) {
2548 needIndent = 1;
Daniel Veillard5099ae81999-04-21 20:12:07 +00002549 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00002550 }
2551 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002552 xmlNodeDump(buf, doc, cur, level);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002553 cur = cur->next;
2554 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002555 if ((xmlIndentTreeOutput) && (needIndent))
2556 for (i = 1;i < level;i++)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002557 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002558}
2559
Daniel Veillard97b58771998-10-20 06:14:16 +00002560/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002561 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002562 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002563 * @doc: the document
2564 * @cur: the current node
2565 * @level: the imbrication level for indenting
2566 *
2567 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002568 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002569static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002570xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002571 int i;
2572
2573 if (cur == NULL) {
2574 fprintf(stderr, "xmlNodeDump : node == NULL\n");
2575 return;
2576 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002577 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00002578 if (cur->content != NULL) {
2579 CHAR *buffer;
2580
2581 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
2582 if (buffer != NULL) {
2583 xmlBufferWriteCHAR(buf, buffer);
2584 free(buffer);
2585 }
2586 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002587 return;
2588 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002589 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002590 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002591 xmlBufferWriteChar(buf, "<!--");
2592 xmlBufferWriteCHAR(buf, cur->content);
2593 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002594 }
2595 return;
2596 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002597 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002598 xmlBufferWriteChar(buf, "&");
2599 xmlBufferWriteCHAR(buf, cur->name);
2600 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00002601 return;
2602 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002603 if (xmlIndentTreeOutput)
2604 for (i = 0;i < level;i++)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002605 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002606
Daniel Veillard5099ae81999-04-21 20:12:07 +00002607 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002608 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002609 xmlBufferWriteCHAR(buf, cur->ns->prefix);
2610 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002611 }
2612
Daniel Veillard5099ae81999-04-21 20:12:07 +00002613 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002614 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002615 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002616 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002617 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002618
2619 if ((cur->content == NULL) && (cur->childs == NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002620 xmlBufferWriteChar(buf, "/>\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002621 return;
2622 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002623 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00002624 if (cur->content != NULL) {
2625 CHAR *buffer;
2626
2627 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
2628 if (buffer != NULL) {
2629 xmlBufferWriteCHAR(buf, buffer);
2630 free(buffer);
2631 }
2632 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002633 if (cur->childs != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002634 xmlNodeListDump(buf, doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002635 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002636 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002637 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002638 xmlBufferWriteCHAR(buf, cur->ns->prefix);
2639 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002640 }
2641
Daniel Veillard5099ae81999-04-21 20:12:07 +00002642 xmlBufferWriteCHAR(buf, cur->name);
2643 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002644}
2645
Daniel Veillard97b58771998-10-20 06:14:16 +00002646/**
2647 * xmlDocContentDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002648 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002649 * @cur: the document
2650 *
2651 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002652 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002653static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002654xmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00002655 xmlBufferWriteChar(buf, "<?xml version=");
2656 if (cur->version != NULL)
2657 xmlBufferWriteQuotedString(buf, cur->version);
2658 else
2659 xmlBufferWriteChar(buf, "\"1.0\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002660 if (cur->encoding != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002661 xmlBufferWriteChar(buf, " encoding=");
2662 xmlBufferWriteQuotedString(buf, cur->encoding);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002663 }
2664 switch (cur->standalone) {
2665 case 0:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002666 xmlBufferWriteChar(buf, " standalone=\"no\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002667 break;
2668 case 1:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002669 xmlBufferWriteChar(buf, " standalone=\"yes\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002670 break;
2671 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002672 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002673 if (cur->intSubset != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002674 xmlDtdDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002675 if (cur->root != NULL) {
2676 /* global namespace definitions, the old way */
2677 if (oldXMLWDcompatibility)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002678 xmlGlobalNsListDump(buf, cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002679 else
2680 xmlUpgradeOldNs(cur);
Daniel Veillard5099ae81999-04-21 20:12:07 +00002681 xmlNodeDump(buf, cur, cur->root, 0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002682 }
2683}
2684
Daniel Veillard97b58771998-10-20 06:14:16 +00002685/**
2686 * xmlDocDumpMemory:
2687 * @cur: the document
2688 * @mem: OUT: the memory pointer
2689 * @size: OUT: the memory lenght
2690 *
2691 * Dump an XML document in memory and return the CHAR * and it's size.
2692 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002693 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002694void
2695xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002696 xmlBufferPtr buf;
2697
Daniel Veillard260a68f1998-08-13 03:39:55 +00002698 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002699#ifdef DEBUG_TREE
2700 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
2701#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002702 *mem = NULL;
2703 *size = 0;
2704 return;
2705 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002706 buf = xmlBufferCreate();
2707 if (buf == NULL) {
2708 *mem = NULL;
2709 *size = 0;
2710 return;
2711 }
2712 xmlDocContentDump(buf, cur);
2713 *mem = buf->content;
2714 *size = buf->use;
2715 memset(buf, -1, sizeof(xmlBuffer));
2716 free(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002717}
2718
Daniel Veillard97b58771998-10-20 06:14:16 +00002719/**
2720 * xmlGetDocCompressMode:
2721 * @doc: the document
2722 *
2723 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00002724 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002725 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002726int
2727 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002728 if (doc == NULL) return(-1);
2729 return(doc->compression);
2730}
2731
Daniel Veillard97b58771998-10-20 06:14:16 +00002732/**
2733 * xmlSetDocCompressMode:
2734 * @doc: the document
2735 * @mode: the compression ratio
2736 *
2737 * set the compression ratio for a document, ZLIB based
2738 * Correct values: 0 (uncompressed) to 9 (max compression)
2739 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002740void
2741xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002742 if (doc == NULL) return;
2743 if (mode < 0) doc->compression = 0;
2744 else if (mode > 9) doc->compression = 9;
2745 else doc->compression = mode;
2746}
2747
Daniel Veillard97b58771998-10-20 06:14:16 +00002748/**
2749 * xmlGetCompressMode:
2750 *
2751 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002752 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002753 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002754int
2755 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002756 return(xmlCompressMode);
2757}
Daniel Veillard97b58771998-10-20 06:14:16 +00002758
2759/**
2760 * xmlSetCompressMode:
2761 * @mode: the compression ratio
2762 *
2763 * set the default compression mode used, ZLIB based
2764 * Correct values: 0 (uncompressed) to 9 (max compression)
2765 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002766void
2767xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002768 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002769 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002770 else xmlCompressMode = mode;
2771}
2772
Daniel Veillard97b58771998-10-20 06:14:16 +00002773/**
2774 * xmlDocDump:
2775 * @f: the FILE*
2776 * @cur: the document
2777 *
2778 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002779 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002780void
2781xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002782 xmlBufferPtr buf;
2783
Daniel Veillard260a68f1998-08-13 03:39:55 +00002784 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002785#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002786 fprintf(stderr, "xmlDocDump : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002787#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002788 return;
2789 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002790 buf = xmlBufferCreate();
2791 if (buf == NULL) return;
2792 xmlDocContentDump(buf, cur);
2793 xmlBufferDump(f, buf);
2794 xmlBufferFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002795}
2796
Daniel Veillard97b58771998-10-20 06:14:16 +00002797/**
2798 * xmlSaveFile:
2799 * @filename: the filename
2800 * @cur: the document
2801 *
2802 * Dump an XML document to a file. Will use compression if
2803 * compiled in and enabled.
2804 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002805 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002806int
2807xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002808 xmlBufferPtr buf;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002809#ifdef HAVE_ZLIB_H
2810 gzFile zoutput = NULL;
2811 char mode[15];
2812#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002813 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002814 int ret;
2815
Daniel Veillard5099ae81999-04-21 20:12:07 +00002816 /*
2817 * save the content to a temp buffer.
2818 */
2819 buf = xmlBufferCreate();
2820 if (buf == NULL) return(0);
2821 xmlDocContentDump(buf, cur);
2822
Daniel Veillard151b1b01998-09-23 00:49:46 +00002823#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002824 if ((cur->compression > 0) && (cur->compression <= 9)) {
2825 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002826 zoutput = gzopen(filename, mode);
2827 }
2828 if (zoutput == NULL) {
2829#endif
2830 output = fopen(filename, "w");
2831 if (output == NULL) return(-1);
2832#ifdef HAVE_ZLIB_H
2833 }
Daniel Veillard151b1b01998-09-23 00:49:46 +00002834
Daniel Veillard151b1b01998-09-23 00:49:46 +00002835 if (zoutput != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002836 ret = gzwrite(zoutput, buf->content, sizeof(CHAR) * buf->use);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002837 gzclose(zoutput);
Daniel Veillard5099ae81999-04-21 20:12:07 +00002838 } else {
2839#endif
2840 ret = xmlBufferDump(output, buf);
2841 fclose(output);
2842#ifdef HAVE_ZLIB_H
Daniel Veillard151b1b01998-09-23 00:49:46 +00002843 }
2844#endif
Manish Vachharajani5e60f5a1999-05-29 03:04:30 +00002845 xmlBufferFree(buf);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002846 return(ret * sizeof(CHAR));
2847}
2848