blob: 13c30875b17ff50557b17a14fe653c4eddd0a406 [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 Veillard27fb0751998-10-17 06:47:46 +0000398#ifndef WITHOUT_CORBA
399 cur->_private = NULL;
400 cur->vepv = NULL;
401#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000402 return(cur);
403}
404
Daniel Veillard97b58771998-10-20 06:14:16 +0000405/**
406 * xmlFreeDoc:
407 * @cur: pointer to the document
408 * @:
409 *
410 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000411 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000412void
413xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000414 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000415#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000416 fprintf(stderr, "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000417#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000418 return;
419 }
420 free((char *) cur->version);
421 if (cur->name != NULL) free((char *) cur->name);
422 if (cur->encoding != NULL) free((char *) cur->encoding);
423 if (cur->root != NULL) xmlFreeNode(cur->root);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000424 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
425 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000426 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000427 memset(cur, -1, sizeof(xmlDoc));
428 free(cur);
429}
430
Daniel Veillard97b58771998-10-20 06:14:16 +0000431/**
Daniel Veillard16253641998-10-28 22:58:05 +0000432 * xmlStringLenGetNodeList:
433 * @doc: the document
434 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000435 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000436 *
437 * Parse the value string and build the node list associated. Should
438 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000439 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000440 */
441xmlNodePtr
442xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value, int len) {
443 xmlNodePtr ret = NULL, last = NULL;
444 xmlNodePtr node;
445 CHAR *val;
446 const CHAR *cur = value;
447 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000448 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000449
450 if (value == NULL) return(NULL);
451
452 q = cur;
453 while ((*cur != 0) && (cur - value < len)) {
454 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000455 /*
456 * Save the current text.
457 */
Daniel Veillard16253641998-10-28 22:58:05 +0000458 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000459 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
460 xmlNodeAddContentLen(last, q, cur - q);
461 } else {
462 node = xmlNewDocTextLen(doc, q, cur - q);
463 if (node == NULL) return(ret);
464 if (last == NULL)
465 last = ret = node;
466 else {
467 last->next = node;
468 node->prev = last;
469 last = node;
470 }
Daniel Veillard16253641998-10-28 22:58:05 +0000471 }
472 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000473 /*
474 * Read the entity string
475 */
Daniel Veillard16253641998-10-28 22:58:05 +0000476 cur++;
477 q = cur;
478 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
479 if ((*cur == 0) || (cur - value >= len)) {
480 fprintf(stderr,
481 "xmlStringGetNodeList: unterminated entity %30s\n", q);
482 return(ret);
483 }
484 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000485 /*
486 * Predefined entities don't generate nodes
487 */
Daniel Veillard16253641998-10-28 22:58:05 +0000488 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000489 ent = xmlGetDocEntity(doc, val);
490 if ((ent != NULL) &&
491 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
492 if (last == NULL) {
493 node = xmlNewDocText(doc, ent->content);
494 last = ret = node;
495 } else
496 xmlNodeAddContent(last, ent->content);
497
498 } else {
499 /*
500 * Create a new REFERENCE_REF node
501 */
502 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000503 if (node == NULL) {
504 if (val != NULL) free(val);
505 return(ret);
506 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000507 if (last == NULL)
508 last = ret = node;
509 else {
510 last->next = node;
511 node->prev = last;
512 last = node;
513 }
Daniel Veillard16253641998-10-28 22:58:05 +0000514 }
515 free(val);
516 }
517 cur++;
518 q = cur;
519 } else
520 cur++;
521 }
522 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000523 /*
524 * Handle the last piece of text.
525 */
526 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
527 xmlNodeAddContentLen(last, q, cur - q);
528 } else {
529 node = xmlNewDocTextLen(doc, q, cur - q);
530 if (node == NULL) return(ret);
531 if (last == NULL)
532 last = ret = node;
533 else {
534 last->next = node;
535 node->prev = last;
536 last = node;
537 }
Daniel Veillard16253641998-10-28 22:58:05 +0000538 }
539 }
540 return(ret);
541}
542
543/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000544 * xmlStringGetNodeList:
545 * @doc: the document
546 * @value: the value of the attribute
547 *
548 * Parse the value string and build the node list associated. Should
549 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000550 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000551 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000552xmlNodePtr
553xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000554 xmlNodePtr ret = NULL, last = NULL;
555 xmlNodePtr node;
556 CHAR *val;
557 const CHAR *cur = value;
558 const CHAR *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000559 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000560
561 if (value == NULL) return(NULL);
562
563 q = cur;
564 while (*cur != 0) {
565 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000566 /*
567 * Save the current text.
568 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000569 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000570 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
571 xmlNodeAddContentLen(last, q, cur - q);
572 } else {
573 node = xmlNewDocTextLen(doc, q, cur - q);
574 if (node == NULL) return(ret);
575 if (last == NULL)
576 last = ret = node;
577 else {
578 last->next = node;
579 node->prev = last;
580 last = node;
581 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000582 }
583 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000584 /*
585 * Read the entity string
586 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000587 cur++;
588 q = cur;
589 while ((*cur != 0) && (*cur != ';')) cur++;
590 if (*cur == 0) {
591 fprintf(stderr,
592 "xmlStringGetNodeList: unterminated entity %30s\n", q);
593 return(ret);
594 }
595 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000596 /*
597 * Predefined entities don't generate nodes
598 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000599 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000600 ent = xmlGetDocEntity(doc, val);
601 if ((ent != NULL) &&
602 (ent->type == XML_INTERNAL_PREDEFINED_ENTITY)) {
603 if (last == NULL) {
604 node = xmlNewDocText(doc, ent->content);
605 last = ret = node;
606 } else
607 xmlNodeAddContent(last, ent->content);
608
609 } else {
610 /*
611 * Create a new REFERENCE_REF node
612 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000613 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000614 if (node == NULL) {
615 if (val != NULL) free(val);
616 return(ret);
617 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000618 if (last == NULL)
619 last = ret = node;
620 else {
621 last->next = node;
622 node->prev = last;
623 last = node;
624 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000625 }
626 free(val);
627 }
628 cur++;
629 q = cur;
630 } else
631 cur++;
632 }
633 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000634 /*
635 * Handle the last piece of text.
636 */
637 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
638 xmlNodeAddContentLen(last, q, cur - q);
639 } else {
640 node = xmlNewDocTextLen(doc, q, cur - q);
641 if (node == NULL) return(ret);
642 if (last == NULL)
643 last = ret = node;
644 else {
645 last->next = node;
646 node->prev = last;
647 last = node;
648 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000649 }
650 }
651 return(ret);
652}
653
654/**
655 * xmlNodeListGetString:
656 * @doc: the document
657 * @list: a Node list
658 * @inLine: should we replace entity contents or show their external form
659 *
660 * Returns the string equivalent to the text contained in the Node list
661 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000662 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000663 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000664CHAR *
665xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000666 xmlNodePtr node = list;
667 CHAR *ret = NULL;
668 xmlEntityPtr ent;
669
670 if (list == NULL) return(NULL);
671
672 while (node != NULL) {
673 if (node->type == XML_TEXT_NODE) {
674 if (inLine)
675 ret = xmlStrcat(ret, node->content);
676 else
677 ret = xmlStrcat(ret, xmlEncodeEntities(doc, node->content));
678 } else if (node->type == XML_ENTITY_REF_NODE) {
679 if (inLine) {
680 ent = xmlGetDocEntity(doc, node->name);
681 if (ent != NULL)
682 ret = xmlStrcat(ret, ent->content);
683 else
684 ret = xmlStrcat(ret, node->content);
685 } else {
686 CHAR buf[2];
687 buf[0] = '&'; buf[1] = 0;
688 ret = xmlStrncat(ret, buf, 1);
689 ret = xmlStrcat(ret, node->name);
690 buf[0] = ';'; buf[1] = 0;
691 ret = xmlStrncat(ret, buf, 1);
692 }
693 }
694#if 0
695 else {
696 fprintf(stderr, "xmlGetNodeListString : invalide node type %d\n",
697 node->type);
698 }
699#endif
700 node = node->next;
701 }
702 return(ret);
703}
704
705/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000706 * xmlNewProp:
707 * @node: the holding node
708 * @name: the name of the attribute
709 * @value: the value of the attribute
710 *
711 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000712 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000713 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000714xmlAttrPtr
715xmlNewProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000716 xmlAttrPtr cur;
717
718 if (name == NULL) {
719 fprintf(stderr, "xmlNewProp : name == NULL\n");
720 return(NULL);
721 }
722
723 /*
724 * Allocate a new property and fill the fields.
725 */
726 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
727 if (cur == NULL) {
728 fprintf(stderr, "xmlNewProp : malloc failed\n");
729 return(NULL);
730 }
731
Daniel Veillard33942841998-10-18 19:12:41 +0000732 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000733 cur->node = node;
734 cur->name = xmlStrdup(name);
735 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +0000736 cur->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000737 else
Daniel Veillardccb09631998-10-27 06:21:04 +0000738 cur->val = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000739#ifndef WITHOUT_CORBA
740 cur->_private = NULL;
741 cur->vepv = NULL;
742#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000743
744 /*
745 * Add it at the end to preserve parsing order ...
746 */
747 cur->next = NULL;
748 if (node != NULL) {
749 if (node->properties == NULL) {
750 node->properties = cur;
751 } else {
752 xmlAttrPtr prev = node->properties;
753
754 while (prev->next != NULL) prev = prev->next;
755 prev->next = cur;
756 }
757 }
758 return(cur);
759}
760
Daniel Veillard97b58771998-10-20 06:14:16 +0000761/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000762 * xmlNewDocProp:
763 * @doc: the document
764 * @name: the name of the attribute
765 * @value: the value of the attribute
766 *
767 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000768 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +0000769 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000770xmlAttrPtr
771xmlNewDocProp(xmlDocPtr doc, const CHAR *name, const CHAR *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000772 xmlAttrPtr cur;
773
774 if (name == NULL) {
775 fprintf(stderr, "xmlNewProp : name == NULL\n");
776 return(NULL);
777 }
778
779 /*
780 * Allocate a new property and fill the fields.
781 */
782 cur = (xmlAttrPtr) malloc(sizeof(xmlAttr));
783 if (cur == NULL) {
784 fprintf(stderr, "xmlNewProp : malloc failed\n");
785 return(NULL);
786 }
787
788 cur->type = XML_ATTRIBUTE_NODE;
789 cur->node = NULL;
790 cur->name = xmlStrdup(name);
791 if (value != NULL)
792 cur->val = xmlStringGetNodeList(doc, value);
793 else
794 cur->val = NULL;
795#ifndef WITHOUT_CORBA
796 cur->_private = NULL;
797 cur->vepv = NULL;
798#endif
799
800 cur->next = NULL;
801 return(cur);
802}
803
804/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000805 * xmlFreePropList:
806 * @cur: the first property in the list
807 *
808 * Free a property and all its siblings, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000809 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000810void
811xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000812 xmlAttrPtr next;
813 if (cur == NULL) {
814 fprintf(stderr, "xmlFreePropList : property == NULL\n");
815 return;
816 }
817 while (cur != NULL) {
818 next = cur->next;
819 xmlFreeProp(cur);
820 cur = next;
821 }
822}
823
Daniel Veillard97b58771998-10-20 06:14:16 +0000824/**
825 * xmlFreeProp:
826 * @cur: the first property in the list
827 *
828 * Free one property, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000829 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000830void
831xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000832 if (cur == NULL) {
833 fprintf(stderr, "xmlFreeProp : property == NULL\n");
834 return;
835 }
836 if (cur->name != NULL) free((char *) cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +0000837 if (cur->val != NULL) xmlFreeNodeList(cur->val);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000838 memset(cur, -1, sizeof(xmlAttr));
839 free(cur);
840}
841
Daniel Veillard97b58771998-10-20 06:14:16 +0000842/**
843 * xmlNewNode:
844 * @ns: namespace if any
845 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +0000846 *
847 * Creation of a new node element. @ns and @content are optionnal (NULL).
Daniel Veillardccb09631998-10-27 06:21:04 +0000848 * If content is non NULL, a child list containing the TEXTs and
849 * ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000850 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000851 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000852xmlNodePtr
853xmlNewNode(xmlNsPtr ns, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000854 xmlNodePtr cur;
855
856 if (name == NULL) {
857 fprintf(stderr, "xmlNewNode : name == NULL\n");
858 return(NULL);
859 }
860
861 /*
862 * Allocate a new node and fill the fields.
863 */
864 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
865 if (cur == NULL) {
866 fprintf(stderr, "xmlNewNode : malloc failed\n");
867 return(NULL);
868 }
869
Daniel Veillard33942841998-10-18 19:12:41 +0000870 cur->type = XML_ELEMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000871 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000872 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000873 cur->next = NULL;
874 cur->prev = NULL;
875 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000876 cur->last = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000877 cur->properties = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000878 cur->name = xmlStrdup(name);
879 cur->ns = ns;
880 cur->nsDef = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000881 cur->content = NULL;
Daniel Veillard27fb0751998-10-17 06:47:46 +0000882#ifndef WITHOUT_CORBA
883 cur->_private = NULL;
884 cur->vepv = NULL;
885#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000886 return(cur);
887}
888
Daniel Veillard97b58771998-10-20 06:14:16 +0000889/**
890 * xmlNewDocNode:
891 * @doc: the document
892 * @ns: namespace if any
893 * @name: the node name
894 * @content: the text content if any
895 *
896 * Creation of a new node element within a document. @ns and @content
897 * are optionnal (NULL).
Daniel Veillard1e346af1999-02-22 10:33:01 +0000898 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +0000899 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000900xmlNodePtr
901xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard0bef1311998-10-14 02:36:47 +0000902 const CHAR *name, CHAR *content) {
903 xmlNodePtr cur;
904
Daniel Veillardccb09631998-10-27 06:21:04 +0000905 cur = xmlNewNode(ns, name);
906 if (cur != NULL) {
907 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000908 if (content != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000909 cur->childs = xmlStringGetNodeList(doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000910 UPDATE_LAST_CHILD(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000911 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000912 }
Daniel Veillard0bef1311998-10-14 02:36:47 +0000913 return(cur);
914}
915
916
Daniel Veillard97b58771998-10-20 06:14:16 +0000917/**
918 * xmlNewText:
919 * @content: the text content
920 *
921 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000922 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000923 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000924xmlNodePtr
925xmlNewText(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000926 xmlNodePtr cur;
927
928 /*
929 * Allocate a new node and fill the fields.
930 */
931 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
932 if (cur == NULL) {
933 fprintf(stderr, "xmlNewText : malloc failed\n");
934 return(NULL);
935 }
936
Daniel Veillard33942841998-10-18 19:12:41 +0000937 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000938 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000939 cur->parent = NULL;
940 cur->next = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000941 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000942 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000943 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000944 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +0000945 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000946 cur->name = xmlStrdup(xmlStringText);
947 cur->ns = NULL;
948 cur->nsDef = NULL;
949 if (content != NULL)
950 cur->content = xmlStrdup(content);
951 else
952 cur->content = NULL;
953 return(cur);
954}
955
Daniel Veillard97b58771998-10-20 06:14:16 +0000956/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000957 * xmlNewReference:
958 * @doc: the document
959 * @name: the reference name, or the reference string with & and ;
960 *
961 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000962 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +0000963 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000964xmlNodePtr
965xmlNewReference(xmlDocPtr doc, const CHAR *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000966 xmlNodePtr cur;
967 xmlEntityPtr ent;
968
969 /*
970 * Allocate a new node and fill the fields.
971 */
972 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
973 if (cur == NULL) {
974 fprintf(stderr, "xmlNewText : malloc failed\n");
975 return(NULL);
976 }
977
978 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillard10c6a8f1998-10-28 01:00:12 +0000979 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +0000980 cur->parent = NULL;
981 cur->next = NULL;
982 cur->prev = NULL;
983 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000984 cur->last = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000985 cur->properties = NULL;
986 if (name[0] == '&') {
987 int len;
988 name++;
989 len = xmlStrlen(name);
990 if (name[len - 1] == ';')
991 cur->name = xmlStrndup(name, len - 1);
992 else
993 cur->name = xmlStrndup(name, len);
994 } else
995 cur->name = xmlStrdup(name);
996 cur->ns = NULL;
997 cur->nsDef = NULL;
998
999 ent = xmlGetDocEntity(doc, cur->name);
1000 if (ent != NULL)
1001 cur->content = ent->content;
1002 else
1003 cur->content = NULL;
1004 return(cur);
1005}
1006
1007/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001008 * xmlNewDocText:
1009 * @doc: the document
1010 * @content: the text content
1011 *
1012 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001013 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001014 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001015xmlNodePtr
1016xmlNewDocText(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001017 xmlNodePtr cur;
1018
1019 cur = xmlNewText(content);
1020 if (cur != NULL) cur->doc = doc;
1021 return(cur);
1022}
1023
Daniel Veillard97b58771998-10-20 06:14:16 +00001024/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001025 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001026 * @content: the text content
1027 * @len: the text len.
1028 *
1029 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001030 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001031 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001032xmlNodePtr
1033xmlNewTextLen(const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001034 xmlNodePtr cur;
1035
1036 /*
1037 * Allocate a new node and fill the fields.
1038 */
1039 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1040 if (cur == NULL) {
1041 fprintf(stderr, "xmlNewText : malloc failed\n");
1042 return(NULL);
1043 }
1044
Daniel Veillard33942841998-10-18 19:12:41 +00001045 cur->type = XML_TEXT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001046 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001047 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001048 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001049 cur->next = NULL;
1050 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001051 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001052 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001053 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001054 cur->name = xmlStrdup(xmlStringText);
1055 cur->ns = NULL;
1056 cur->nsDef = NULL;
1057 if (content != NULL)
1058 cur->content = xmlStrndup(content, len);
1059 else
1060 cur->content = NULL;
1061 return(cur);
1062}
1063
Daniel Veillard97b58771998-10-20 06:14:16 +00001064/**
1065 * xmlNewDocTextLen:
1066 * @doc: the document
1067 * @content: the text content
1068 * @len: the text len.
1069 *
1070 * Creation of a new text node with an extra content lenght parameter. The
1071 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001072 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001073 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001074xmlNodePtr
1075xmlNewDocTextLen(xmlDocPtr doc, const CHAR *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001076 xmlNodePtr cur;
1077
1078 cur = xmlNewTextLen(content, len);
1079 if (cur != NULL) cur->doc = doc;
1080 return(cur);
1081}
1082
Daniel Veillard97b58771998-10-20 06:14:16 +00001083/**
1084 * xmlNewComment:
1085 * @content: the comment content
1086 *
1087 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001088 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001089 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001090xmlNodePtr
Daniel Veillard517752b1999-04-05 12:20:10 +00001091xmlNewComment(const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001092 xmlNodePtr cur;
1093
1094 /*
1095 * Allocate a new node and fill the fields.
1096 */
1097 cur = (xmlNodePtr) malloc(sizeof(xmlNode));
1098 if (cur == NULL) {
1099 fprintf(stderr, "xmlNewComment : malloc failed\n");
1100 return(NULL);
1101 }
1102
Daniel Veillard33942841998-10-18 19:12:41 +00001103 cur->type = XML_COMMENT_NODE;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001104 cur->doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001105 cur->parent = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001106 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001107 cur->next = NULL;
1108 cur->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001109 cur->last = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001110 cur->properties = NULL;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001111 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001112 cur->name = xmlStrdup(xmlStringText);
1113 cur->ns = NULL;
1114 cur->nsDef = NULL;
1115 if (content != NULL)
1116 cur->content = xmlStrdup(content);
1117 else
1118 cur->content = NULL;
1119 return(cur);
1120}
1121
Daniel Veillard97b58771998-10-20 06:14:16 +00001122/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001123 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001124 * @doc: the document
1125 * @content: the comment content
1126 *
1127 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001128 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001129 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001130xmlNodePtr
Daniel Veillard517752b1999-04-05 12:20:10 +00001131xmlNewDocComment(xmlDocPtr doc, const CHAR *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001132 xmlNodePtr cur;
1133
1134 cur = xmlNewComment(content);
1135 if (cur != NULL) cur->doc = doc;
1136 return(cur);
1137}
1138
Daniel Veillard97b58771998-10-20 06:14:16 +00001139/**
1140 * xmlNewChild:
1141 * @parent: the parent node
1142 * @ns: a namespace if any
1143 * @name: the name of the child
1144 * @content: the content of the child if any.
1145 *
1146 *
1147 * Creation of a new child element, added at the end of @parent childs list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001148 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1149 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001150 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001151 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001152xmlNodePtr
1153xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001154 const CHAR *name, CHAR *content) {
1155 xmlNodePtr cur, prev;
1156
1157 if (parent == NULL) {
1158 fprintf(stderr, "xmlNewChild : parent == NULL\n");
1159 return(NULL);
1160 }
1161
1162 if (name == NULL) {
1163 fprintf(stderr, "xmlNewChild : name == NULL\n");
1164 return(NULL);
1165 }
1166
1167 /*
1168 * Allocate a new node
1169 */
1170 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001171 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001172 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001173 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001174 if (cur == NULL) return(NULL);
1175
1176 /*
1177 * add the new element at the end of the childs list.
1178 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001179 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001180 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001181 cur->doc = parent->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001182 if (parent->childs == NULL) {
1183 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001184 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001185 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001186 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001187 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001188 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001189 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001190 }
1191
1192 return(cur);
1193}
1194
Daniel Veillard97b58771998-10-20 06:14:16 +00001195/**
1196 * xmlAddChild:
1197 * @parent: the parent node
1198 * @cur: the child node
1199 *
1200 * Add a new child element, to @parent, at the end of the child list.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001201 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001202 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001203xmlNodePtr
1204xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001205 xmlNodePtr prev;
1206
1207 if (parent == NULL) {
1208 fprintf(stderr, "xmladdChild : parent == NULL\n");
1209 return(NULL);
1210 }
1211
1212 if (cur == NULL) {
1213 fprintf(stderr, "xmladdChild : child == NULL\n");
1214 return(NULL);
1215 }
1216
Daniel Veillard0bef1311998-10-14 02:36:47 +00001217 if ((cur->doc != NULL) && (parent->doc != NULL) &&
1218 (cur->doc != parent->doc)) {
1219 fprintf(stderr, "Elements moved to a different document\n");
1220 }
1221
Daniel Veillard260a68f1998-08-13 03:39:55 +00001222 /*
1223 * add the new element at the end of the childs list.
1224 */
1225 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001226 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001227
Daniel Veillardccb09631998-10-27 06:21:04 +00001228 /*
1229 * Handle the case where parent->content != NULL, in that case it will
1230 * create a intermediate TEXT node.
1231 */
1232 if (parent->content != NULL) {
1233 xmlNodePtr text;
1234
1235 text = xmlNewDocText(parent->doc, parent->content);
1236 if (text != NULL) {
1237 text->next = parent->childs;
1238 if (text->next != NULL)
1239 text->next->prev = text;
1240 parent->childs = text;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001241 UPDATE_LAST_CHILD(parent)
Daniel Veillardccb09631998-10-27 06:21:04 +00001242 free(parent->content);
1243 parent->content = NULL;
1244 }
1245 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001246 if (parent->childs == NULL) {
1247 parent->childs = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001248 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001249 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001250 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001251 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001252 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001253 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001254 }
1255
1256 return(cur);
1257}
1258
Daniel Veillard97b58771998-10-20 06:14:16 +00001259/**
1260 * xmlGetLastChild:
1261 * @parent: the parent node
1262 *
1263 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001264 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001265 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001266xmlNodePtr
1267xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001268 if (parent == NULL) {
1269 fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
1270 return(NULL);
1271 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001272 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001273}
1274
Daniel Veillard97b58771998-10-20 06:14:16 +00001275/**
1276 * xmlFreeNodeList:
1277 * @cur: the first node in the list
1278 *
1279 * Free a node and all its siblings, this is a recursive behaviour, all
1280 * the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001281 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001282void
1283xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001284 xmlNodePtr next;
1285 if (cur == NULL) {
1286 fprintf(stderr, "xmlFreeNodeList : node == NULL\n");
1287 return;
1288 }
1289 while (cur != NULL) {
1290 next = cur->next;
1291 xmlFreeNode(cur);
1292 cur = next;
1293 }
1294}
1295
Daniel Veillard97b58771998-10-20 06:14:16 +00001296/**
1297 * xmlFreeNode:
1298 * @cur: the node
1299 *
1300 * Free a node, this is a recursive behaviour, all the childs are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001301 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001302void
1303xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001304 if (cur == NULL) {
1305 fprintf(stderr, "xmlFreeNode : node == NULL\n");
1306 return;
1307 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001308 cur->doc = NULL;
1309 cur->parent = NULL;
1310 cur->next = NULL;
1311 cur->prev = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001312 if (cur->childs != NULL) xmlFreeNodeList(cur->childs);
Daniel Veillardccb09631998-10-27 06:21:04 +00001313 if (cur->properties != NULL) xmlFreePropList(cur->properties);
1314 if (cur->type != XML_ENTITY_REF_NODE)
1315 if (cur->content != NULL) free(cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001316 if (cur->name != NULL) free((char *) cur->name);
1317 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
1318 memset(cur, -1, sizeof(xmlNode));
1319 free(cur);
1320}
1321
Daniel Veillard16253641998-10-28 22:58:05 +00001322/**
1323 * xmlUnlinkNode:
1324 * @cur: the node
1325 *
1326 * Unlink a node from it's current context, the node is not freed
1327 */
1328void
1329xmlUnlinkNode(xmlNodePtr cur) {
1330 if (cur == NULL) {
1331 fprintf(stderr, "xmlUnlinkNode : node == NULL\n");
1332 return;
1333 }
1334 if ((cur->parent != NULL) && (cur->parent->childs == cur))
1335 cur->parent->childs = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001336 if ((cur->parent != NULL) && (cur->parent->last == cur))
1337 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00001338 if (cur->next != NULL)
1339 cur->next->prev = cur->prev;
1340 if (cur->prev != NULL)
1341 cur->prev->next = cur->next;
1342 cur->next = cur->prev = NULL;
1343 cur->parent = NULL;
1344}
1345
Daniel Veillard260a68f1998-08-13 03:39:55 +00001346/************************************************************************
1347 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001348 * Copy operations *
1349 * *
1350 ************************************************************************/
1351
1352/**
1353 * xmlCopyNamespace:
1354 * @cur: the namespace
1355 *
1356 * Do a copy of the namespace.
1357 *
1358 * Returns: a new xmlNsPtr, or NULL in case of error.
1359 */
1360xmlNsPtr
1361xmlCopyNamespace(xmlNsPtr cur) {
1362 xmlNsPtr ret;
1363
1364 if (cur == NULL) return(NULL);
1365 switch (cur->type) {
1366 case XML_GLOBAL_NAMESPACE:
1367 ret = xmlNewGlobalNs(NULL, cur->href, cur->prefix);
1368 break;
1369 case XML_LOCAL_NAMESPACE:
1370 ret = xmlNewNs(NULL, cur->href, cur->prefix);
1371 break;
1372 default:
1373 fprintf(stderr, "xmlCopyNamespace: unknown type %d\n", cur->type);
1374 return(NULL);
1375 }
1376 return(ret);
1377}
1378
1379/**
1380 * xmlCopyNamespaceList:
1381 * @cur: the first namespace
1382 *
1383 * Do a copy of an namespace list.
1384 *
1385 * Returns: a new xmlNsPtr, or NULL in case of error.
1386 */
1387xmlNsPtr
1388xmlCopyNamespaceList(xmlNsPtr cur) {
1389 xmlNsPtr ret = NULL;
1390 xmlNsPtr p = NULL,q;
1391
1392 while (cur != NULL) {
1393 q = xmlCopyNamespace(cur);
1394 if (p == NULL) {
1395 ret = p = q;
1396 } else {
1397 p->next = q;
1398 p = q;
1399 }
1400 cur = cur->next;
1401 }
1402 return(ret);
1403}
1404
1405/**
1406 * xmlCopyProp:
1407 * @cur: the attribute
1408 *
1409 * Do a copy of the attribute.
1410 *
1411 * Returns: a new xmlAttrPtr, or NULL in case of error.
1412 */
1413xmlAttrPtr
1414xmlCopyProp(xmlAttrPtr cur) {
1415 xmlAttrPtr ret;
1416
1417 if (cur == NULL) return(NULL);
1418 if (cur->val != NULL)
1419 ret = xmlNewDocProp(cur->val->doc, cur->name, NULL);
1420 else
1421 ret = xmlNewDocProp(NULL, cur->name, NULL);
1422 if (ret == NULL) return(NULL);
1423 if (cur->val != NULL)
1424 ret->val = xmlCopyNodeList(cur->val);
1425 return(ret);
1426}
1427
1428/**
1429 * xmlCopyPropList:
1430 * @cur: the first attribute
1431 *
1432 * Do a copy of an attribute list.
1433 *
1434 * Returns: a new xmlAttrPtr, or NULL in case of error.
1435 */
1436xmlAttrPtr
1437xmlCopyPropList(xmlAttrPtr cur) {
1438 xmlAttrPtr ret = NULL;
1439 xmlAttrPtr p = NULL,q;
1440
1441 while (cur != NULL) {
1442 q = xmlCopyProp(cur);
1443 if (p == NULL) {
1444 ret = p = q;
1445 } else {
1446 p->next = q;
1447 p = q;
1448 }
1449 cur = cur->next;
1450 }
1451 return(ret);
1452}
1453
1454/*
1455 * NOTE about the CopyNode operations !
1456 *
1457 * They are splitted into external and internal parts for one
1458 * tricky reason: namespaces. Doing a direct copy of a node
1459 * say RPM:Copyright without changing the namespace pointer to
1460 * something else can produce stale links. One way to do it is
1461 * to keep a reference counter but this doesn't work as soon
1462 * as one move the element or the subtree out of the scope of
1463 * the existing namespace. The actual solution seems to add
1464 * a copy of the namespace at the top of the copied tree if
1465 * not available in the subtree.
1466 * Hence two functions, the public front-end call the inner ones
1467 */
1468
1469static xmlNodePtr
1470xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
1471
1472static xmlNodePtr
1473xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
1474 int recursive) {
1475 xmlNodePtr ret;
1476
1477 if (node == NULL) return(NULL);
1478 /*
1479 * Allocate a new node and fill the fields.
1480 */
1481 ret = (xmlNodePtr) malloc(sizeof(xmlNode));
1482 if (ret == NULL) {
1483 fprintf(stderr, "xmlStaticCopyNode : malloc failed\n");
1484 return(NULL);
1485 }
1486
1487 ret->type = node->type;
1488 ret->doc = doc;
1489 ret->parent = parent;
1490 ret->next = NULL;
1491 ret->prev = NULL;
1492 ret->childs = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001493 ret->last = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001494 ret->properties = NULL;
1495 if (node->name != NULL)
1496 ret->name = xmlStrdup(node->name);
1497 else
1498 ret->name = NULL;
1499 ret->ns = NULL;
1500 ret->nsDef = NULL;
1501 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE))
1502 ret->content = xmlStrdup(node->content);
1503 else
1504 ret->content = NULL;
1505#ifndef WITHOUT_CORBA
1506 ret->_private = NULL;
1507 ret->vepv = NULL;
1508#endif
1509 if (parent != NULL)
1510 xmlAddChild(parent, ret);
1511
1512 if (!recursive) return(ret);
1513 if (node->properties != NULL)
1514 ret->properties = xmlCopyPropList(node->properties);
1515 if (node->nsDef != NULL)
1516 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
1517
1518 if (node->ns != NULL) {
1519 xmlNsPtr ns;
1520
1521 ns = xmlSearchNs(doc, ret, node->ns->prefix);
1522 if (ns == NULL) {
1523 /*
1524 * Humm, we are copying an element whose namespace is defined
1525 * out of the new tree scope. Search it in the original tree
1526 * and add it at the top of the new tree
1527 */
1528 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
1529 if (ns != NULL) {
1530 xmlNodePtr root = ret;
1531
1532 while (root->parent != NULL) root = root->parent;
1533 xmlNewNs(root, ns->href, ns->prefix);
1534 }
1535 } else {
1536 /*
1537 * reference the existing namespace definition in our own tree.
1538 */
1539 ret->ns = ns;
1540 }
1541 }
1542 if (node->childs != NULL)
1543 ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001544 UPDATE_LAST_CHILD(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001545 return(ret);
1546}
1547
1548static xmlNodePtr
1549xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
1550 xmlNodePtr ret = NULL;
1551 xmlNodePtr p = NULL,q;
1552
1553 while (node != NULL) {
1554 q = xmlStaticCopyNode(node, doc, parent, 1);
1555 if (parent == NULL) {
1556 if (ret == NULL) ret = q;
1557 } else {
1558 if (ret == NULL) {
1559 q->prev = NULL;
1560 ret = p = q;
1561 } else {
1562 p->next = q;
1563 q->prev = p;
1564 p = q;
1565 }
1566 }
1567 node = node->next;
1568 }
1569 return(ret);
1570}
1571
1572/**
1573 * xmlCopyNode:
1574 * @node: the node
1575 * @recursive: if 1 do a recursive copy.
1576 *
1577 * Do a copy of the node.
1578 *
1579 * Returns: a new xmlNodePtr, or NULL in case of error.
1580 */
1581xmlNodePtr
1582xmlCopyNode(xmlNodePtr node, int recursive) {
1583 xmlNodePtr ret;
1584
1585 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
1586 return(ret);
1587}
1588
1589/**
1590 * xmlCopyNodeList:
1591 * @node: the first node in the list.
1592 *
1593 * Do a recursive copy of the node list.
1594 *
1595 * Returns: a new xmlNodePtr, or NULL in case of error.
1596 */
1597xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
1598 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
1599 return(ret);
1600}
1601
1602/**
1603 * xmlCopyElement:
1604 * @elem: the element
1605 *
1606 * Do a copy of the element definition.
1607 *
1608 * Returns: a new xmlElementPtr, or NULL in case of error.
1609xmlElementPtr
1610xmlCopyElement(xmlElementPtr elem) {
1611 xmlElementPtr ret;
1612
1613 if (elem == NULL) return(NULL);
1614 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
1615 if (ret == NULL) return(NULL);
1616 if (!recursive) return(ret);
1617 if (elem->properties != NULL)
1618 ret->properties = xmlCopyPropList(elem->properties);
1619
1620 if (elem->nsDef != NULL)
1621 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
1622 if (elem->childs != NULL)
1623 ret->childs = xmlCopyElementList(elem->childs);
1624 return(ret);
1625}
1626 */
1627
1628/**
1629 * xmlCopyDtd:
1630 * @dtd: the dtd
1631 *
1632 * Do a copy of the dtd.
1633 *
1634 * Returns: a new xmlDtdPtr, or NULL in case of error.
1635 */
1636xmlDtdPtr
1637xmlCopyDtd(xmlDtdPtr dtd) {
1638 xmlDtdPtr ret;
1639
1640 if (dtd == NULL) return(NULL);
1641 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
1642 if (ret == NULL) return(NULL);
1643 if (dtd->entities != NULL)
1644 ret->entities = (void *) xmlCopyEntitiesTable(
1645 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001646 if (dtd->notations != NULL)
1647 ret->notations = (void *) xmlCopyNotationTable(
1648 (xmlNotationTablePtr) dtd->notations);
1649 if (dtd->elements != NULL)
1650 ret->elements = (void *) xmlCopyElementTable(
1651 (xmlElementTablePtr) dtd->elements);
1652 if (dtd->attributes != NULL)
1653 ret->attributes = (void *) xmlCopyAttributeTable(
1654 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001655 /*
1656 * TODO: support for Element definitions.
1657 */
1658 return(ret);
1659}
1660
1661/**
1662 * xmlCopyDoc:
1663 * @doc: the document
1664 * @recursive: if 1 do a recursive copy.
1665 *
1666 * Do a copy of the document info. If recursive, the content tree will
1667 * be copied too as well as Dtd, namespaces and entities.
1668 *
1669 * Returns: a new xmlDocPtr, or NULL in case of error.
1670 */
1671xmlDocPtr
1672xmlCopyDoc(xmlDocPtr doc, int recursive) {
1673 xmlDocPtr ret;
1674
1675 if (doc == NULL) return(NULL);
1676 ret = xmlNewDoc(doc->version);
1677 if (ret == NULL) return(NULL);
1678 if (doc->name != NULL)
1679 ret->name = strdup(doc->name);
1680 if (doc->encoding != NULL)
1681 ret->encoding = xmlStrdup(doc->encoding);
1682 ret->compression = doc->compression;
1683 ret->standalone = doc->standalone;
1684 if (!recursive) return(ret);
1685
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001686 if (doc->intSubset != NULL)
1687 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001688 if (doc->oldNs != NULL)
1689 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
1690 if (doc->root != NULL)
1691 ret->root = xmlStaticCopyNodeList(doc->root, ret, NULL);
1692 return(ret);
1693}
1694
1695/************************************************************************
1696 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001697 * Content access functions *
1698 * *
1699 ************************************************************************/
1700
Daniel Veillard97b58771998-10-20 06:14:16 +00001701/**
Daniel Veillard16253641998-10-28 22:58:05 +00001702 * xmlNodeGetContent:
1703 * @cur: the node being read
1704 *
1705 * Read the value of a node, this can be either the text carried
1706 * directly by this node if it's a TEXT node or the aggregate string
1707 * of the values carried by this node child's (TEXT and ENTITY_REF).
1708 * Entity references are substitued.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001709 * Returns a new CHAR * or NULL if no content is available.
Daniel Veillard16253641998-10-28 22:58:05 +00001710 */
1711CHAR *
1712xmlNodeGetContent(xmlNodePtr cur) {
1713 if (cur == NULL) return(NULL);
1714 switch (cur->type) {
1715 case XML_DOCUMENT_FRAG_NODE:
1716 case XML_ELEMENT_NODE:
1717 return(xmlNodeListGetString(cur->doc, cur->childs, 1));
1718 break;
1719 case XML_ATTRIBUTE_NODE:
1720 case XML_CDATA_SECTION_NODE:
1721 case XML_ENTITY_REF_NODE:
1722 case XML_ENTITY_NODE:
1723 case XML_PI_NODE:
1724 case XML_COMMENT_NODE:
1725 case XML_DOCUMENT_NODE:
1726 case XML_DOCUMENT_TYPE_NODE:
1727 case XML_NOTATION_NODE:
1728 return(NULL);
1729 case XML_TEXT_NODE:
1730 if (cur->content != NULL)
1731 return(xmlStrdup(cur->content));
1732 return(NULL);
1733 }
1734 return(NULL);
1735}
1736
1737/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001738 * xmlNodeSetContent:
1739 * @cur: the node being modified
1740 * @content: the new value of the content
1741 *
1742 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001743 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001744void
1745xmlNodeSetContent(xmlNodePtr cur, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001746 if (cur == NULL) {
1747 fprintf(stderr, "xmlNodeSetContent : node == NULL\n");
1748 return;
1749 }
Daniel Veillard16253641998-10-28 22:58:05 +00001750 switch (cur->type) {
1751 case XML_DOCUMENT_FRAG_NODE:
1752 case XML_ELEMENT_NODE:
1753 if (cur->content != NULL) {
1754 free(cur->content);
1755 cur->content = NULL;
1756 }
1757 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1758 cur->childs = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001759 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001760 break;
1761 case XML_ATTRIBUTE_NODE:
1762 break;
1763 case XML_TEXT_NODE:
1764 case XML_CDATA_SECTION_NODE:
1765 case XML_ENTITY_REF_NODE:
1766 case XML_ENTITY_NODE:
1767 case XML_PI_NODE:
1768 case XML_COMMENT_NODE:
1769 if (cur->content != NULL) free(cur->content);
1770 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001771 cur->last = cur->childs = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001772 if (content != NULL)
1773 cur->content = xmlStrdup(content);
1774 else
1775 cur->content = NULL;
1776 case XML_DOCUMENT_NODE:
1777 case XML_DOCUMENT_TYPE_NODE:
1778 break;
1779 case XML_NOTATION_NODE:
1780 break;
1781 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001782}
1783
Daniel Veillard97b58771998-10-20 06:14:16 +00001784/**
1785 * xmlNodeSetContentLen:
1786 * @cur: the node being modified
1787 * @content: the new value of the content
1788 * @len: the size of @content
1789 *
1790 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001791 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001792void
1793xmlNodeSetContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001794 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001795 fprintf(stderr, "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001796 return;
1797 }
Daniel Veillard16253641998-10-28 22:58:05 +00001798 switch (cur->type) {
1799 case XML_DOCUMENT_FRAG_NODE:
1800 case XML_ELEMENT_NODE:
1801 if (cur->content != NULL) {
1802 free(cur->content);
1803 cur->content = NULL;
1804 }
1805 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1806 cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001807 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001808 break;
1809 case XML_ATTRIBUTE_NODE:
1810 break;
1811 case XML_TEXT_NODE:
1812 case XML_CDATA_SECTION_NODE:
1813 case XML_ENTITY_REF_NODE:
1814 case XML_ENTITY_NODE:
1815 case XML_PI_NODE:
1816 case XML_COMMENT_NODE:
1817 if (cur->content != NULL) free(cur->content);
1818 if (cur->childs != NULL) xmlFreeNode(cur->childs);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001819 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001820 if (content != NULL)
1821 cur->content = xmlStrndup(content, len);
1822 else
1823 cur->content = NULL;
1824 case XML_DOCUMENT_NODE:
1825 case XML_DOCUMENT_TYPE_NODE:
1826 break;
1827 case XML_NOTATION_NODE:
1828 if (cur->content != NULL) free(cur->content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001829 if (cur->childs != NULL) xmlFreeNode(cur->childs);
1830 cur->childs = cur->last = NULL;
Daniel Veillard16253641998-10-28 22:58:05 +00001831 if (content != NULL)
1832 cur->content = xmlStrndup(content, len);
1833 else
1834 cur->content = NULL;
1835 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001836 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001837}
1838
Daniel Veillard97b58771998-10-20 06:14:16 +00001839/**
1840 * xmlNodeAddContentLen:
1841 * @cur: the node being modified
1842 * @content: extra content
1843 * @len: the size of @content
1844 *
1845 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001846 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001847void
1848xmlNodeAddContentLen(xmlNodePtr cur, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001849 if (cur == NULL) {
Daniel Veillard16253641998-10-28 22:58:05 +00001850 fprintf(stderr, "xmlNodeAddContentLen : node == NULL\n");
1851 return;
1852 }
1853 if (len <= 0) return;
1854 switch (cur->type) {
1855 case XML_DOCUMENT_FRAG_NODE:
1856 case XML_ELEMENT_NODE: {
1857 xmlNodePtr last = NULL, new;
1858
1859 if (cur->childs != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001860 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001861 } else {
1862 if (cur->content != NULL) {
1863 cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001864 UPDATE_LAST_CHILD(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00001865 free(cur->content);
1866 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001867 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00001868 }
1869 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001870 new = xmlNewTextLen(content, len);
Daniel Veillard16253641998-10-28 22:58:05 +00001871 if (new != NULL) {
1872 xmlAddChild(cur, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001873 if ((last != NULL) && (last->next == new)) {
Daniel Veillard16253641998-10-28 22:58:05 +00001874 xmlTextMerge(last, new);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001875 }
Daniel Veillard16253641998-10-28 22:58:05 +00001876 }
1877 break;
1878 }
1879 case XML_ATTRIBUTE_NODE:
1880 break;
1881 case XML_TEXT_NODE:
1882 case XML_CDATA_SECTION_NODE:
1883 case XML_ENTITY_REF_NODE:
1884 case XML_ENTITY_NODE:
1885 case XML_PI_NODE:
1886 case XML_COMMENT_NODE:
1887 if (content != NULL)
1888 cur->content = xmlStrncat(cur->content, content, len);
1889 case XML_DOCUMENT_NODE:
1890 case XML_DOCUMENT_TYPE_NODE:
1891 break;
1892 case XML_NOTATION_NODE:
1893 if (content != NULL)
1894 cur->content = xmlStrncat(cur->content, content, len);
1895 break;
1896 }
1897}
1898
1899/**
1900 * xmlNodeAddContent:
1901 * @cur: the node being modified
1902 * @content: extra content
1903 *
1904 * Append the extra substring to the node content.
1905 */
1906void
1907xmlNodeAddContent(xmlNodePtr cur, const CHAR *content) {
1908 int len;
1909
1910 if (cur == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001911 fprintf(stderr, "xmlNodeAddContent : node == NULL\n");
1912 return;
1913 }
Daniel Veillard16253641998-10-28 22:58:05 +00001914 if (content == NULL) return;
1915 len = xmlStrlen(content);
1916 xmlNodeAddContentLen(cur, content, len);
1917}
1918
1919/**
1920 * xmlTextMerge:
1921 * @first: the first text node
1922 * @second: the second text node being merged
1923 *
1924 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00001925 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00001926 */
1927xmlNodePtr
1928xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
1929 if (first == NULL) return(second);
1930 if (second == NULL) return(first);
1931 if (first->type != XML_TEXT_NODE) return(first);
1932 if (second->type != XML_TEXT_NODE) return(first);
1933 xmlNodeAddContent(first, second->content);
1934 xmlUnlinkNode(second);
1935 xmlFreeNode(second);
1936 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001937}
1938
Daniel Veillard97b58771998-10-20 06:14:16 +00001939/**
1940 * xmlSearchNs:
1941 * @doc: the document
1942 * @node: the current node
1943 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00001944 *
Daniel Veillard97b58771998-10-20 06:14:16 +00001945 * Search a Ns registered under a given name space for a document.
1946 * recurse on the parents until it finds the defined namespace
1947 * or return NULL otherwise.
1948 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001949 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001950 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001951xmlNsPtr
1952xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const CHAR *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001953 xmlNsPtr cur;
1954
1955 while (node != NULL) {
1956 cur = node->nsDef;
1957 while (cur != NULL) {
1958 if ((cur->prefix == NULL) && (nameSpace == NULL))
1959 return(cur);
1960 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1961 (!xmlStrcmp(cur->prefix, nameSpace)))
1962 return(cur);
1963 cur = cur->next;
1964 }
1965 node = node->parent;
1966 }
1967 if (doc != NULL) {
1968 cur = doc->oldNs;
1969 while (cur != NULL) {
1970 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
1971 (!xmlStrcmp(cur->prefix, nameSpace)))
1972 return(cur);
1973 cur = cur->next;
1974 }
1975 }
1976 return(NULL);
1977}
1978
Daniel Veillard97b58771998-10-20 06:14:16 +00001979/**
1980 * xmlSearchNsByHref:
1981 * @doc: the document
1982 * @node: the current node
1983 * @href: the namespace value
1984 *
1985 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
1986 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001987 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001988 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001989xmlNsPtr
1990xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const CHAR *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001991 xmlNsPtr cur;
1992
1993 while (node != NULL) {
1994 cur = node->nsDef;
1995 while (cur != NULL) {
1996 if ((cur->href != NULL) && (href != NULL) &&
1997 (!xmlStrcmp(cur->href, href)))
1998 return(cur);
1999 cur = cur->next;
2000 }
2001 node = node->parent;
2002 }
2003 if (doc != NULL) {
2004 cur = doc->oldNs;
2005 while (cur != NULL) {
2006 if ((cur->href != NULL) && (href != NULL) &&
2007 (!xmlStrcmp(cur->href, href)))
2008 return(cur);
2009 cur = cur->next;
2010 }
2011 }
2012 return(NULL);
2013}
2014
Daniel Veillard97b58771998-10-20 06:14:16 +00002015/**
2016 * xmlGetProp:
2017 * @node: the node
2018 * @name: the attribute name
2019 *
2020 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00002021 * This does the entity substitution.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002022 * Returns the attribute value or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002023 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002024CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002025 xmlAttrPtr prop = node->properties;
2026
2027 while (prop != NULL) {
Daniel Veillard68178931999-02-08 18:34:36 +00002028 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillard6800ef31999-02-08 18:33:22 +00002029 CHAR *ret;
2030
2031 ret = xmlNodeListGetString(node->doc, prop->val, 1);
2032 if (ret == NULL) return(xmlStrdup(""));
2033 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00002034 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002035 prop = prop->next;
2036 }
2037 return(NULL);
2038}
2039
Daniel Veillard97b58771998-10-20 06:14:16 +00002040/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002041 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00002042 * @node: the node
2043 * @name: the attribute name
2044 * @value: the attribute value
2045 *
2046 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002047 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002048 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002049xmlAttrPtr
2050xmlSetProp(xmlNodePtr node, const CHAR *name, const CHAR *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002051 xmlAttrPtr prop = node->properties;
2052
2053 while (prop != NULL) {
2054 if (!xmlStrcmp(prop->name, name)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002055 if (prop->val != NULL)
2056 xmlFreeNode(prop->val);
2057 prop->val = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002058 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00002059 prop->val = xmlStringGetNodeList(node->doc, value);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002060 return(prop);
2061 }
2062 prop = prop->next;
2063 }
2064 prop = xmlNewProp(node, name, value);
2065 return(prop);
2066}
2067
Daniel Veillard97b58771998-10-20 06:14:16 +00002068/**
2069 * xmlNodeIsText:
2070 * @node: the node
2071 *
2072 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00002073 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00002074 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002075int
2076xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002077 if (node == NULL) return(0);
2078
Daniel Veillard0bef1311998-10-14 02:36:47 +00002079 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002080 return(0);
2081}
2082
Daniel Veillard97b58771998-10-20 06:14:16 +00002083/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00002084 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00002085 * @node: the node
2086 * @content: the content
2087 * @len: @content lenght
2088 *
2089 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00002090 */
Daniel Veillard97b58771998-10-20 06:14:16 +00002091
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002092void
2093xmlTextConcat(xmlNodePtr node, const CHAR *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002094 if (node == NULL) return;
2095
Daniel Veillard0bef1311998-10-14 02:36:47 +00002096 if (node->type != XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002097 fprintf(stderr, "xmlTextConcat: node is not text\n");
2098 return;
2099 }
2100 node->content = xmlStrncat(node->content, content, len);
2101}
2102
2103/************************************************************************
2104 * *
2105 * Output : to a FILE or in memory *
2106 * *
2107 ************************************************************************/
2108
Daniel Veillard260a68f1998-08-13 03:39:55 +00002109static CHAR *buffer = NULL;
2110static int buffer_index = 0;
2111static int buffer_size = 0;
2112
Daniel Veillard97b58771998-10-20 06:14:16 +00002113/**
2114 * xmlBufferWriteCHAR:
2115 * @string: the string to add
2116 *
2117 * routine which manage and grows an output buffer. This one add
2118 * CHARs at the end of the array.
2119 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002120void
2121xmlBufferWriteCHAR(const CHAR *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002122 const CHAR *cur;
2123
2124 if (buffer == NULL) {
2125 buffer_size = 50000;
2126 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2127 if (buffer == NULL) {
2128 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2129 exit(1);
2130 }
2131 }
2132
2133 if (string == NULL) return;
2134 for (cur = string;*cur != 0;cur++) {
2135 if (buffer_index + 10 >= buffer_size) {
2136 buffer_size *= 2;
2137 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2138 if (buffer == NULL) {
2139 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2140 exit(1);
2141 }
2142 }
2143 buffer[buffer_index++] = *cur;
2144 }
2145 buffer[buffer_index] = 0;
2146}
2147
Daniel Veillard97b58771998-10-20 06:14:16 +00002148/**
2149 * xmlBufferWriteChar:
2150 * @string: the string to add
2151 *
2152 * routine which manage and grows an output buffer. This one add
2153 * C chars at the end of the array.
2154 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002155void
2156xmlBufferWriteChar(const char *string) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002157 const char *cur;
2158
2159 if (buffer == NULL) {
2160 buffer_size = 50000;
2161 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
2162 if (buffer == NULL) {
2163 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2164 exit(1);
2165 }
2166 }
2167
2168 if (string == NULL) return;
2169 for (cur = string;*cur != 0;cur++) {
2170 if (buffer_index + 10 >= buffer_size) {
2171 buffer_size *= 2;
2172 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
2173 if (buffer == NULL) {
2174 fprintf(stderr, "xmlBufferWrite : out of memory!\n");
2175 exit(1);
2176 }
2177 }
2178 buffer[buffer_index++] = *cur;
2179 }
2180 buffer[buffer_index] = 0;
2181}
2182
Daniel Veillard97b58771998-10-20 06:14:16 +00002183/**
2184 * xmlGlobalNsDump:
2185 * @cur: a namespace
2186 *
2187 * Dump a global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002188 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002189static void
2190xmlGlobalNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002191 if (cur == NULL) {
2192 fprintf(stderr, "xmlGlobalNsDump : Ns == NULL\n");
2193 return;
2194 }
2195 if (cur->type == XML_GLOBAL_NAMESPACE) {
2196 xmlBufferWriteChar("<?namespace");
2197 if (cur->href != NULL) {
2198 xmlBufferWriteChar(" href=\"");
2199 xmlBufferWriteCHAR(cur->href);
2200 xmlBufferWriteChar("\"");
2201 }
2202 if (cur->prefix != NULL) {
2203 xmlBufferWriteChar(" AS=\"");
2204 xmlBufferWriteCHAR(cur->prefix);
2205 xmlBufferWriteChar("\"");
2206 }
2207 xmlBufferWriteChar("?>\n");
2208 }
2209}
2210
Daniel Veillard97b58771998-10-20 06:14:16 +00002211/**
2212 * xmlGlobalNsListDump:
2213 * @cur: the first namespace
2214 *
2215 * Dump a list of global Namespace, this is the old version based on PIs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002216 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002217static void
2218xmlGlobalNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002219 while (cur != NULL) {
2220 xmlGlobalNsDump(cur);
2221 cur = cur->next;
2222 }
2223}
2224
Daniel Veillard97b58771998-10-20 06:14:16 +00002225/**
2226 * xmlNsDump:
2227 * @cur: a namespace
2228 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002229 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00002230 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002231 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002232static void
2233xmlNsDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002234 if (cur == NULL) {
2235 fprintf(stderr, "xmlNsDump : Ns == NULL\n");
2236 return;
2237 }
2238 if (cur->type == XML_LOCAL_NAMESPACE) {
2239 /* Within the context of an element attributes */
2240 if (cur->prefix != NULL) {
2241 xmlBufferWriteChar(" xmlns:");
2242 xmlBufferWriteCHAR(cur->prefix);
2243 } else
2244 xmlBufferWriteChar(" xmlns");
2245 xmlBufferWriteChar("=\"");
2246 xmlBufferWriteCHAR(cur->href);
2247 xmlBufferWriteChar("\"");
2248 }
2249}
2250
Daniel Veillard97b58771998-10-20 06:14:16 +00002251/**
2252 * xmlNsListDump:
2253 * @cur: the first namespace
2254 *
2255 * Dump a list of local Namespace definitions.
2256 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002257 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002258static void
2259xmlNsListDump(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002260 while (cur != NULL) {
2261 xmlNsDump(cur);
2262 cur = cur->next;
2263 }
2264}
2265
Daniel Veillard97b58771998-10-20 06:14:16 +00002266/**
2267 * xmlDtdDump:
2268 * @doc: the document
2269 *
2270 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002271 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002272static void
2273xmlDtdDump(xmlDocPtr doc) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002274 xmlDtdPtr cur = doc->intSubset;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002275
2276 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002277 fprintf(stderr, "xmlDtdDump : no internal subset\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002278 return;
2279 }
2280 xmlBufferWriteChar("<!DOCTYPE ");
2281 xmlBufferWriteCHAR(cur->name);
2282 if (cur->ExternalID != NULL) {
2283 xmlBufferWriteChar(" PUBLIC \"");
2284 xmlBufferWriteCHAR(cur->ExternalID);
2285 xmlBufferWriteChar("\" \"");
2286 xmlBufferWriteCHAR(cur->SystemID);
2287 xmlBufferWriteChar("\"");
2288 } else if (cur->SystemID != NULL) {
2289 xmlBufferWriteChar(" SYSTEM \"");
2290 xmlBufferWriteCHAR(cur->SystemID);
2291 xmlBufferWriteChar("\"");
2292 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002293 if ((cur->entities == NULL) && (cur->elements == NULL) &&
2294 (cur->attributes == NULL) && (cur->notations == NULL)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002295 xmlBufferWriteChar(">\n");
2296 return;
2297 }
2298 xmlBufferWriteChar(" [\n");
2299 if (cur->entities != NULL)
2300 xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002301 if (cur->notations != NULL)
2302 xmlDumpNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002303 if (cur->elements != NULL)
2304 xmlDumpElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002305 if (cur->attributes != NULL)
2306 xmlDumpAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002307 xmlBufferWriteChar("]");
2308
2309 /* TODO !!! a lot more things to dump ... */
2310 xmlBufferWriteChar(">\n");
2311}
2312
Daniel Veillard97b58771998-10-20 06:14:16 +00002313/**
2314 * xmlAttrDump:
2315 * @doc: the document
2316 * @cur: the attribute pointer
2317 *
2318 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00002319 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002320static void
2321xmlAttrDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002322 CHAR *value;
2323
Daniel Veillard260a68f1998-08-13 03:39:55 +00002324 if (cur == NULL) {
2325 fprintf(stderr, "xmlAttrDump : property == NULL\n");
2326 return;
2327 }
2328 xmlBufferWriteChar(" ");
2329 xmlBufferWriteCHAR(cur->name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002330 value = xmlNodeListGetString(doc, cur->val, 0);
2331 if (value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002332 xmlBufferWriteChar("=\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00002333 xmlBufferWriteCHAR(value);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002334 xmlBufferWriteChar("\"");
Daniel Veillardccb09631998-10-27 06:21:04 +00002335 free(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00002336 } else {
2337 xmlBufferWriteChar("=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002338 }
2339}
2340
Daniel Veillard97b58771998-10-20 06:14:16 +00002341/**
2342 * xmlAttrListDump:
2343 * @doc: the document
2344 * @cur: the first attribute pointer
2345 *
2346 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00002347 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002348static void
2349xmlAttrListDump(xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002350 if (cur == NULL) {
2351 fprintf(stderr, "xmlAttrListDump : property == NULL\n");
2352 return;
2353 }
2354 while (cur != NULL) {
2355 xmlAttrDump(doc, cur);
2356 cur = cur->next;
2357 }
2358}
2359
Daniel Veillard260a68f1998-08-13 03:39:55 +00002360
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002361static void
2362xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level);
Daniel Veillard97b58771998-10-20 06:14:16 +00002363/**
2364 * xmlNodeListDump:
2365 * @doc: the document
2366 * @cur: the first node
2367 * @level: the imbrication level for indenting
2368 *
2369 * Dump an XML node list, recursive behaviour,children are printed too.
2370 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002371static void
2372xmlNodeListDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002373 int needIndent = 0, i;
2374
Daniel Veillard260a68f1998-08-13 03:39:55 +00002375 if (cur == NULL) {
2376 fprintf(stderr, "xmlNodeListDump : node == NULL\n");
2377 return;
2378 }
2379 while (cur != NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002380 if ((cur->type != XML_TEXT_NODE) &&
2381 (cur->type != XML_ENTITY_REF_NODE)) {
2382 if (!needIndent) {
2383 needIndent = 1;
2384 xmlBufferWriteChar("\n");
2385 }
2386 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002387 xmlNodeDump(doc, cur, level);
2388 cur = cur->next;
2389 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002390 if ((xmlIndentTreeOutput) && (needIndent))
2391 for (i = 1;i < level;i++)
2392 xmlBufferWriteChar(" ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002393}
2394
Daniel Veillard97b58771998-10-20 06:14:16 +00002395/**
Daniel Veillardccb09631998-10-27 06:21:04 +00002396 * xmlNodeDump:
Daniel Veillard97b58771998-10-20 06:14:16 +00002397 * @doc: the document
2398 * @cur: the current node
2399 * @level: the imbrication level for indenting
2400 *
2401 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002402 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002403static void
2404xmlNodeDump(xmlDocPtr doc, xmlNodePtr cur, int level) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002405 int i;
2406
2407 if (cur == NULL) {
2408 fprintf(stderr, "xmlNodeDump : node == NULL\n");
2409 return;
2410 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002411 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002412 if (cur->content != NULL)
2413 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2414 return;
2415 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00002416 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002417 if (cur->content != NULL) {
2418 xmlBufferWriteChar("<!--");
2419 xmlBufferWriteCHAR(cur->content);
2420 xmlBufferWriteChar("-->");
2421 }
2422 return;
2423 }
Daniel Veillardccb09631998-10-27 06:21:04 +00002424 if (cur->type == XML_ENTITY_REF_NODE) {
2425 xmlBufferWriteChar("&");
2426 xmlBufferWriteCHAR(cur->name);
2427 xmlBufferWriteChar(";");
2428 return;
2429 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002430 if (xmlIndentTreeOutput)
2431 for (i = 0;i < level;i++)
2432 xmlBufferWriteChar(" ");
2433
2434 xmlBufferWriteChar("<");
2435 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2436 xmlBufferWriteCHAR(cur->ns->prefix);
2437 xmlBufferWriteChar(":");
2438 }
2439
2440 xmlBufferWriteCHAR(cur->name);
2441 if (cur->nsDef)
2442 xmlNsListDump(cur->nsDef);
2443 if (cur->properties != NULL)
2444 xmlAttrListDump(doc, cur->properties);
2445
2446 if ((cur->content == NULL) && (cur->childs == NULL)) {
2447 xmlBufferWriteChar("/>\n");
2448 return;
2449 }
2450 xmlBufferWriteChar(">");
2451 if (cur->content != NULL)
2452 xmlBufferWriteCHAR(xmlEncodeEntities(doc, cur->content));
2453 if (cur->childs != NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002454 xmlNodeListDump(doc, cur->childs, level + 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002455 }
2456 xmlBufferWriteChar("</");
2457 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
2458 xmlBufferWriteCHAR(cur->ns->prefix);
2459 xmlBufferWriteChar(":");
2460 }
2461
2462 xmlBufferWriteCHAR(cur->name);
2463 xmlBufferWriteChar(">\n");
2464}
2465
Daniel Veillard97b58771998-10-20 06:14:16 +00002466/**
2467 * xmlDocContentDump:
2468 * @cur: the document
2469 *
2470 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002471 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002472static void
2473xmlDocContentDump(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002474 if (oldXMLWDcompatibility)
2475 xmlBufferWriteChar("<?XML version=\"");
2476 else
2477 xmlBufferWriteChar("<?xml version=\"");
2478 xmlBufferWriteCHAR(cur->version);
2479 xmlBufferWriteChar("\"");
2480 if (cur->encoding != NULL) {
2481 xmlBufferWriteChar(" encoding=\"");
2482 xmlBufferWriteCHAR(cur->encoding);
2483 xmlBufferWriteChar("\"");
2484 }
2485 switch (cur->standalone) {
2486 case 0:
2487 xmlBufferWriteChar(" standalone=\"no\"");
2488 break;
2489 case 1:
2490 xmlBufferWriteChar(" standalone=\"yes\"");
2491 break;
2492 }
2493 xmlBufferWriteChar("?>\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002494 if (cur->intSubset != NULL)
Daniel Veillard260a68f1998-08-13 03:39:55 +00002495 xmlDtdDump(cur);
2496 if (cur->root != NULL) {
2497 /* global namespace definitions, the old way */
2498 if (oldXMLWDcompatibility)
2499 xmlGlobalNsListDump(cur->oldNs);
2500 else
2501 xmlUpgradeOldNs(cur);
2502 xmlNodeDump(cur, cur->root, 0);
2503 }
2504}
2505
Daniel Veillard97b58771998-10-20 06:14:16 +00002506/**
2507 * xmlDocDumpMemory:
2508 * @cur: the document
2509 * @mem: OUT: the memory pointer
2510 * @size: OUT: the memory lenght
2511 *
2512 * Dump an XML document in memory and return the CHAR * and it's size.
2513 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002514 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002515void
2516xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002517 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002518#ifdef DEBUG_TREE
2519 fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
2520#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002521 *mem = NULL;
2522 *size = 0;
2523 return;
2524 }
2525 buffer_index = 0;
2526 xmlDocContentDump(cur);
2527
2528 *mem = buffer;
2529 *size = buffer_index;
2530}
2531
Daniel Veillard97b58771998-10-20 06:14:16 +00002532/**
2533 * xmlGetDocCompressMode:
2534 * @doc: the document
2535 *
2536 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00002537 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00002538 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002539int
2540 xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002541 if (doc == NULL) return(-1);
2542 return(doc->compression);
2543}
2544
Daniel Veillard97b58771998-10-20 06:14:16 +00002545/**
2546 * xmlSetDocCompressMode:
2547 * @doc: the document
2548 * @mode: the compression ratio
2549 *
2550 * set the compression ratio for a document, ZLIB based
2551 * Correct values: 0 (uncompressed) to 9 (max compression)
2552 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002553void
2554xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00002555 if (doc == NULL) return;
2556 if (mode < 0) doc->compression = 0;
2557 else if (mode > 9) doc->compression = 9;
2558 else doc->compression = mode;
2559}
2560
Daniel Veillard97b58771998-10-20 06:14:16 +00002561/**
2562 * xmlGetCompressMode:
2563 *
2564 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002565 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00002566 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002567int
2568 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002569 return(xmlCompressMode);
2570}
Daniel Veillard97b58771998-10-20 06:14:16 +00002571
2572/**
2573 * xmlSetCompressMode:
2574 * @mode: the compression ratio
2575 *
2576 * set the default compression mode used, ZLIB based
2577 * Correct values: 0 (uncompressed) to 9 (max compression)
2578 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002579void
2580xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002581 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00002582 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002583 else xmlCompressMode = mode;
2584}
2585
Daniel Veillard97b58771998-10-20 06:14:16 +00002586/**
2587 * xmlDocDump:
2588 * @f: the FILE*
2589 * @cur: the document
2590 *
2591 * Dump an XML document to an open FILE.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002592 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002593void
2594xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002595 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002596#ifdef DEBUG_TREE
Daniel Veillard260a68f1998-08-13 03:39:55 +00002597 fprintf(stderr, "xmlDocDump : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002598#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002599 return;
2600 }
2601 buffer_index = 0;
2602 xmlDocContentDump(cur);
2603
2604 fwrite(buffer, sizeof(CHAR), buffer_index, f);
2605}
2606
Daniel Veillard97b58771998-10-20 06:14:16 +00002607/**
2608 * xmlSaveFile:
2609 * @filename: the filename
2610 * @cur: the document
2611 *
2612 * Dump an XML document to a file. Will use compression if
2613 * compiled in and enabled.
2614 * returns: the number of file written or -1 in case of failure.
Daniel Veillard151b1b01998-09-23 00:49:46 +00002615 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002616int
2617xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00002618#ifdef HAVE_ZLIB_H
2619 gzFile zoutput = NULL;
2620 char mode[15];
2621#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002622 FILE *output = NULL;
Daniel Veillard151b1b01998-09-23 00:49:46 +00002623 int ret;
2624
2625#ifdef HAVE_ZLIB_H
Daniel Veillarddc3dd9d1998-09-24 19:25:54 +00002626 if ((cur->compression > 0) && (cur->compression <= 9)) {
2627 sprintf(mode, "w%d", cur->compression);
Daniel Veillard151b1b01998-09-23 00:49:46 +00002628 zoutput = gzopen(filename, mode);
2629 }
2630 if (zoutput == NULL) {
2631#endif
2632 output = fopen(filename, "w");
2633 if (output == NULL) return(-1);
2634#ifdef HAVE_ZLIB_H
2635 }
2636#endif
2637
2638 /*
2639 * save the content to a temp buffer.
2640 */
2641 buffer_index = 0;
2642 xmlDocContentDump(cur);
2643
2644#ifdef HAVE_ZLIB_H
2645 if (zoutput != NULL) {
2646 ret = gzwrite(zoutput, buffer, sizeof(CHAR) * buffer_index);
2647 gzclose(zoutput);
2648 return(ret);
2649 }
2650#endif
2651 ret = fwrite(buffer, sizeof(CHAR), buffer_index, output);
2652 fclose(output);
2653 return(ret * sizeof(CHAR));
2654}
2655