blob: 86fd4ff7f629bc524f0932e55b86db7d7d504e93 [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * tree.c : implemetation of access function for an XML tree.
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00006 * TODO Cleanup the Dump mechanism.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00007 *
8 * Daniel.Veillard@w3.org
Daniel Veillard260a68f1998-08-13 03:39:55 +00009 */
10
Daniel Veillard151b1b01998-09-23 00:49:46 +000011#include "config.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000012#include <stdio.h>
13#include <ctype.h>
Seth Alvese7f12e61998-10-01 20:51:15 +000014#include <stdlib.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000015#include <string.h> /* for memset() only ! */
16
Daniel Veillard151b1b01998-09-23 00:49:46 +000017#ifdef HAVE_ZLIB_H
18#include <zlib.h>
19#endif
20
Daniel Veillard260a68f1998-08-13 03:39:55 +000021#include "tree.h"
22#include "entities.h"
Daniel Veillard3b9def11999-01-31 22:15:06 +000023#include "valid.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000024
25static CHAR xmlStringText[] = { 't', 'e', 'x', 't', 0 };
26int oldXMLWDcompatibility = 0;
27int xmlIndentTreeOutput = 1;
28
Daniel Veillard15a8df41998-09-24 19:15:06 +000029static int xmlCompressMode = 0;
30
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000031#define UPDATE_LAST_CHILD(n) if ((n) != NULL) { \
32 xmlNodePtr ulccur = (n)->childs; \
33 if (ulccur == NULL) { \
34 (n)->last = NULL; \
35 } else { \
36 while (ulccur->next != NULL) ulccur = ulccur->next; \
37 (n)->last = ulccur; \
Daniel Veillard1e346af1999-02-22 10:33:01 +000038}}
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000039
Daniel Veillard260a68f1998-08-13 03:39:55 +000040/************************************************************************
41 * *
42 * Allocation and deallocation of basic structures *
43 * *
44 ************************************************************************/
45
Daniel Veillard97b58771998-10-20 06:14:16 +000046/**
47 * xmlUpgradeOldNs:
48 * @doc: a document pointer
49 *
50 * Upgrade old style Namespaces (PI) and move them to the root of the document.
Daniel Veillard260a68f1998-08-13 03:39:55 +000051 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000052void
53xmlUpgradeOldNs(xmlDocPtr doc) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000054 xmlNsPtr cur;
55
56 if ((doc == NULL) || (doc->oldNs == NULL)) return;
57 if (doc->root == NULL) {
58 fprintf(stderr, "xmlUpgradeOldNs: failed no root !\n");
59 return;
60 }
61
62 cur = doc->oldNs;
63 while (cur->next != NULL) {
64 cur->type = XML_LOCAL_NAMESPACE;
65 cur = cur->next;
66 }
67 cur->type = XML_LOCAL_NAMESPACE;
68 cur->next = doc->root->nsDef;
69 doc->root->nsDef = doc->oldNs;
70 doc->oldNs = NULL;
71}
72
Daniel Veillard97b58771998-10-20 06:14:16 +000073/**
74 * xmlNewNs:
75 * @node: the element carrying the namespace
76 * @href: the URI associated
77 * @prefix: the prefix for the namespace
78 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000079 * Creation of a new Namespace.
Daniel Veillard1e346af1999-02-22 10:33:01 +000080 * Returns returns a new namespace pointer
Daniel Veillard260a68f1998-08-13 03:39:55 +000081 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000082xmlNsPtr
83xmlNewNs(xmlNodePtr node, const CHAR *href, const CHAR *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000084 xmlNsPtr cur;
85
86 if (href == NULL) {
87 fprintf(stderr, "xmlNewNs: href == NULL !\n");
88 return(NULL);
89 }
90
91 /*
92 * Allocate a new DTD and fill the fields.
93 */
94 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
95 if (cur == NULL) {
96 fprintf(stderr, "xmlNewNs : malloc failed\n");
97 return(NULL);
98 }
99
100 cur->type = XML_LOCAL_NAMESPACE;
101 if (href != NULL)
102 cur->href = xmlStrdup(href);
103 else
104 cur->href = NULL;
105 if (prefix != NULL)
106 cur->prefix = xmlStrdup(prefix);
107 else
108 cur->prefix = NULL;
109
110 /*
111 * Add it at the end to preserve parsing order ...
112 */
113 cur->next = NULL;
114 if (node != NULL) {
115 if (node->nsDef == NULL) {
116 node->nsDef = cur;
117 } else {
118 xmlNsPtr prev = node->nsDef;
119
120 while (prev->next != NULL) prev = prev->next;
121 prev->next = cur;
122 }
123 }
124
125 return(cur);
126}
127
Daniel Veillard97b58771998-10-20 06:14:16 +0000128/**
129 * xmlNewGlobalNs:
130 * @doc: the document carrying the namespace
131 * @href: the URI associated
132 * @prefix: the prefix for the namespace
133 *
134 * Creation of a Namespace, the old way using PI and without scoping, to AVOID.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000135 * Returns returns a new namespace pointer
Daniel Veillard260a68f1998-08-13 03:39:55 +0000136 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000137xmlNsPtr
138xmlNewGlobalNs(xmlDocPtr doc, const CHAR *href, const CHAR *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000139 xmlNsPtr cur;
140
141 /*
142 * Allocate a new DTD and fill the fields.
143 */
144 cur = (xmlNsPtr) malloc(sizeof(xmlNs));
145 if (cur == NULL) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000146 fprintf(stderr, "xmlNewGlobalNs : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000147 return(NULL);
148 }
149
150 cur->type = XML_GLOBAL_NAMESPACE;
151 if (href != NULL)
152 cur->href = xmlStrdup(href);
153 else
154 cur->href = NULL;
155 if (prefix != NULL)
156 cur->prefix = xmlStrdup(prefix);
157 else
158 cur->prefix = NULL;
159
160 /*
161 * Add it at the end to preserve parsing order ...
162 */
163 cur->next = NULL;
164 if (doc != NULL) {
165 if (doc->oldNs == NULL) {
166 doc->oldNs = cur;
167 } else {
168 xmlNsPtr prev = doc->oldNs;
169
170 while (prev->next != NULL) prev = prev->next;
171 prev->next = cur;
172 }
173 }
174
175 return(cur);
176}
177
Daniel Veillard97b58771998-10-20 06:14:16 +0000178/**
179 * xmlSetNs:
180 * @node: a node in the document
181 * @ns: a namespace pointer
182 *
183 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000184 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000185void
186xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000187 if (node == NULL) {
188 fprintf(stderr, "xmlSetNs: node == NULL\n");
189 return;
190 }
191 node->ns = ns;
192}
193
Daniel Veillard97b58771998-10-20 06:14:16 +0000194/**
195 * xmlFreeNs:
196 * @cur: the namespace pointer
197 *
198 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000199 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000200void
201xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000202 if (cur == NULL) {
203 fprintf(stderr, "xmlFreeNs : ns == NULL\n");
204 return;
205 }
206 if (cur->href != NULL) free((char *) cur->href);
207 if (cur->prefix != NULL) free((char *) cur->prefix);
208 memset(cur, -1, sizeof(xmlNs));
209 free(cur);
210}
211
Daniel Veillard97b58771998-10-20 06:14:16 +0000212/**
213 * xmlFreeNsList:
214 * @cur: the first namespace pointer
215 *
216 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000217 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000218void
219xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000220 xmlNsPtr next;
221 if (cur == NULL) {
222 fprintf(stderr, "xmlFreeNsList : ns == NULL\n");
223 return;
224 }
225 while (cur != NULL) {
226 next = cur->next;
227 xmlFreeNs(cur);
228 cur = next;
229 }
230}
231
Daniel Veillard97b58771998-10-20 06:14:16 +0000232/**
233 * xmlNewDtd:
234 * @doc: the document pointer
235 * @name: the DTD name
236 * @ExternalID: the external ID
237 * @SystemID: the system ID
238 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000239 * Creation of a new DTD.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000240 * Returns a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000241 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000242xmlDtdPtr
243xmlNewDtd(xmlDocPtr doc, const CHAR *name,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000244 const CHAR *ExternalID, const CHAR *SystemID) {
245 xmlDtdPtr cur;
246
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000247 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000248 fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000249 /* !!! */ (char *) name, doc->name,
250 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000251 }
252
253 /*
254 * Allocate a new DTD and fill the fields.
255 */
256 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
257 if (cur == NULL) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000258 fprintf(stderr, "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000259 return(NULL);
260 }
261
262 if (name != NULL)
263 cur->name = xmlStrdup(name);
264 else
265 cur->name = NULL;
266 if (ExternalID != NULL)
267 cur->ExternalID = xmlStrdup(ExternalID);
268 else
269 cur->ExternalID = NULL;
270 if (SystemID != NULL)
271 cur->SystemID = xmlStrdup(SystemID);
272 else
273 cur->SystemID = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000274 cur->notations = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000275 cur->elements = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000276 cur->attributes = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000277 cur->entities = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000278 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000279 doc->extSubset = cur;
280
281 return(cur);
282}
283
284/**
285 * xmlCreateIntSubset:
286 * @doc: the document pointer
287 * @name: the DTD name
288 * @ExternalID: the external ID
289 * @SystemID: the system ID
290 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000291 * Create the internal subset of a document
292 * Returns a pointer to the new DTD structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000293 */
294xmlDtdPtr
295xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
296 const CHAR *ExternalID, const CHAR *SystemID) {
297 xmlDtdPtr cur;
298
299 if ((doc != NULL) && (doc->intSubset != NULL)) {
300 fprintf(stderr,
301 "xmlCreateIntSubset(): document %s already have an internal subset\n",
302 doc->name);
303 return(NULL);
304 }
305
306 /*
307 * Allocate a new DTD and fill the fields.
308 */
309 cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
310 if (cur == NULL) {
311 fprintf(stderr, "xmlNewDtd : malloc failed\n");
312 return(NULL);
313 }
314
315 if (name != NULL)
316 cur->name = xmlStrdup(name);
317 else
318 cur->name = NULL;
319 if (ExternalID != NULL)
320 cur->ExternalID = xmlStrdup(ExternalID);
321 else
322 cur->ExternalID = NULL;
323 if (SystemID != NULL)
324 cur->SystemID = xmlStrdup(SystemID);
325 else
326 cur->SystemID = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000327 cur->notations = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000328 cur->elements = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000329 cur->attributes = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000330 cur->entities = NULL;
331 if (doc != NULL)
332 doc->intSubset = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000333
334 return(cur);
335}
336
Daniel Veillard97b58771998-10-20 06:14:16 +0000337/**
338 * xmlFreeDtd:
339 * @cur: the DTD structure to free up
340 *
341 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000342 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000343void
344xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000345 if (cur == NULL) {
346 fprintf(stderr, "xmlFreeDtd : DTD == NULL\n");
347 return;
348 }
349 if (cur->name != NULL) free((char *) cur->name);
350 if (cur->SystemID != NULL) free((char *) cur->SystemID);
351 if (cur->ExternalID != NULL) free((char *) cur->ExternalID);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000352 if (cur->notations != NULL)
353 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000354 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000355 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000356 if (cur->attributes != NULL)
357 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000358 if (cur->entities != NULL)
359 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
360 memset(cur, -1, sizeof(xmlDtd));
361 free(cur);
362}
363
Daniel Veillard97b58771998-10-20 06:14:16 +0000364/**
365 * xmlNewDoc:
366 * @version: CHAR string giving the version of XML "1.0"
367 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000368 * Returns a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000369 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000370xmlDocPtr
371xmlNewDoc(const CHAR *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000372 xmlDocPtr cur;
373
374 if (version == NULL) {
375 fprintf(stderr, "xmlNewDoc : version == NULL\n");
376 return(NULL);
377 }
378
379 /*
380 * Allocate a new document and fill the fields.
381 */
382 cur = (xmlDocPtr) malloc(sizeof(xmlDoc));
383 if (cur == NULL) {
384 fprintf(stderr, "xmlNewDoc : malloc failed\n");
385 return(NULL);
386 }
387
Daniel Veillard33942841998-10-18 19:12:41 +0000388 cur->type = XML_DOCUMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000389 cur->version = xmlStrdup(version);
390 cur->name = NULL;
391 cur->root = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000392 cur->intSubset = NULL;
393 cur->extSubset = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000394 cur->oldNs = NULL;
395 cur->encoding = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000396 cur->standalone = -1;
Daniel Veillard15a8df41998-09-24 19:15:06 +0000397 cur->compression = xmlCompressMode;
Daniel Veillard27d88741999-05-29 11:51:49 +0000398#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000399 cur->_private = NULL;
400 cur->vepv = NULL;
401#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000402 return(cur);
403}
404
Daniel Veillard97b58771998-10-20 06:14:16 +0000405/**
406 * xmlFreeDoc:
407 * @cur: pointer to the document
408 * @:
409 *
410 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000411 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000412void
413xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000414 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000415#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000416 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000417#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000418 return;
419 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000420 if (cur->version != NULL) free((char *) cur->version);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000421 if (cur->name != NULL) free((char *) cur->name);
422 if (cur->encoding != NULL) free((char *) cur->encoding);
423 if (cur->root != NULL) xmlFreeNode(cur->root);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000424 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
425 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000426 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000427 memset(cur, -1, sizeof(xmlDoc));
428 free(cur);
429}
430
Daniel Veillard97b58771998-10-20 06:14:16 +0000431/**
Daniel Veillard16253641998-10-28 22:58:05 +0000432 * xmlStringLenGetNodeList:
433 * @doc: the document
434 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000435 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000436 *
437 * Parse the value string and build the node list associated. Should
438 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000439 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000440 */
441xmlNodePtr
442xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
443 xmlNodePtr ret = NULL, last = NULL;
444 xmlNodePtr node;
445 CHAR *val;
446 const CHAR *cur = value;
447 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000448 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000449
450 if (value == NULL) return(NULL);
451
452 q = cur;
453 while ((*cur != 0) && (cur - value < len)) {
454 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000455 /*
456 * Save the current text.
457 */
Daniel Veillard16253641998-10-28 22:58:05 +0000458 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000459 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
460 xmlNodeAddContentLen(last, q, cur - q);
461 } else {
462 node = xmlNewDocTextLen(doc, q, cur - q);
463 if (node == NULL) return(ret);
464 if (last == NULL)
465 last = ret = node;
466 else {
467 last->next = node;
468 node->prev = last;
469 last = node;
470 }
Daniel Veillard16253641998-10-28 22:58:05 +0000471 }
472 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000473 /*
474 * Read the entity string
475 */
Daniel Veillard16253641998-10-28 22:58:05 +0000476 cur++;
477 q = cur;
478 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
479 if ((*cur == 0) || (cur - value >= len)) {
480 fprintf(stderr,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000481 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillard16253641998-10-28 22:58:05 +0000482 return(ret);
483 }
484 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000485 /*
486 * Predefined entities don't generate nodes
487 */
Daniel Veillard16253641998-10-28 22:58:05 +0000488 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000489 ent = xmlGetDocEntity(doc, val);
490 if ((ent != NULL) &&
491 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
492 if (last == NULL) {
493 node = xmlNewDocText(doc, ent->content);
494 last = ret = node;
495 } else
496 xmlNodeAddContent(last, ent->content);
497
498 } else {
499 /*
500 * Create a new REFERENCE_REF node
501 */
502 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000503 if (node == NULL) {
504 if (val != NULL) free(val);
505 return(ret);
506 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000507 if (last == NULL)
508 last = ret = node;
509 else {
510 last->next = node;
511 node->prev = last;
512 last = node;
513 }
Daniel Veillard16253641998-10-28 22:58:05 +0000514 }
515 free(val);
516 }
517 cur++;
518 q = cur;
519 } else
520 cur++;
521 }
522 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000523 /*
524 * Handle the last piece of text.
525 */
526 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
527 xmlNodeAddContentLen(last, q, cur - q);
528 } else {
529 node = xmlNewDocTextLen(doc, q, cur - q);
530 if (node == NULL) return(ret);
531 if (last == NULL)
532 last = ret = node;
533 else {
534 last->next = node;
535 node->prev = last;
536 last = node;
537 }
Daniel Veillard16253641998-10-28 22:58:05 +0000538 }
539 }
540 return(ret);
541}
542
543/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000544 * xmlStringGetNodeList:
545 * @doc: the document
546 * @value: the value of the attribute
547 *
548 * Parse the value string and build the node list associated. Should
549 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000550 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000551 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000552xmlNodePtr
553xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000554 xmlNodePtr ret = NULL, last = NULL;
555 xmlNodePtr node;
556 CHAR *val;
557 const CHAR *cur = value;
558 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000559 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000560
561 if (value == NULL) return(NULL);
562
563 q = cur;
564 while (*cur != 0) {
565 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000566 /*
567 * Save the current text.
568 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000569 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000570 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
571 xmlNodeAddContentLen(last, q, cur - q);
572 } else {
573 node = xmlNewDocTextLen(doc, q, cur - q);
574 if (node == NULL) return(ret);
575 if (last == NULL)
576 last = ret = node;
577 else {
578 last->next = node;
579 node->prev = last;
580 last = node;
581 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000582 }
583 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000584 /*
585 * Read the entity string
586 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000587 cur++;
588 q = cur;
589 while ((*cur != 0) && (*cur != ';')) cur++;
590 if (*cur == 0) {
591 fprintf(stderr,
592 "xmlStringGetNodeList: unterminated entity %30s\n", q);
593 return(ret);
594 }
595 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000596 /*
597 * Predefined entities don't generate nodes
598 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000599 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000600 ent = xmlGetDocEntity(doc, val);
601 if ((ent != NULL) &&
602 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
603 if (last == NULL) {
604 node = xmlNewDocText(doc, ent->content);
605 last = ret = node;
606 } else
607 xmlNodeAddContent(last, ent->content);
608
609 } else {
610 /*
611 * Create a new REFERENCE_REF node
612 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000613 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000614 if (node == NULL) {
615 if (val != NULL) free(val);
616 return(ret);
617 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000618 if (last == NULL)
619 last = ret = node;
620 else {
621 last->next = node;
622 node->prev = last;
623 last = node;
624 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000625 }
626 free(val);
627 }
628 cur++;
629 q = cur;
630 } else
631 cur++;
632 }
633 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000634 /*
635 * Handle the last piece of text.
636 */
637 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
638 xmlNodeAddContentLen(last, q, cur - q);
639 } else {
640 node = xmlNewDocTextLen(doc, q, cur - q);
641 if (node == NULL) return(ret);
642 if (last == NULL)
643 last = ret = node;
644 else {
645 last->next = node;
646 node->prev = last;
647 last = node;
648 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000649 }
650 }
651 return(ret);
652}
653
654/**
655 * xmlNodeListGetString:
656 * @doc: the document
657 * @list: a Node list
658 * @inLine: should we replace entity contents or show their external form
659 *
660 * Returns the string equivalent to the text contained in the Node list
661 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000662 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000663 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000664CHAR *
665xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000666 xmlNodePtr node = list;
667 CHAR *ret = NULL;
668 xmlEntityPtr ent;
669
670 if (list == NULL) return(NULL);
671
672 while (node != NULL) {
673 if (node->type == XML_TEXT_NODE) {
674 if (inLine)
675 ret = xmlStrcat(ret, node->content);
Daniel Veillard14fff061999-06-22 21:49:07 +0000676 else {
677 CHAR *buffer;
678
679 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
680 if (buffer != NULL) {
681 ret = xmlStrcat(ret, buffer);
682 free(buffer);
683 }
684 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000685 } else if (node->type == XML_ENTITY_REF_NODE) {
686 if (inLine) {
687 ent = xmlGetDocEntity(doc, node->name);
688 if (ent != NULL)
689 ret = xmlStrcat(ret, ent->content);
690 else
691 ret = xmlStrcat(ret, node->content);
692 } else {
693 CHAR buf[2];
694 buf[0] = '&'; buf[1] = 0;
695 ret = xmlStrncat(ret, buf, 1);
696 ret = xmlStrcat(ret, node->name);
697 buf[0] = ';'; buf[1] = 0;
698 ret = xmlStrncat(ret, buf, 1);
699 }
700 }
701#if 0
702 else {
703 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
704 node->type);
705 }
706#endif
707 node = node->next;
708 }
709 return(ret);
710}
711
712/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000713 * xmlNewProp:
714 * @node: the holding node
715 * @name: the name of the attribute
716 * @value: the value of the attribute
717 *
718 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000719 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000720 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000721xmlAttrPtr
722xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000723 xmlAttrPtr cur;
724
725 if (name == NULL) {
726 fprintf(stderr, "xmlNewProp : name == NULL\n");
727 return(NULL);
728 }
729
730 /*
731 * Allocate a new property and fill the fields.
732 */
733 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
734 if (cur == NULL) {
735 fprintf(stderr, "xmlNewProp : malloc failed\n");
736 return(NULL);
737 }
738
Daniel Veillard33942841998-10-18 19:12:41 +0000739 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000740 cur->node = node;
741 cur->name = xmlStrdup(name);
742 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +0000743 cur->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000744 else
Daniel Veillardccb09631998-10-27 06:21:04 +0000745 cur->val = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000746#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000747 cur->_private = NULL;
748 cur->vepv = NULL;
749#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000750
751 /*
752 * Add it at the end to preserve parsing order ...
753 */
754 cur->next = NULL;
755 if (node != NULL) {
756 if (node->properties == NULL) {
757 node->properties = cur;
758 } else {
759 xmlAttrPtr prev = node->properties;
760
761 while (prev->next != NULL) prev = prev->next;
762 prev->next = cur;
763 }
764 }
765 return(cur);
766}
767
Daniel Veillard97b58771998-10-20 06:14:16 +0000768/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000769 * xmlNewDocProp:
770 * @doc: the document
771 * @name: the name of the attribute
772 * @value: the value of the attribute
773 *
774 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000775 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +0000776 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000777xmlAttrPtr
778xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000779 xmlAttrPtr cur;
780
781 if (name == NULL) {
782 fprintf(stderr, "xmlNewProp : name == NULL\n");
783 return(NULL);
784 }
785
786 /*
787 * Allocate a new property and fill the fields.
788 */
789 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
790 if (cur == NULL) {
791 fprintf(stderr, "xmlNewProp : malloc failed\n");
792 return(NULL);
793 }
794
795 cur->type = XML_ATTRIBUTE_NODE;
796 cur->node = NULL;
797 cur->name = xmlStrdup(name);
798 if (value != NULL)
799 cur->val = xmlStringGetNodeList(doc, value);
800 else
801 cur->val = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000802#ifndef XML_WITHOUT_CORBA
Daniel Veillardccb09631998-10-27 06:21:04 +0000803 cur->_private = NULL;
804 cur->vepv = NULL;
805#endif
806
807 cur->next = NULL;
808 return(cur);
809}
810
811/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000812 * xmlFreePropList:
813 * @cur: the first property in the list
814 *
815 * Free a property and all its siblings, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000816 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000817void
818xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000819 xmlAttrPtr next;
820 if (cur == NULL) {
821 fprintf(stderr, "xmlFreePropList : property == NULL\n");
822 return;
823 }
824 while (cur != NULL) {
825 next = cur->next;
826 xmlFreeProp(cur);
827 cur = next;
828 }
829}
830
Daniel Veillard97b58771998-10-20 06:14:16 +0000831/**
832 * xmlFreeProp:
833 * @cur: the first property in the list
834 *
835 * Free one property, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000836 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000837void
838xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000839 if (cur == NULL) {
840 fprintf(stderr, "xmlFreeProp : property == NULL\n");
841 return;
842 }
843 if (cur->name != NULL) free((char *) cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +0000844 if (cur->val != NULL) xmlFreeNodeList(cur->val);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000845 memset(cur, -1, sizeof(xmlAttr));
846 free(cur);
847}
848
Daniel Veillard97b58771998-10-20 06:14:16 +0000849/**
850 * xmlNewNode:
851 * @ns: namespace if any
852 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +0000853 *
854 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +0000855 * If content is non NULL, a child list containing the TEXTs and
856 * ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000857 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000858 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000859xmlNodePtr
860xmlNewNode(xmlNsPtr ns, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000861 xmlNodePtr cur;
862
863 if (name == NULL) {
864 fprintf(stderr, "xmlNewNode : name == NULL\n");
865 return(NULL);
866 }
867
868 /*
869 * Allocate a new node and fill the fields.
870 */
871 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
872 if (cur == NULL) {
873 fprintf(stderr, "xmlNewNode : malloc failed\n");
874 return(NULL);
875 }
876
Daniel Veillard33942841998-10-18 19:12:41 +0000877 cur->type = XML_ELEMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000878 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000879 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000880 cur->next = NULL;
881 cur->prev = NULL;
882 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000883 cur->last = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000884 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000885 cur->name = xmlStrdup(name);
886 cur->ns = ns;
887 cur->nsDef = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000888 cur->content = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +0000889#ifndef XML_WITHOUT_CORBA
Daniel Veillard27fb0751998-10-17 06:47:46 +0000890 cur->_private = NULL;
891 cur->vepv = NULL;
892#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000893 return(cur);
894}
895
Daniel Veillard97b58771998-10-20 06:14:16 +0000896/**
897 * xmlNewDocNode:
898 * @doc: the document
899 * @ns: namespace if any
900 * @name: the node name
901 * @content: the text content if any
902 *
903 * Creation of a new node element within a document. @ns and @content
904 * are optionnal (NULL).
Daniel Veillard1e346af1999-02-22 10:33:01 +0000905 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +0000906 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000907xmlNodePtr
908xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard15b75af1999-07-26 16:42:37 +0000909 const CHAR *name, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +0000910 xmlNodePtr cur;
911
Daniel Veillardccb09631998-10-27 06:21:04 +0000912 cur = xmlNewNode(ns, name);
913 if (cur != NULL) {
914 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000915 if (content != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000916 cur->childs = xmlStringGetNodeList(doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000917 UPDATE_LAST_CHILD(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000918 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000919 }
Daniel Veillard0bef1311998-10-14 02:36:47 +0000920 return(cur);
921}
922
923
Daniel Veillard97b58771998-10-20 06:14:16 +0000924/**
925 * xmlNewText:
926 * @content: the text content
927 *
928 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000929 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000930 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000931xmlNodePtr
932xmlNewText(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000933 xmlNodePtr cur;
934
935 /*
936 * Allocate a new node and fill the fields.
937 */
938 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
939 if (cur == NULL) {
940 fprintf(stderr, "xmlNewText : malloc failed\n");
941 return(NULL);
942 }
943
Daniel Veillard33942841998-10-18 19:12:41 +0000944 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000945 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000946 cur->parent = NULL;
947 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000948 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000949 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000950 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000951 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000952 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000953 cur->name = xmlStrdup(xmlStringText);
954 cur->ns = NULL;
955 cur->nsDef = NULL;
956 if (content != NULL)
957 cur->content = xmlStrdup(content);
958 else
959 cur->content = NULL;
960 return(cur);
961}
962
Daniel Veillard97b58771998-10-20 06:14:16 +0000963/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000964 * xmlNewReference:
965 * @doc: the document
966 * @name: the reference name, or the reference string with & and ;
967 *
968 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000969 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +0000970 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000971xmlNodePtr
972xmlNewReference(xmlDocPtr doc, const CHAR *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000973 xmlNodePtr cur;
974 xmlEntityPtr ent;
975
976 /*
977 * Allocate a new node and fill the fields.
978 */
979 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
980 if (cur == NULL) {
981 fprintf(stderr, "xmlNewText : malloc failed\n");
982 return(NULL);
983 }
984
985 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillard10c6a8f1998-10-28 01:00:12 +0000986 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +0000987 cur->parent = NULL;
988 cur->next = NULL;
989 cur->prev = NULL;
990 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000991 cur->last = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000992 cur->properties = NULL;
993 if (name[0] == '&') {
994 int len;
995 name++;
996 len = xmlStrlen(name);
997 if (name[len - 1] == ';')
998 cur->name = xmlStrndup(name, len - 1);
999 else
1000 cur->name = xmlStrndup(name, len);
1001 } else
1002 cur->name = xmlStrdup(name);
1003 cur->ns = NULL;
1004 cur->nsDef = NULL;
1005
1006 ent = xmlGetDocEntity(doc, cur->name);
1007 if (ent != NULL)
1008 cur->content = ent->content;
1009 else
1010 cur->content = NULL;
1011 return(cur);
1012}
1013
1014/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001015 * xmlNewDocText:
1016 * @doc: the document
1017 * @content: the text content
1018 *
1019 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001020 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001021 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001022xmlNodePtr
1023xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001024 xmlNodePtr cur;
1025
1026 cur = xmlNewText(content);
1027 if (cur != NULL) cur->doc = doc;
1028 return(cur);
1029}
1030
Daniel Veillard97b58771998-10-20 06:14:16 +00001031/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001032 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001033 * @content: the text content
1034 * @len: the text len.
1035 *
1036 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001037 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001038 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001039xmlNodePtr
1040xmlNewTextLen(const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001041 xmlNodePtr cur;
1042
1043 /*
1044 * Allocate a new node and fill the fields.
1045 */
1046 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1047 if (cur == NULL) {
1048 fprintf(stderr, "xmlNewText : malloc failed\n");
1049 return(NULL);
1050 }
1051
Daniel Veillard33942841998-10-18 19:12:41 +00001052 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001053 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001054 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001055 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001056 cur->next = NULL;
1057 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001058 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001059 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001060 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001061 cur->name = xmlStrdup(xmlStringText);
1062 cur->ns = NULL;
1063 cur->nsDef = NULL;
1064 if (content != NULL)
1065 cur->content = xmlStrndup(content, len);
1066 else
1067 cur->content = NULL;
1068 return(cur);
1069}
1070
Daniel Veillard97b58771998-10-20 06:14:16 +00001071/**
1072 * xmlNewDocTextLen:
1073 * @doc: the document
1074 * @content: the text content
1075 * @len: the text len.
1076 *
1077 * Creation of a new text node with an extra content lenght parameter. The
1078 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001079 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001080 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001081xmlNodePtr
1082xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001083 xmlNodePtr cur;
1084
1085 cur = xmlNewTextLen(content, len);
1086 if (cur != NULL) cur->doc = doc;
1087 return(cur);
1088}
1089
Daniel Veillard97b58771998-10-20 06:14:16 +00001090/**
1091 * xmlNewComment:
1092 * @content: the comment content
1093 *
1094 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001095 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001096 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001097xmlNodePtr
Daniel Veillard517752b1999-04-05 12:20:10 +00001098xmlNewComment(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001099 xmlNodePtr cur;
1100
1101 /*
1102 * Allocate a new node and fill the fields.
1103 */
1104 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1105 if (cur == NULL) {
1106 fprintf(stderr, "xmlNewComment : malloc failed\n");
1107 return(NULL);
1108 }
1109
Daniel Veillard33942841998-10-18 19:12:41 +00001110 cur->type = XML_COMMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001111 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001112 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001113 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001114 cur->next = NULL;
1115 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001116 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001117 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001118 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001119 cur->name = xmlStrdup(xmlStringText);
1120 cur->ns = NULL;
1121 cur->nsDef = NULL;
1122 if (content != NULL)
1123 cur->content = xmlStrdup(content);
1124 else
1125 cur->content = NULL;
1126 return(cur);
1127}
1128
Daniel Veillard97b58771998-10-20 06:14:16 +00001129/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001130 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001131 * @doc: the document
1132 * @content: the comment content
1133 *
1134 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001135 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001136 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001137xmlNodePtr
Daniel Veillard517752b1999-04-05 12:20:10 +00001138xmlNewDocComment(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001139 xmlNodePtr cur;
1140
1141 cur = xmlNewComment(content);
1142 if (cur != NULL) cur->doc = doc;
1143 return(cur);
1144}
1145
Daniel Veillard97b58771998-10-20 06:14:16 +00001146/**
1147 * xmlNewChild:
1148 * @parent: the parent node
1149 * @ns: a namespace if any
1150 * @name: the name of the child
1151 * @content: the content of the child if any.
1152 *
1153 *
1154 * Creation of a new child element, added at the end of @parent childs list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001155 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1156 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001157 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001158 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001159xmlNodePtr
1160xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard15b75af1999-07-26 16:42:37 +00001161 const CHAR *name, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001162 xmlNodePtr cur, prev;
1163
1164 if (parent == NULL) {
1165 fprintf(stderr, "xmlNewChild : parent == NULL\n");
1166 return(NULL);
1167 }
1168
1169 if (name == NULL) {
1170 fprintf(stderr, "xmlNewChild : name == NULL\n");
1171 return(NULL);
1172 }
1173
1174 /*
1175 * Allocate a new node
1176 */
1177 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001178 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001179 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001180 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001181 if (cur == NULL) return(NULL);
1182
1183 /*
1184 * add the new element at the end of the childs list.
1185 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001186 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001187 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001188 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001189 if (parent->childs == NULL) {
1190 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001191 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001192 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001193 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001194 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001195 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001196 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001197 }
1198
1199 return(cur);
1200}
1201
Daniel Veillard97b58771998-10-20 06:14:16 +00001202/**
1203 * xmlAddChild:
1204 * @parent: the parent node
1205 * @cur: the child node
1206 *
1207 * Add a new child element, to @parent, at the end of the child list.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001208 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001209 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001210xmlNodePtr
1211xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001212 xmlNodePtr prev;
1213
1214 if (parent == NULL) {
1215 fprintf(stderr, "xmladdChild : parent == NULL\n");
1216 return(NULL);
1217 }
1218
1219 if (cur == NULL) {
1220 fprintf(stderr, "xmladdChild : child == NULL\n");
1221 return(NULL);
1222 }
1223
Daniel Veillard0bef1311998-10-14 02:36:47 +00001224 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1225 (cur->doc != parent->doc)) {
1226 fprintf(stderr, "Elements moved to a different document\n");
1227 }
1228
Daniel Veillard260a68f1998-08-13 03:39:55 +00001229 /*
1230 * add the new element at the end of the childs list.
1231 */
1232 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001233 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001234
Daniel Veillardccb09631998-10-27 06:21:04 +00001235 /*
1236 * Handle the case where parent->content != NULL, in that case it will
1237 * create a intermediate TEXT node.
1238 */
1239 if (parent->content != NULL) {
1240 xmlNodePtr text;
1241
1242 text = xmlNewDocText(parent->doc, parent->content);
1243 if (text != NULL) {
1244 text->next = parent->childs;
1245 if (text->next != NULL)
1246 text->next->prev = text;
1247 parent->childs = text;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001248 UPDATE_LAST_CHILD(parent)
Daniel Veillardccb09631998-10-27 06:21:04 +00001249 free(parent->content);
1250 parent->content = NULL;
1251 }
1252 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001253 if (parent->childs == NULL) {
1254 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001255 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001256 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001257 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001258 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001259 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001260 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001261 }
1262
1263 return(cur);
1264}
1265
Daniel Veillard97b58771998-10-20 06:14:16 +00001266/**
1267 * xmlGetLastChild:
1268 * @parent: the parent node
1269 *
1270 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001271 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001272 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001273xmlNodePtr
1274xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001275 if (parent == NULL) {
1276 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1277 return(NULL);
1278 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001279 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001280}
1281
Daniel Veillard97b58771998-10-20 06:14:16 +00001282/**
1283 * xmlFreeNodeList:
1284 * @cur: the first node in the list
1285 *
1286 * Free a node and all its siblings, this is a recursive behaviour, all
1287 * the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001288 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001289void
1290xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001291 xmlNodePtr next;
1292 if (cur == NULL) {
1293 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1294 return;
1295 }
1296 while (cur != NULL) {
1297 next = cur->next;
1298 xmlFreeNode(cur);
1299 cur = next;
1300 }
1301}
1302
Daniel Veillard97b58771998-10-20 06:14:16 +00001303/**
1304 * xmlFreeNode:
1305 * @cur: the node
1306 *
1307 * Free a node, this is a recursive behaviour, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001308 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001309void
1310xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001311 if (cur == NULL) {
1312 fprintf(stderr, "xmlFreeNode : node == NULL\n");
1313 return;
1314 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001315 cur->doc = NULL;
1316 cur->parent = NULL;
1317 cur->next = NULL;
1318 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001319 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
Daniel Veillardccb09631998-10-27 06:21:04 +00001320 if (cur->properties != NULL) xmlFreePropList(cur->properties);
1321 if (cur->type != XML_ENTITY_REF_NODE)
1322 if (cur->content != NULL) free(cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001323 if (cur->name != NULL) free((char *) cur->name);
1324 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1325 memset(cur, -1, sizeof(xmlNode));
1326 free(cur);
1327}
1328
Daniel Veillard16253641998-10-28 22:58:05 +00001329/**
1330 * xmlUnlinkNode:
1331 * @cur: the node
1332 *
1333 * Unlink a node from it's current context, the node is not freed
1334 */
1335void
1336xmlUnlinkNode(xmlNodePtr cur) {
1337 if (cur == NULL) {
1338 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1339 return;
1340 }
1341 if ((cur->parent != NULL) && (cur->parent->childs == cur))
1342 cur->parent->childs = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001343 if ((cur->parent != NULL) && (cur->parent->last == cur))
1344 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00001345 if (cur->next != NULL)
1346 cur->next->prev = cur->prev;
1347 if (cur->prev != NULL)
1348 cur->prev->next = cur->next;
1349 cur->next = cur->prev = NULL;
1350 cur->parent = NULL;
1351}
1352
Daniel Veillard260a68f1998-08-13 03:39:55 +00001353/************************************************************************
1354 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001355 * Copy operations *
1356 * *
1357 ************************************************************************/
1358
1359/**
1360 * xmlCopyNamespace:
1361 * @cur: the namespace
1362 *
1363 * Do a copy of the namespace.
1364 *
1365 * Returns: a new xmlNsPtr, or NULL in case of error.
1366 */
1367xmlNsPtr
1368xmlCopyNamespace(xmlNsPtr cur) {
1369 xmlNsPtr ret;
1370
1371 if (cur == NULL) return(NULL);
1372 switch (cur->type) {
1373 case XML_GLOBAL_NAMESPACE:
1374 ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
1375 break;
1376 case XML_LOCAL_NAMESPACE:
1377 ret = xmlNewNs(NULL, cur->href, cur->prefix);
1378 break;
1379 default:
1380 fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
1381 return(NULL);
1382 }
1383 return(ret);
1384}
1385
1386/**
1387 * xmlCopyNamespaceList:
1388 * @cur: the first namespace
1389 *
1390 * Do a copy of an namespace list.
1391 *
1392 * Returns: a new xmlNsPtr, or NULL in case of error.
1393 */
1394xmlNsPtr
1395xmlCopyNamespaceList(xmlNsPtr cur) {
1396 xmlNsPtr ret = NULL;
1397 xmlNsPtr p = NULL,q;
1398
1399 while (cur != NULL) {
1400 q = xmlCopyNamespace(cur);
1401 if (p == NULL) {
1402 ret = p = q;
1403 } else {
1404 p->next = q;
1405 p = q;
1406 }
1407 cur = cur->next;
1408 }
1409 return(ret);
1410}
1411
1412/**
1413 * xmlCopyProp:
1414 * @cur: the attribute
1415 *
1416 * Do a copy of the attribute.
1417 *
1418 * Returns: a new xmlAttrPtr, or NULL in case of error.
1419 */
1420xmlAttrPtr
1421xmlCopyProp(xmlAttrPtr cur) {
1422 xmlAttrPtr ret;
1423
1424 if (cur == NULL) return(NULL);
1425 if (cur->val != NULL)
1426 ret = xmlNewDocProp(cur->val->doc, cur->name, NULL);
1427 else
1428 ret = xmlNewDocProp(NULL, cur->name, NULL);
1429 if (ret == NULL) return(NULL);
1430 if (cur->val != NULL)
1431 ret->val = xmlCopyNodeList(cur->val);
1432 return(ret);
1433}
1434
1435/**
1436 * xmlCopyPropList:
1437 * @cur: the first attribute
1438 *
1439 * Do a copy of an attribute list.
1440 *
1441 * Returns: a new xmlAttrPtr, or NULL in case of error.
1442 */
1443xmlAttrPtr
1444xmlCopyPropList(xmlAttrPtr cur) {
1445 xmlAttrPtr ret = NULL;
1446 xmlAttrPtr p = NULL,q;
1447
1448 while (cur != NULL) {
1449 q = xmlCopyProp(cur);
1450 if (p == NULL) {
1451 ret = p = q;
1452 } else {
1453 p->next = q;
1454 p = q;
1455 }
1456 cur = cur->next;
1457 }
1458 return(ret);
1459}
1460
1461/*
1462 * NOTE about the CopyNode operations !
1463 *
1464 * They are splitted into external and internal parts for one
1465 * tricky reason: namespaces. Doing a direct copy of a node
1466 * say RPM:Copyright without changing the namespace pointer to
1467 * something else can produce stale links. One way to do it is
1468 * to keep a reference counter but this doesn't work as soon
1469 * as one move the element or the subtree out of the scope of
1470 * the existing namespace. The actual solution seems to add
1471 * a copy of the namespace at the top of the copied tree if
1472 * not available in the subtree.
1473 * Hence two functions, the public front-end call the inner ones
1474 */
1475
1476static xmlNodePtr
1477xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
1478
1479static xmlNodePtr
1480xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
1481 int recursive) {
1482 xmlNodePtr ret;
1483
1484 if (node == NULL) return(NULL);
1485 /*
1486 * Allocate a new node and fill the fields.
1487 */
1488 ret = (xmlNodePtr) malloc(sizeof(xmlNode));
1489 if (ret == NULL) {
1490 fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
1491 return(NULL);
1492 }
1493
1494 ret->type = node->type;
1495 ret->doc = doc;
1496 ret->parent = parent;
1497 ret->next = NULL;
1498 ret->prev = NULL;
1499 ret->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001500 ret->last = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001501 ret->properties = NULL;
1502 if (node->name != NULL)
1503 ret->name = xmlStrdup(node->name);
1504 else
1505 ret->name = NULL;
1506 ret->ns = NULL;
1507 ret->nsDef = NULL;
1508 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE))
1509 ret->content = xmlStrdup(node->content);
1510 else
1511 ret->content = NULL;
Daniel Veillard27d88741999-05-29 11:51:49 +00001512#ifndef XML_WITHOUT_CORBA
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001513 ret->_private = NULL;
1514 ret->vepv = NULL;
1515#endif
1516 if (parent != NULL)
1517 xmlAddChild(parent, ret);
1518
1519 if (!recursive) return(ret);
1520 if (node->properties != NULL)
1521 ret->properties = xmlCopyPropList(node->properties);
1522 if (node->nsDef != NULL)
1523 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
1524
1525 if (node->ns != NULL) {
1526 xmlNsPtr ns;
1527
1528 ns = xmlSearchNs(doc, ret, node->ns->prefix);
1529 if (ns == NULL) {
1530 /*
1531 * Humm, we are copying an element whose namespace is defined
1532 * out of the new tree scope. Search it in the original tree
1533 * and add it at the top of the new tree
1534 */
1535 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
1536 if (ns != NULL) {
1537 xmlNodePtr root = ret;
1538
1539 while (root->parent != NULL) root = root->parent;
1540 xmlNewNs(root, ns->href, ns->prefix);
1541 }
1542 } else {
1543 /*
1544 * reference the existing namespace definition in our own tree.
1545 */
1546 ret->ns = ns;
1547 }
1548 }
1549 if (node->childs != NULL)
1550 ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001551 UPDATE_LAST_CHILD(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001552 return(ret);
1553}
1554
1555static xmlNodePtr
1556xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
1557 xmlNodePtr ret = NULL;
1558 xmlNodePtr p = NULL,q;
1559
1560 while (node != NULL) {
1561 q = xmlStaticCopyNode(node, doc, parent, 1);
1562 if (parent == NULL) {
1563 if (ret == NULL) ret = q;
1564 } else {
1565 if (ret == NULL) {
1566 q->prev = NULL;
1567 ret = p = q;
1568 } else {
1569 p->next = q;
1570 q->prev = p;
1571 p = q;
1572 }
1573 }
1574 node = node->next;
1575 }
1576 return(ret);
1577}
1578
1579/**
1580 * xmlCopyNode:
1581 * @node: the node
1582 * @recursive: if 1 do a recursive copy.
1583 *
1584 * Do a copy of the node.
1585 *
1586 * Returns: a new xmlNodePtr, or NULL in case of error.
1587 */
1588xmlNodePtr
1589xmlCopyNode(xmlNodePtr node, int recursive) {
1590 xmlNodePtr ret;
1591
1592 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
1593 return(ret);
1594}
1595
1596/**
1597 * xmlCopyNodeList:
1598 * @node: the first node in the list.
1599 *
1600 * Do a recursive copy of the node list.
1601 *
1602 * Returns: a new xmlNodePtr, or NULL in case of error.
1603 */
1604xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
1605 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
1606 return(ret);
1607}
1608
1609/**
1610 * xmlCopyElement:
1611 * @elem: the element
1612 *
1613 * Do a copy of the element definition.
1614 *
1615 * Returns: a new xmlElementPtr, or NULL in case of error.
1616xmlElementPtr
1617xmlCopyElement(xmlElementPtr elem) {
1618 xmlElementPtr ret;
1619
1620 if (elem == NULL) return(NULL);
1621 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
1622 if (ret == NULL) return(NULL);
1623 if (!recursive) return(ret);
1624 if (elem->properties != NULL)
1625 ret->properties = xmlCopyPropList(elem->properties);
1626
1627 if (elem->nsDef != NULL)
1628 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
1629 if (elem->childs != NULL)
1630 ret->childs = xmlCopyElementList(elem->childs);
1631 return(ret);
1632}
1633 */
1634
1635/**
1636 * xmlCopyDtd:
1637 * @dtd: the dtd
1638 *
1639 * Do a copy of the dtd.
1640 *
1641 * Returns: a new xmlDtdPtr, or NULL in case of error.
1642 */
1643xmlDtdPtr
1644xmlCopyDtd(xmlDtdPtr dtd) {
1645 xmlDtdPtr ret;
1646
1647 if (dtd == NULL) return(NULL);
1648 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
1649 if (ret == NULL) return(NULL);
1650 if (dtd->entities != NULL)
1651 ret->entities = (void *) xmlCopyEntitiesTable(
1652 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001653 if (dtd->notations != NULL)
1654 ret->notations = (void *) xmlCopyNotationTable(
1655 (xmlNotationTablePtr) dtd->notations);
1656 if (dtd->elements != NULL)
1657 ret->elements = (void *) xmlCopyElementTable(
1658 (xmlElementTablePtr) dtd->elements);
1659 if (dtd->attributes != NULL)
1660 ret->attributes = (void *) xmlCopyAttributeTable(
1661 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001662 /*
1663 * TODO: support for Element definitions.
1664 */
1665 return(ret);
1666}
1667
1668/**
1669 * xmlCopyDoc:
1670 * @doc: the document
1671 * @recursive: if 1 do a recursive copy.
1672 *
1673 * Do a copy of the document info. If recursive, the content tree will
1674 * be copied too as well as Dtd, namespaces and entities.
1675 *
1676 * Returns: a new xmlDocPtr, or NULL in case of error.
1677 */
1678xmlDocPtr
1679xmlCopyDoc(xmlDocPtr doc, int recursive) {
1680 xmlDocPtr ret;
1681
1682 if (doc == NULL) return(NULL);
1683 ret = xmlNewDoc(doc->version);
1684 if (ret == NULL) return(NULL);
1685 if (doc->name != NULL)
1686 ret->name = strdup(doc->name);
1687 if (doc->encoding != NULL)
1688 ret->encoding = xmlStrdup(doc->encoding);
1689 ret->compression = doc->compression;
1690 ret->standalone = doc->standalone;
1691 if (!recursive) return(ret);
1692
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001693 if (doc->intSubset != NULL)
1694 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001695 if (doc->oldNs != NULL)
1696 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
1697 if (doc->root != NULL)
1698 ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL);
1699 return(ret);
1700}
1701
1702/************************************************************************
1703 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001704 * Content access functions *
1705 * *
1706 ************************************************************************/
1707
Daniel Veillard97b58771998-10-20 06:14:16 +00001708/**
Daniel Veillard16253641998-10-28 22:58:05 +00001709 * xmlNodeGetContent:
1710 * @cur: the node being read
1711 *
1712 * Read the value of a node, this can be either the text carried
1713 * directly by this node if it's a TEXT node or the aggregate string
1714 * of the values carried by this node child's (TEXT and ENTITY_REF).
1715 * Entity references are substitued.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001716 * Returns a new CHAR * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00001717 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00001718 */
1719CHAR *
1720xmlNodeGetContent(xmlNodePtr cur) {
1721 if (cur == NULL) return(NULL);
1722 switch (cur->type) {
1723 case XML_DOCUMENT_FRAG_NODE:
1724 case XML_ELEMENT_NODE:
1725 return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1726 break;
1727 case XML_ATTRIBUTE_NODE:
1728 case XML_CDATA_SECTION_NODE:
1729 case XML_ENTITY_REF_NODE:
1730 case XML_ENTITY_NODE:
1731 case XML_PI_NODE:
1732 case XML_COMMENT_NODE:
1733 case XML_DOCUMENT_NODE:
1734 case XML_DOCUMENT_TYPE_NODE:
1735 case XML_NOTATION_NODE:
1736 return(NULL);
1737 case XML_TEXT_NODE:
1738 if (cur->content != NULL)
1739 return(xmlStrdup(cur->content));
1740 return(NULL);
1741 }
1742 return(NULL);
1743}
1744
1745/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001746 * xmlNodeSetContent:
1747 * @cur: the node being modified
1748 * @content: the new value of the content
1749 *
1750 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001751 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001752void
1753xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001754 if (cur == NULL) {
1755 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1756 return;
1757 }
Daniel Veillard16253641998-10-28 22:58:05 +00001758 switch (cur->type) {
1759 case XML_DOCUMENT_FRAG_NODE:
1760 case XML_ELEMENT_NODE:
1761 if (cur->content != NULL) {
1762 free(cur->content);
1763 cur->content = NULL;
1764 }
1765 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1766 cur->childs = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001767 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001768 break;
1769 case XML_ATTRIBUTE_NODE:
1770 break;
1771 case XML_TEXT_NODE:
1772 case XML_CDATA_SECTION_NODE:
1773 case XML_ENTITY_REF_NODE:
1774 case XML_ENTITY_NODE:
1775 case XML_PI_NODE:
1776 case XML_COMMENT_NODE:
1777 if (cur->content != NULL) free(cur->content);
1778 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001779 cur->last = cur->childs = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001780 if (content != NULL)
1781 cur->content = xmlStrdup(content);
1782 else
1783 cur->content = NULL;
1784 case XML_DOCUMENT_NODE:
1785 case XML_DOCUMENT_TYPE_NODE:
1786 break;
1787 case XML_NOTATION_NODE:
1788 break;
1789 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001790}
1791
Daniel Veillard97b58771998-10-20 06:14:16 +00001792/**
1793 * xmlNodeSetContentLen:
1794 * @cur: the node being modified
1795 * @content: the new value of the content
1796 * @len: the size of @content
1797 *
1798 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001799 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001800void
1801xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001802 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001803 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001804 return;
1805 }
Daniel Veillard16253641998-10-28 22:58:05 +00001806 switch (cur->type) {
1807 case XML_DOCUMENT_FRAG_NODE:
1808 case XML_ELEMENT_NODE:
1809 if (cur->content != NULL) {
1810 free(cur->content);
1811 cur->content = NULL;
1812 }
1813 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1814 cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001815 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001816 break;
1817 case XML_ATTRIBUTE_NODE:
1818 break;
1819 case XML_TEXT_NODE:
1820 case XML_CDATA_SECTION_NODE:
1821 case XML_ENTITY_REF_NODE:
1822 case XML_ENTITY_NODE:
1823 case XML_PI_NODE:
1824 case XML_COMMENT_NODE:
1825 if (cur->content != NULL) free(cur->content);
1826 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001827 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001828 if (content != NULL)
1829 cur->content = xmlStrndup(content, len);
1830 else
1831 cur->content = NULL;
1832 case XML_DOCUMENT_NODE:
1833 case XML_DOCUMENT_TYPE_NODE:
1834 break;
1835 case XML_NOTATION_NODE:
1836 if (cur->content != NULL) free(cur->content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001837 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1838 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001839 if (content != NULL)
1840 cur->content = xmlStrndup(content, len);
1841 else
1842 cur->content = NULL;
1843 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001844 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001845}
1846
Daniel Veillard97b58771998-10-20 06:14:16 +00001847/**
1848 * xmlNodeAddContentLen:
1849 * @cur: the node being modified
1850 * @content: extra content
1851 * @len: the size of @content
1852 *
1853 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001854 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001855void
1856xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001857 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001858 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1859 return;
1860 }
1861 if (len <= 0) return;
1862 switch (cur->type) {
1863 case XML_DOCUMENT_FRAG_NODE:
1864 case XML_ELEMENT_NODE: {
1865 xmlNodePtr last = NULL, new;
1866
1867 if (cur->childs != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001868 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001869 } else {
1870 if (cur->content != NULL) {
1871 cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001872 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001873 free(cur->content);
1874 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001875 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001876 }
1877 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001878 new = xmlNewTextLen(content, len);
Daniel Veillard16253641998-10-28 22:58:05 +00001879 if (new != NULL) {
1880 xmlAddChild(cur, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001881 if ((last != NULL) && (last->next == new)) {
Daniel Veillard16253641998-10-28 22:58:05 +00001882 xmlTextMerge(last, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001883 }
Daniel Veillard16253641998-10-28 22:58:05 +00001884 }
1885 break;
1886 }
1887 case XML_ATTRIBUTE_NODE:
1888 break;
1889 case XML_TEXT_NODE:
1890 case XML_CDATA_SECTION_NODE:
1891 case XML_ENTITY_REF_NODE:
1892 case XML_ENTITY_NODE:
1893 case XML_PI_NODE:
1894 case XML_COMMENT_NODE:
1895 if (content != NULL)
1896 cur->content = xmlStrncat(cur->content, content, len);
1897 case XML_DOCUMENT_NODE:
1898 case XML_DOCUMENT_TYPE_NODE:
1899 break;
1900 case XML_NOTATION_NODE:
1901 if (content != NULL)
1902 cur->content = xmlStrncat(cur->content, content, len);
1903 break;
1904 }
1905}
1906
1907/**
1908 * xmlNodeAddContent:
1909 * @cur: the node being modified
1910 * @content: extra content
1911 *
1912 * Append the extra substring to the node content.
1913 */
1914void
1915xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1916 int len;
1917
1918 if (cur == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001919 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1920 return;
1921 }
Daniel Veillard16253641998-10-28 22:58:05 +00001922 if (content == NULL) return;
1923 len = xmlStrlen(content);
1924 xmlNodeAddContentLen(cur, content, len);
1925}
1926
1927/**
1928 * xmlTextMerge:
1929 * @first: the first text node
1930 * @second: the second text node being merged
1931 *
1932 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00001933 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00001934 */
1935xmlNodePtr
1936xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1937 if (first == NULL) return(second);
1938 if (second == NULL) return(first);
1939 if (first->type != XML_TEXT_NODE) return(first);
1940 if (second->type != XML_TEXT_NODE) return(first);
1941 xmlNodeAddContent(first, second->content);
1942 xmlUnlinkNode(second);
1943 xmlFreeNode(second);
1944 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001945}
1946
Daniel Veillard97b58771998-10-20 06:14:16 +00001947/**
1948 * xmlSearchNs:
1949 * @doc: the document
1950 * @node: the current node
1951 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00001952 *
Daniel Veillard97b58771998-10-20 06:14:16 +00001953 * Search a Ns registered under a given name space for a document.
1954 * recurse on the parents until it finds the defined namespace
1955 * or return NULL otherwise.
1956 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001957 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001958 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001959xmlNsPtr
1960xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001961 xmlNsPtr cur;
1962
1963 while (node != NULL) {
1964 cur = node->nsDef;
1965 while (cur != NULL) {
1966 if ((cur->prefix == NULL) && (nameSpace == NULL))
1967 return(cur);
1968 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1969 (!xmlStrcmp(cur->prefix, nameSpace)))
1970 return(cur);
1971 cur = cur->next;
1972 }
1973 node = node->parent;
1974 }
1975 if (doc != NULL) {
1976 cur = doc->oldNs;
1977 while (cur != NULL) {
1978 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1979 (!xmlStrcmp(cur->prefix, nameSpace)))
1980 return(cur);
1981 cur = cur->next;
1982 }
1983 }
1984 return(NULL);
1985}
1986
Daniel Veillard97b58771998-10-20 06:14:16 +00001987/**
1988 * xmlSearchNsByHref:
1989 * @doc: the document
1990 * @node: the current node
1991 * @href: the namespace value
1992 *
1993 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1994 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001995 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001996 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001997xmlNsPtr
1998xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001999 xmlNsPtr cur;
2000
2001 while (node != NULL) {
2002 cur = node->nsDef;
2003 while (cur != NULL) {
2004 if ((cur->href != NULL) && (href != NULL) &&
2005 (!xmlStrcmp(cur->href, href)))
2006 return(cur);
2007 cur = cur->next;
2008 }
2009 node = node->parent;
2010 }
2011 if (doc != NULL) {
2012 cur = doc->oldNs;
2013 while (cur != NULL) {
2014 if ((cur->href != NULL) && (href != NULL) &&
2015 (!xmlStrcmp(cur->href, href)))
2016 return(cur);
2017 cur = cur->next;
2018 }
2019 }
2020 return(NULL);
2021}
2022
Daniel Veillard97b58771998-10-20 06:14:16 +00002023/**
2024 * xmlGetProp:
2025 * @node: the node
2026 * @name: the attribute name
2027 *
2028 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00002029 * This does the entity substitution.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002030 * Returns the attribute value or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002031 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002032CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002033 xmlAttrPtr prop = node->properties;
2034
2035 while (prop != NULL) {
Daniel Veillard68178931999-02-08 18:34:36 +00002036 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillard6800ef31999-02-08 18:33:22 +00002037 CHAR *ret;
2038
2039 ret = xmlNodeListGetString(node->doc, prop->val, 1);
2040 if (ret == NULL) return(xmlStrdup(""));
2041 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00002042 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002043 prop = prop->next;
2044 }
2045 return(NULL);
2046}
2047
Daniel Veillard97b58771998-10-20 06:14:16 +00002048/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002049 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00002050 * @node: the node
2051 * @name: the attribute name
2052 * @value: the attribute value
2053 *
2054 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002055 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002056 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002057xmlAttrPtr
2058xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002059 xmlAttrPtr prop = node->properties;
2060
2061 while (prop != NULL) {
2062 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002063 if (prop->val != NULL)
2064 xmlFreeNode(prop->val);
2065 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002066 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00002067 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002068 return(prop);
2069 }
2070 prop = prop->next;
2071 }
2072 prop = xmlNewProp(node, name, value);
2073 return(prop);
2074}
2075
Daniel Veillard97b58771998-10-20 06:14:16 +00002076/**
2077 * xmlNodeIsText:
2078 * @node: the node
2079 *
2080 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00002081 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00002082 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002083int
2084xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002085 if (node == NULL) return(0);
2086
Daniel Veillard0bef1311998-10-14 02:36:47 +00002087 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002088 return(0);
2089}
2090
Daniel Veillard97b58771998-10-20 06:14:16 +00002091/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00002092 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00002093 * @node: the node
2094 * @content: the content
2095 * @len: @content lenght
2096 *
2097 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00002098 */
Daniel Veillard97b58771998-10-20 06:14:16 +00002099
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002100void
2101xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002102 if (node == NULL) return;
2103
Daniel Veillard0bef1311998-10-14 02:36:47 +00002104 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002105 fprintf(stderr, "xmlTextConcat: node is not text\n");
2106 return;
2107 }
2108 node->content = xmlStrncat(node->content, content, len);
2109}
2110
2111/************************************************************************
2112 * *
2113 * Output : to a FILE or in memory *
2114 * *
2115 ************************************************************************/
2116
Daniel Veillard5099ae81999-04-21 20:12:07 +00002117#define BASE_BUFFER_SIZE 4000
2118
2119/**
2120 * xmlBufferCreate:
2121 *
2122 * routine to create an XML buffer.
2123 * returns the new structure.
2124 */
2125xmlBufferPtr
2126xmlBufferCreate(void) {
2127 xmlBufferPtr ret;
2128
2129 ret = (xmlBufferPtr) malloc(sizeof(xmlBuffer));
2130 if (ret == NULL) {
2131 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
2132 return(NULL);
2133 }
2134 ret->use = 0;
2135 ret->size = BASE_BUFFER_SIZE;
2136 ret->content = (CHAR *) malloc(ret->size * sizeof(CHAR));
2137 if (ret->content == NULL) {
2138 fprintf(stderr, "xmlBufferCreate : out of memory!\n");
2139 free(ret);
2140 return(NULL);
2141 }
2142 ret->content[0] = 0;
2143 return(ret);
2144}
2145
2146/**
2147 * xmlBufferFree:
2148 * @buf: the buffer to free
2149 *
2150 * Frees an XML buffer.
2151 */
2152void
2153xmlBufferFree(xmlBufferPtr buf) {
2154 if (buf == NULL) {
2155 fprintf(stderr, "xmlBufferFree: buf == NULL\n");
2156 return;
2157 }
2158 if (buf->content == NULL) {
2159 fprintf(stderr, "xmlBufferFree: buf->content == NULL\n");
2160 } else {
2161 memset(buf->content, -1, BASE_BUFFER_SIZE);
2162 free(buf->content);
2163 }
2164 memset(buf, -1, sizeof(xmlBuffer));
2165 free(buf);
2166}
2167
2168/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002169 * xmlBufferEmpty:
2170 * @buf: the buffer
2171 *
2172 * empty a buffer.
2173 */
2174void
2175xmlBufferEmpty(xmlBufferPtr buf) {
2176 buf->use = 0;
2177 memset(buf->content, -1, buf->size);/* just for debug */
2178}
2179
2180/**
2181 * xmlBufferShrink:
2182 * @buf: the buffer to dump
2183 * @len: the number of CHAR to remove
2184 *
2185 * Remove the beginning of an XML buffer.
2186 *
2187 * Returns the number of CHAR removed, or -1 in case of failure.
2188 */
2189int
2190xmlBufferShrink(xmlBufferPtr buf, int len) {
2191 if (len == 0) return(0);
2192 if (len > buf->use) return(-1);
2193
2194 buf->use -= len;
2195 memmove(buf->content, &buf->content[len], buf->use * sizeof(CHAR));
2196
2197 buf->content[buf->use] = 0;
2198 return(len);
2199}
2200
2201/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00002202 * xmlBufferDump:
2203 * @file: the file output
2204 * @buf: the buffer to dump
2205 *
2206 * Dumps an XML buffer to a FILE *.
2207 * Returns the number of CHAR written
2208 */
2209int
2210xmlBufferDump(FILE *file, xmlBufferPtr buf) {
2211 int ret;
2212
2213 if (buf == NULL) {
2214 fprintf(stderr, "xmlBufferDump: buf == NULL\n");
2215 return(0);
2216 }
2217 if (buf->content == NULL) {
2218 fprintf(stderr, "xmlBufferDump: buf->content == NULL\n");
2219 return(0);
2220 }
2221 if (file == NULL) file = stdout;
2222 ret = fwrite(buf->content, sizeof(CHAR), buf->use, file);
2223 return(ret);
2224}
2225
2226/**
2227 * xmlBufferAdd:
2228 * @buf: the buffer to dump
2229 * @str: the CHAR string
2230 * @len: the number of CHAR to add
2231 *
2232 * Add a string range to an XML buffer.
2233 */
2234void
2235xmlBufferAdd(xmlBufferPtr buf, const CHAR *str, int len) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002236 int l;
Daniel Veillard5099ae81999-04-21 20:12:07 +00002237
2238 if (str == NULL) {
2239 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2240 return;
2241 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002242 l = xmlStrlen(str);
2243 if (l < len) len = l;
2244 if (len <= 0) return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00002245
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002246 if (buf->use + len + 10 >= buf->size) {
2247 CHAR *rebuf;
2248
2249 buf->size *= 2;
2250 if (buf->use + len + 10 > buf->size)
2251 buf->size = buf->use + len + 10;
2252 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2253 if (rebuf == NULL) {
2254 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2255 return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00002256 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002257 buf->content = rebuf;
Daniel Veillard5099ae81999-04-21 20:12:07 +00002258 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002259 memmove(&buf->content[buf->use], str, len);
2260 buf->use += len;
2261 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00002262}
2263
2264/**
2265 * xmlBufferCat:
2266 * @buf: the buffer to dump
2267 * @str: the CHAR string
2268 *
2269 * Append a zero terminated string to an XML buffer.
2270 */
2271void
2272xmlBufferCat(xmlBufferPtr buf, const CHAR *str) {
2273 const CHAR *cur;
2274
2275 if (str == NULL) {
2276 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2277 return;
2278 }
2279 for (cur = str;*cur != 0;cur++) {
2280 if (buf->use + 10 >= buf->size) {
2281 CHAR *rebuf;
2282
2283 buf->size *= 2;
2284 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2285 if (rebuf == NULL) {
2286 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2287 return;
2288 }
2289 buf->content = rebuf;
2290 }
2291 buf->content[buf->use++] = *cur;
2292 }
2293}
2294
2295/**
2296 * xmlBufferCCat:
2297 * @buf: the buffer to dump
2298 * @str: the C char string
2299 *
2300 * Append a zero terminated C string to an XML buffer.
2301 */
2302void
2303xmlBufferCCat(xmlBufferPtr buf, const char *str) {
2304 const char *cur;
2305
2306 if (str == NULL) {
2307 fprintf(stderr, "xmlBufferAdd: str == NULL\n");
2308 return;
2309 }
2310 for (cur = str;*cur != 0;cur++) {
2311 if (buf->use + 10 >= buf->size) {
2312 CHAR *rebuf;
2313
2314 buf->size *= 2;
2315 rebuf = (CHAR *) realloc(buf->content, buf->size * sizeof(CHAR));
2316 if (rebuf == NULL) {
2317 fprintf(stderr, "xmlBufferAdd : out of memory!\n");
2318 return;
2319 }
2320 buf->content = rebuf;
2321 }
2322 buf->content[buf->use++] = *cur;
2323 }
2324}
Daniel Veillard260a68f1998-08-13 03:39:55 +00002325
Daniel Veillard97b58771998-10-20 06:14:16 +00002326/**
2327 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002328 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00002329 * @string: the string to add
2330 *
2331 * routine which manage and grows an output buffer. This one add
Daniel Veillard5099ae81999-04-21 20:12:07 +00002332 * CHARs at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00002333 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002334void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002335xmlBufferWriteCHAR(xmlBufferPtr buf, const CHAR *string) {
2336 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002337}
2338
Daniel Veillard97b58771998-10-20 06:14:16 +00002339/**
2340 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002341 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002342 * @string: the string to add
2343 *
2344 * routine which manage and grows an output buffer. This one add
2345 * C chars at the end of the array.
2346 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002347void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002348xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
2349 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002350}
2351
Daniel Veillard5099ae81999-04-21 20:12:07 +00002352
Daniel Veillard97b58771998-10-20 06:14:16 +00002353/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00002354 * xmlBufferWriteQuotedString:
2355 * @buf: the XML buffer output
2356 * @string: the string to add
2357 *
2358 * routine which manage and grows an output buffer. This one writes
2359 * a quoted or double quoted CHAR string, checking first if it holds
2360 * quote or double-quotes internally
2361 */
2362void
2363xmlBufferWriteQuotedString(xmlBufferPtr buf, const CHAR *string) {
2364 /*
2365 * TODO: fix strchr by xmlStrchr to work coreectly on UTF-8 !!!
2366 */
2367 if (strchr(string, '"')) {
2368 if (strchr(string, '\'')) {
2369 fprintf(stderr,
2370 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
2371 }
2372 xmlBufferCCat(buf, "'");
2373 xmlBufferCat(buf, string);
2374 xmlBufferCCat(buf, "'");
2375 } else {
2376 xmlBufferCCat(buf, "\"");
2377 xmlBufferCat(buf, string);
2378 xmlBufferCCat(buf, "\"");
2379 }
2380}
2381
2382
2383/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002384 * xmlGlobalNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002385 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002386 * @cur: a namespace
2387 *
2388 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002389 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002390static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002391xmlGlobalNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002392 if (cur == NULL) {
2393 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
2394 return;
2395 }
2396 if (cur->type == XML_GLOBAL_NAMESPACE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002397 xmlBufferWriteChar(buf, "<?namespace");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002398 if (cur->href != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002399 xmlBufferWriteChar(buf, " href=");
2400 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002401 }
2402 if (cur->prefix != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002403 xmlBufferWriteChar(buf, " AS=");
2404 xmlBufferWriteQuotedString(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002405 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002406 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002407 }
2408}
2409
Daniel Veillard97b58771998-10-20 06:14:16 +00002410/**
2411 * xmlGlobalNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002412 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002413 * @cur: the first namespace
2414 *
2415 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002416 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002417static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002418xmlGlobalNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002419 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002420 xmlGlobalNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002421 cur = cur->next;
2422 }
2423}
2424
Daniel Veillard97b58771998-10-20 06:14:16 +00002425/**
2426 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002427 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002428 * @cur: a namespace
2429 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002430 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00002431 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002432 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002433static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002434xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002435 if (cur == NULL) {
2436 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
2437 return;
2438 }
2439 if (cur->type == XML_LOCAL_NAMESPACE) {
2440 /* Within the context of an element attributes */
2441 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002442 xmlBufferWriteChar(buf, " xmlns:");
2443 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002444 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00002445 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00002446 xmlBufferWriteChar(buf, "=");
2447 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002448 }
2449}
2450
Daniel Veillard97b58771998-10-20 06:14:16 +00002451/**
2452 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002453 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002454 * @cur: the first namespace
2455 *
2456 * Dump a list of local Namespace definitions.
2457 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002458 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002459static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002460xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002461 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002462 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002463 cur = cur->next;
2464 }
2465}
2466
Daniel Veillard97b58771998-10-20 06:14:16 +00002467/**
2468 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002469 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002470 * @doc: the document
2471 *
2472 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002473 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002474static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002475xmlDtdDump(xmlBufferPtr buf, xmlDocPtr doc) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002476 xmlDtdPtr cur = doc->intSubset;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002477
2478 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002479 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002480 return;
2481 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002482 xmlBufferWriteChar(buf, "<!DOCTYPE ");
2483 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002484 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002485 xmlBufferWriteChar(buf, " PUBLIC ");
2486 xmlBufferWriteQuotedString(buf, cur->ExternalID);
2487 xmlBufferWriteChar(buf, " ");
2488 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002489 } else if (cur->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002490 xmlBufferWriteChar(buf, " SYSTEM ");
2491 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002492 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002493 if ((cur->entities == NULL) && (cur->elements == NULL) &&
2494 (cur->attributes == NULL) && (cur->notations == NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002495 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002496 return;
2497 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002498 xmlBufferWriteChar(buf, " [\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002499 if (cur->entities != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002500 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) cur->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002501 if (cur->notations != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002502 xmlDumpNotationTable(buf, (xmlNotationTablePtr) cur->notations);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002503 if (cur->elements != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002504 xmlDumpElementTable(buf, (xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002505 if (cur->attributes != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002506 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) cur->attributes);
2507 xmlBufferWriteChar(buf, "]");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002508
2509 /* TODO !!! a lot more things to dump ... */
Daniel Veillard5099ae81999-04-21 20:12:07 +00002510 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002511}
2512
Daniel Veillard97b58771998-10-20 06:14:16 +00002513/**
2514 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002515 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002516 * @doc: the document
2517 * @cur: the attribute pointer
2518 *
2519 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00002520 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002521static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002522xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002523 CHAR *value;
2524
Daniel Veillard260a68f1998-08-13 03:39:55 +00002525 if (cur == NULL) {
2526 fprintf(stderr, "xmlAttrDump : property == NULL\n");
2527 return;
2528 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002529 xmlBufferWriteChar(buf, " ");
2530 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002531 value = xmlNodeListGetString(doc, cur->val, 0);
2532 if (value) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002533 xmlBufferWriteChar(buf, "=");
2534 xmlBufferWriteQuotedString(buf, value);
Daniel Veillardccb09631998-10-27 06:21:04 +00002535 free(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00002536 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002537 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002538 }
2539}
2540
Daniel Veillard97b58771998-10-20 06:14:16 +00002541/**
2542 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002543 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002544 * @doc: the document
2545 * @cur: the first attribute pointer
2546 *
2547 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00002548 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002549static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002550xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002551 if (cur == NULL) {
2552 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
2553 return;
2554 }
2555 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002556 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002557 cur = cur->next;
2558 }
2559}
2560
Daniel Veillard260a68f1998-08-13 03:39:55 +00002561
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002562static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002563xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00002564/**
2565 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002566 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002567 * @doc: the document
2568 * @cur: the first node
2569 * @level: the imbrication level for indenting
2570 *
2571 * Dump an XML node list, recursive behaviour,children are printed too.
2572 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002573static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002574xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002575 int needIndent = 0, i;
2576
Daniel Veillard260a68f1998-08-13 03:39:55 +00002577 if (cur == NULL) {
2578 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
2579 return;
2580 }
2581 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002582 if ((cur->type != XML_TEXT_NODE) &&
2583 (cur->type != XML_ENTITY_REF_NODE)) {
2584 if (!needIndent) {
2585 needIndent = 1;
Daniel Veillard5099ae81999-04-21 20:12:07 +00002586 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00002587 }
2588 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002589 xmlNodeDump(buf, doc, cur, level);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002590 cur = cur->next;
2591 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002592 if ((xmlIndentTreeOutput) && (needIndent))
2593 for (i = 1;i < level;i++)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002594 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002595}
2596
Daniel Veillard97b58771998-10-20 06:14:16 +00002597/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002598 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002599 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002600 * @doc: the document
2601 * @cur: the current node
2602 * @level: the imbrication level for indenting
2603 *
2604 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002605 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002606static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002607xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002608 int i;
2609
2610 if (cur == NULL) {
2611 fprintf(stderr, "xmlNodeDump : node == NULL\n");
2612 return;
2613 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002614 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00002615 if (cur->content != NULL) {
2616 CHAR *buffer;
2617
2618 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
2619 if (buffer != NULL) {
2620 xmlBufferWriteCHAR(buf, buffer);
2621 free(buffer);
2622 }
2623 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002624 return;
2625 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002626 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002627 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002628 xmlBufferWriteChar(buf, "<!--");
2629 xmlBufferWriteCHAR(buf, cur->content);
2630 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002631 }
2632 return;
2633 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002634 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002635 xmlBufferWriteChar(buf, "&");
2636 xmlBufferWriteCHAR(buf, cur->name);
2637 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00002638 return;
2639 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002640 if (xmlIndentTreeOutput)
2641 for (i = 0;i < level;i++)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002642 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002643
Daniel Veillard5099ae81999-04-21 20:12:07 +00002644 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002645 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002646 xmlBufferWriteCHAR(buf, cur->ns->prefix);
2647 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002648 }
2649
Daniel Veillard5099ae81999-04-21 20:12:07 +00002650 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002651 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002652 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002653 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002654 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002655
2656 if ((cur->content == NULL) && (cur->childs == NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002657 xmlBufferWriteChar(buf, "/>\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002658 return;
2659 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002660 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00002661 if (cur->content != NULL) {
2662 CHAR *buffer;
2663
2664 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
2665 if (buffer != NULL) {
2666 xmlBufferWriteCHAR(buf, buffer);
2667 free(buffer);
2668 }
2669 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002670 if (cur->childs != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002671 xmlNodeListDump(buf, doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002672 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002673 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002674 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002675 xmlBufferWriteCHAR(buf, cur->ns->prefix);
2676 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002677 }
2678
Daniel Veillard5099ae81999-04-21 20:12:07 +00002679 xmlBufferWriteCHAR(buf, cur->name);
2680 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002681}
2682
Daniel Veillard97b58771998-10-20 06:14:16 +00002683/**
2684 * xmlDocContentDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00002685 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00002686 * @cur: the document
2687 *
2688 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002689 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002690static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00002691xmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00002692 xmlBufferWriteChar(buf, "<?xml version=");
2693 if (cur->version != NULL)
2694 xmlBufferWriteQuotedString(buf, cur->version);
2695 else
2696 xmlBufferWriteChar(buf, "\"1.0\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002697 if (cur->encoding != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002698 xmlBufferWriteChar(buf, " encoding=");
2699 xmlBufferWriteQuotedString(buf, cur->encoding);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002700 }
2701 switch (cur->standalone) {
2702 case 0:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002703 xmlBufferWriteChar(buf, " standalone=\"no\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002704 break;
2705 case 1:
Daniel Veillard5099ae81999-04-21 20:12:07 +00002706 xmlBufferWriteChar(buf, " standalone=\"yes\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002707 break;
2708 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002709 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002710 if (cur->intSubset != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002711 xmlDtdDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002712 if (cur->root != NULL) {
2713 /* global namespace definitions, the old way */
2714 if (oldXMLWDcompatibility)
Daniel Veillard5099ae81999-04-21 20:12:07 +00002715 xmlGlobalNsListDump(buf, cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002716 else
2717 xmlUpgradeOldNs(cur);
Daniel Veillard5099ae81999-04-21 20:12:07 +00002718 xmlNodeDump(buf, cur, cur->root, 0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002719 }
2720}
2721
Daniel Veillard97b58771998-10-20 06:14:16 +00002722/**
2723 * xmlDocDumpMemory:
2724 * @cur: the document
2725 * @mem: OUT: the memory pointer
2726 * @size: OUT: the memory lenght
2727 *
2728 * Dump an XML document in memory and return the CHAR * and it's size.
2729 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002730 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002731void
2732xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002733 xmlBufferPtr buf;
2734
Daniel Veillard260a68f1998-08-13 03:39:55 +00002735 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002736#ifdef DEBUG_TREE
2737 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
2738#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002739 *mem = NULL;
2740 *size = 0;
2741 return;
2742 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002743 buf = xmlBufferCreate();
2744 if (buf == NULL) {
2745 *mem = NULL;
2746 *size = 0;
2747 return;
2748 }
2749 xmlDocContentDump(buf, cur);
2750 *mem = buf->content;
2751 *size = buf->use;
2752 memset(buf, -1, sizeof(xmlBuffer));
2753 free(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002754}
2755
Daniel Veillard97b58771998-10-20 06:14:16 +00002756/**
2757 * xmlGetDocCompressMode:
2758 * @doc: the document
2759 *
2760 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00002761 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002762 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002763int
2764 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002765 if (doc == NULL) return(-1);
2766 return(doc->compression);
2767}
2768
Daniel Veillard97b58771998-10-20 06:14:16 +00002769/**
2770 * xmlSetDocCompressMode:
2771 * @doc: the document
2772 * @mode: the compression ratio
2773 *
2774 * set the compression ratio for a document, ZLIB based
2775 * Correct values: 0 (uncompressed) to 9 (max compression)
2776 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002777void
2778xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002779 if (doc == NULL) return;
2780 if (mode < 0) doc->compression = 0;
2781 else if (mode > 9) doc->compression = 9;
2782 else doc->compression = mode;
2783}
2784
Daniel Veillard97b58771998-10-20 06:14:16 +00002785/**
2786 * xmlGetCompressMode:
2787 *
2788 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002789 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002790 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002791int
2792 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002793 return(xmlCompressMode);
2794}
Daniel Veillard97b58771998-10-20 06:14:16 +00002795
2796/**
2797 * xmlSetCompressMode:
2798 * @mode: the compression ratio
2799 *
2800 * set the default compression mode used, ZLIB based
2801 * Correct values: 0 (uncompressed) to 9 (max compression)
2802 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002803void
2804xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002805 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002806 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002807 else xmlCompressMode = mode;
2808}
2809
Daniel Veillard97b58771998-10-20 06:14:16 +00002810/**
2811 * xmlDocDump:
2812 * @f: the FILE*
2813 * @cur: the document
2814 *
2815 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002816 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002817void
2818xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002819 xmlBufferPtr buf;
2820
Daniel Veillard260a68f1998-08-13 03:39:55 +00002821 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002822#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002823 fprintf(stderr, "xmlDocDump : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002824#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002825 return;
2826 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00002827 buf = xmlBufferCreate();
2828 if (buf == NULL) return;
2829 xmlDocContentDump(buf, cur);
2830 xmlBufferDump(f, buf);
2831 xmlBufferFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002832}
2833
Daniel Veillard97b58771998-10-20 06:14:16 +00002834/**
2835 * xmlSaveFile:
2836 * @filename: the filename
2837 * @cur: the document
2838 *
2839 * Dump an XML document to a file. Will use compression if
2840 * compiled in and enabled.
2841 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002842 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002843int
2844xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002845 xmlBufferPtr buf;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002846#ifdef HAVE_ZLIB_H
2847 gzFile zoutput = NULL;
2848 char mode[15];
2849#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002850 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002851 int ret;
2852
Daniel Veillard5099ae81999-04-21 20:12:07 +00002853 /*
2854 * save the content to a temp buffer.
2855 */
2856 buf = xmlBufferCreate();
2857 if (buf == NULL) return(0);
2858 xmlDocContentDump(buf, cur);
2859
Daniel Veillard151b1b01998-09-23 00:49:46 +00002860#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002861 if ((cur->compression > 0) && (cur->compression <= 9)) {
2862 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002863 zoutput = gzopen(filename, mode);
2864 }
2865 if (zoutput == NULL) {
2866#endif
2867 output = fopen(filename, "w");
2868 if (output == NULL) return(-1);
2869#ifdef HAVE_ZLIB_H
2870 }
Daniel Veillard151b1b01998-09-23 00:49:46 +00002871
Daniel Veillard151b1b01998-09-23 00:49:46 +00002872 if (zoutput != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00002873 ret = gzwrite(zoutput, buf->content, sizeof(CHAR) * buf->use);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002874 gzclose(zoutput);
Daniel Veillard5099ae81999-04-21 20:12:07 +00002875 } else {
2876#endif
2877 ret = xmlBufferDump(output, buf);
2878 fclose(output);
2879#ifdef HAVE_ZLIB_H
Daniel Veillard151b1b01998-09-23 00:49:46 +00002880 }
2881#endif
Manish Vachharajani5e60f5a1999-05-29 03:04:30 +00002882 xmlBufferFree(buf);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002883 return(ret * sizeof(CHAR));
2884}
2885