blob: 99c3989ed36eb6ce154b05eba0286fb5e5e861cf [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * tree.c : implemetation of access function for an XML tree.
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
12 */
13
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000036
Daniel Veillard56a4cb82001-03-24 17:00:36 +000037xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
38
39/************************************************************************
40 * *
41 * A few static variables and macros *
42 * *
43 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000044/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000045const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000046/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000047const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000048 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000049/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000050const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
51
Owen Taylor3473f882001-02-23 17:55:21 +000052static int xmlCompressMode = 0;
53static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000054
Owen Taylor3473f882001-02-23 17:55:21 +000055#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
56 xmlNodePtr ulccur = (n)->children; \
57 if (ulccur == NULL) { \
58 (n)->last = NULL; \
59 } else { \
60 while (ulccur->next != NULL) { \
61 ulccur->parent = (n); \
62 ulccur = ulccur->next; \
63 } \
64 ulccur->parent = (n); \
65 (n)->last = ulccur; \
66}}
67
68/* #define DEBUG_BUFFER */
69/* #define DEBUG_TREE */
70
71/************************************************************************
72 * *
73 * Allocation and deallocation of basic structures *
74 * *
75 ************************************************************************/
76
77/**
78 * xmlSetBufferAllocationScheme:
79 * @scheme: allocation method to use
80 *
81 * Set the buffer allocation method. Types are
82 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
83 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
84 * improves performance
85 */
86void
87xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
88 xmlBufferAllocScheme = scheme;
89}
90
91/**
92 * xmlGetBufferAllocationScheme:
93 *
94 * Types are
95 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
96 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
97 * improves performance
98 *
99 * Returns the current allocation scheme
100 */
101xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000102xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000103 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000104}
105
106/**
107 * xmlNewNs:
108 * @node: the element carrying the namespace
109 * @href: the URI associated
110 * @prefix: the prefix for the namespace
111 *
112 * Creation of a new Namespace. This function will refuse to create
113 * a namespace with a similar prefix than an existing one present on this
114 * node.
115 * We use href==NULL in the case of an element creation where the namespace
116 * was not defined.
117 * Returns returns a new namespace pointer or NULL
118 */
119xmlNsPtr
120xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
121 xmlNsPtr cur;
122
123 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
124 return(NULL);
125
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000126 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
127 return(NULL);
128
Owen Taylor3473f882001-02-23 17:55:21 +0000129 /*
130 * Allocate a new Namespace and fill the fields.
131 */
132 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
133 if (cur == NULL) {
134 xmlGenericError(xmlGenericErrorContext,
135 "xmlNewNs : malloc failed\n");
136 return(NULL);
137 }
138 memset(cur, 0, sizeof(xmlNs));
139 cur->type = XML_LOCAL_NAMESPACE;
140
141 if (href != NULL)
142 cur->href = xmlStrdup(href);
143 if (prefix != NULL)
144 cur->prefix = xmlStrdup(prefix);
145
146 /*
147 * Add it at the end to preserve parsing order ...
148 * and checks for existing use of the prefix
149 */
150 if (node != NULL) {
151 if (node->nsDef == NULL) {
152 node->nsDef = cur;
153 } else {
154 xmlNsPtr prev = node->nsDef;
155
156 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
157 (xmlStrEqual(prev->prefix, cur->prefix))) {
158 xmlFreeNs(cur);
159 return(NULL);
160 }
161 while (prev->next != NULL) {
162 prev = prev->next;
163 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
164 (xmlStrEqual(prev->prefix, cur->prefix))) {
165 xmlFreeNs(cur);
166 return(NULL);
167 }
168 }
169 prev->next = cur;
170 }
171 }
172 return(cur);
173}
174
175/**
176 * xmlSetNs:
177 * @node: a node in the document
178 * @ns: a namespace pointer
179 *
180 * Associate a namespace to a node, a posteriori.
181 */
182void
183xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
184 if (node == NULL) {
185#ifdef DEBUG_TREE
186 xmlGenericError(xmlGenericErrorContext,
187 "xmlSetNs: node == NULL\n");
188#endif
189 return;
190 }
191 node->ns = ns;
192}
193
194/**
195 * xmlFreeNs:
196 * @cur: the namespace pointer
197 *
198 * Free up the structures associated to a namespace
199 */
200void
201xmlFreeNs(xmlNsPtr cur) {
202 if (cur == NULL) {
203#ifdef DEBUG_TREE
204 xmlGenericError(xmlGenericErrorContext,
205 "xmlFreeNs : ns == NULL\n");
206#endif
207 return;
208 }
209 if (cur->href != NULL) xmlFree((char *) cur->href);
210 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000211 xmlFree(cur);
212}
213
214/**
215 * xmlFreeNsList:
216 * @cur: the first namespace pointer
217 *
218 * Free up all the structures associated to the chained namespaces.
219 */
220void
221xmlFreeNsList(xmlNsPtr cur) {
222 xmlNsPtr next;
223 if (cur == NULL) {
224#ifdef DEBUG_TREE
225 xmlGenericError(xmlGenericErrorContext,
226 "xmlFreeNsList : ns == NULL\n");
227#endif
228 return;
229 }
230 while (cur != NULL) {
231 next = cur->next;
232 xmlFreeNs(cur);
233 cur = next;
234 }
235}
236
237/**
238 * xmlNewDtd:
239 * @doc: the document pointer
240 * @name: the DTD name
241 * @ExternalID: the external ID
242 * @SystemID: the system ID
243 *
244 * Creation of a new DTD for the external subset. To create an
245 * internal subset, use xmlCreateIntSubset().
246 *
247 * Returns a pointer to the new DTD structure
248 */
249xmlDtdPtr
250xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
251 const xmlChar *ExternalID, const xmlChar *SystemID) {
252 xmlDtdPtr cur;
253
254 if ((doc != NULL) && (doc->extSubset != NULL)) {
255#ifdef DEBUG_TREE
256 xmlGenericError(xmlGenericErrorContext,
257 "xmlNewDtd(%s): document %s already have a DTD %s\n",
258 /* !!! */ (char *) name, doc->name,
259 /* !!! */ (char *)doc->extSubset->name);
260#endif
261 return(NULL);
262 }
263
264 /*
265 * Allocate a new DTD and fill the fields.
266 */
267 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
268 if (cur == NULL) {
269 xmlGenericError(xmlGenericErrorContext,
270 "xmlNewDtd : malloc failed\n");
271 return(NULL);
272 }
273 memset(cur, 0 , sizeof(xmlDtd));
274 cur->type = XML_DTD_NODE;
275
276 if (name != NULL)
277 cur->name = xmlStrdup(name);
278 if (ExternalID != NULL)
279 cur->ExternalID = xmlStrdup(ExternalID);
280 if (SystemID != NULL)
281 cur->SystemID = xmlStrdup(SystemID);
282 if (doc != NULL)
283 doc->extSubset = cur;
284 cur->doc = doc;
285
286 return(cur);
287}
288
289/**
290 * xmlGetIntSubset:
291 * @doc: the document pointer
292 *
293 * Get the internal subset of a document
294 * Returns a pointer to the DTD structure or NULL if not found
295 */
296
297xmlDtdPtr
298xmlGetIntSubset(xmlDocPtr doc) {
299 xmlNodePtr cur;
300
301 if (doc == NULL)
302 return(NULL);
303 cur = doc->children;
304 while (cur != NULL) {
305 if (cur->type == XML_DTD_NODE)
306 return((xmlDtdPtr) cur);
307 cur = cur->next;
308 }
309 return((xmlDtdPtr) doc->intSubset);
310}
311
312/**
313 * xmlCreateIntSubset:
314 * @doc: the document pointer
315 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000316 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000317 * @SystemID: the system ID
318 *
319 * Create the internal subset of a document
320 * Returns a pointer to the new DTD structure
321 */
322xmlDtdPtr
323xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
324 const xmlChar *ExternalID, const xmlChar *SystemID) {
325 xmlDtdPtr cur;
326
327 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
328#ifdef DEBUG_TREE
329 xmlGenericError(xmlGenericErrorContext,
330
331 "xmlCreateIntSubset(): document %s already have an internal subset\n",
332 doc->name);
333#endif
334 return(NULL);
335 }
336
337 /*
338 * Allocate a new DTD and fill the fields.
339 */
340 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
341 if (cur == NULL) {
342 xmlGenericError(xmlGenericErrorContext,
343 "xmlNewDtd : malloc failed\n");
344 return(NULL);
345 }
346 memset(cur, 0, sizeof(xmlDtd));
347 cur->type = XML_DTD_NODE;
348
349 if (name != NULL)
350 cur->name = xmlStrdup(name);
351 if (ExternalID != NULL)
352 cur->ExternalID = xmlStrdup(ExternalID);
353 if (SystemID != NULL)
354 cur->SystemID = xmlStrdup(SystemID);
355 if (doc != NULL) {
356 doc->intSubset = cur;
357 cur->parent = doc;
358 cur->doc = doc;
359 if (doc->children == NULL) {
360 doc->children = (xmlNodePtr) cur;
361 doc->last = (xmlNodePtr) cur;
362 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000363 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000364 xmlNodePtr prev;
365
Owen Taylor3473f882001-02-23 17:55:21 +0000366 prev = doc->children;
367 prev->prev = (xmlNodePtr) cur;
368 cur->next = prev;
369 doc->children = (xmlNodePtr) cur;
370 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000371 xmlNodePtr next;
372
373 next = doc->children;
374 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
375 next = next->next;
376 if (next == NULL) {
377 cur->prev = doc->last;
378 cur->prev->next = (xmlNodePtr) cur;
379 cur->next = NULL;
380 doc->last = (xmlNodePtr) cur;
381 } else {
382 cur->next = next;
383 cur->prev = next->prev;
384 if (cur->prev == NULL)
385 doc->children = (xmlNodePtr) cur;
386 else
387 cur->prev->next = (xmlNodePtr) cur;
388 next->prev = (xmlNodePtr) cur;
389 }
Owen Taylor3473f882001-02-23 17:55:21 +0000390 }
391 }
392 }
393 return(cur);
394}
395
396/**
397 * xmlFreeDtd:
398 * @cur: the DTD structure to free up
399 *
400 * Free a DTD structure.
401 */
402void
403xmlFreeDtd(xmlDtdPtr cur) {
404 if (cur == NULL) {
405#ifdef DEBUG_TREE
406 xmlGenericError(xmlGenericErrorContext,
407 "xmlFreeDtd : DTD == NULL\n");
408#endif
409 return;
410 }
411 if (cur->children != NULL) {
412 xmlNodePtr next, c = cur->children;
413
414 /*
415 * Cleanup all the DTD comments they are not in the Dtd
416 * indexes.
417 */
418 while (c != NULL) {
419 next = c->next;
420 if (c->type == XML_COMMENT_NODE) {
421 xmlUnlinkNode(c);
422 xmlFreeNode(c);
423 }
424 c = next;
425 }
426 }
427 if (cur->name != NULL) xmlFree((char *) cur->name);
428 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
429 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
430 /* TODO !!! */
431 if (cur->notations != NULL)
432 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
433
434 if (cur->elements != NULL)
435 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
436 if (cur->attributes != NULL)
437 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
438 if (cur->entities != NULL)
439 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
440 if (cur->pentities != NULL)
441 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
442
Owen Taylor3473f882001-02-23 17:55:21 +0000443 xmlFree(cur);
444}
445
446/**
447 * xmlNewDoc:
448 * @version: xmlChar string giving the version of XML "1.0"
449 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000450 * Creates a new XML document
451 *
Owen Taylor3473f882001-02-23 17:55:21 +0000452 * Returns a new document
453 */
454xmlDocPtr
455xmlNewDoc(const xmlChar *version) {
456 xmlDocPtr cur;
457
458 if (version == NULL)
459 version = (const xmlChar *) "1.0";
460
461 /*
462 * Allocate a new document and fill the fields.
463 */
464 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
465 if (cur == NULL) {
466 xmlGenericError(xmlGenericErrorContext,
467 "xmlNewDoc : malloc failed\n");
468 return(NULL);
469 }
470 memset(cur, 0, sizeof(xmlDoc));
471 cur->type = XML_DOCUMENT_NODE;
472
473 cur->version = xmlStrdup(version);
474 cur->standalone = -1;
475 cur->compression = -1; /* not initialized */
476 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000477 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000478 return(cur);
479}
480
481/**
482 * xmlFreeDoc:
483 * @cur: pointer to the document
484 * @:
485 *
486 * Free up all the structures used by a document, tree included.
487 */
488void
489xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000490 xmlDtdPtr extSubset, intSubset;
491
Owen Taylor3473f882001-02-23 17:55:21 +0000492 if (cur == NULL) {
493#ifdef DEBUG_TREE
494 xmlGenericError(xmlGenericErrorContext,
495 "xmlFreeDoc : document == NULL\n");
496#endif
497 return;
498 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000499 /*
500 * Do this before freeing the children list to avoid ID lookups
501 */
502 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
503 cur->ids = NULL;
504 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
505 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000506 extSubset = cur->extSubset;
507 intSubset = cur->intSubset;
508 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000509 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000510 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000511 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000512 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000513 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000514 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000515 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000516 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000517 }
518
519 if (cur->children != NULL) xmlFreeNodeList(cur->children);
520
Owen Taylor3473f882001-02-23 17:55:21 +0000521 if (cur->version != NULL) xmlFree((char *) cur->version);
522 if (cur->name != NULL) xmlFree((char *) cur->name);
523 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000524 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000525 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000526 xmlFree(cur);
527}
528
529/**
530 * xmlStringLenGetNodeList:
531 * @doc: the document
532 * @value: the value of the text
533 * @len: the length of the string value
534 *
535 * Parse the value string and build the node list associated. Should
536 * produce a flat tree with only TEXTs and ENTITY_REFs.
537 * Returns a pointer to the first child
538 */
539xmlNodePtr
540xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
541 xmlNodePtr ret = NULL, last = NULL;
542 xmlNodePtr node;
543 xmlChar *val;
544 const xmlChar *cur = value;
545 const xmlChar *q;
546 xmlEntityPtr ent;
547
548 if (value == NULL) return(NULL);
549
550 q = cur;
551 while ((*cur != 0) && (cur - value < len)) {
552 if (*cur == '&') {
553 /*
554 * Save the current text.
555 */
556 if (cur != q) {
557 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
558 xmlNodeAddContentLen(last, q, cur - q);
559 } else {
560 node = xmlNewDocTextLen(doc, q, cur - q);
561 if (node == NULL) return(ret);
562 if (last == NULL)
563 last = ret = node;
564 else {
565 last->next = node;
566 node->prev = last;
567 last = node;
568 }
569 }
570 }
571 /*
572 * Read the entity string
573 */
574 cur++;
575 q = cur;
576 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
577 if ((*cur == 0) || (cur - value >= len)) {
578#ifdef DEBUG_TREE
579 xmlGenericError(xmlGenericErrorContext,
580 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
581#endif
582 return(ret);
583 }
584 if (cur != q) {
585 /*
586 * Predefined entities don't generate nodes
587 */
588 val = xmlStrndup(q, cur - q);
589 ent = xmlGetDocEntity(doc, val);
590 if ((ent != NULL) &&
591 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
592 if (last == NULL) {
593 node = xmlNewDocText(doc, ent->content);
594 last = ret = node;
595 } else
596 xmlNodeAddContent(last, ent->content);
597
598 } else {
599 /*
600 * Create a new REFERENCE_REF node
601 */
602 node = xmlNewReference(doc, val);
603 if (node == NULL) {
604 if (val != NULL) xmlFree(val);
605 return(ret);
606 }
607 if (last == NULL)
608 last = ret = node;
609 else {
610 last->next = node;
611 node->prev = last;
612 last = node;
613 }
614 }
615 xmlFree(val);
616 }
617 cur++;
618 q = cur;
619 } else
620 cur++;
621 }
622 if (cur != q) {
623 /*
624 * Handle the last piece of text.
625 */
626 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
627 xmlNodeAddContentLen(last, q, cur - q);
628 } else {
629 node = xmlNewDocTextLen(doc, q, cur - q);
630 if (node == NULL) return(ret);
631 if (last == NULL)
632 last = ret = node;
633 else {
634 last->next = node;
635 node->prev = last;
636 last = node;
637 }
638 }
639 }
640 return(ret);
641}
642
643/**
644 * xmlStringGetNodeList:
645 * @doc: the document
646 * @value: the value of the attribute
647 *
648 * Parse the value string and build the node list associated. Should
649 * produce a flat tree with only TEXTs and ENTITY_REFs.
650 * Returns a pointer to the first child
651 */
652xmlNodePtr
653xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
654 xmlNodePtr ret = NULL, last = NULL;
655 xmlNodePtr node;
656 xmlChar *val;
657 const xmlChar *cur = value;
658 const xmlChar *q;
659 xmlEntityPtr ent;
660
661 if (value == NULL) return(NULL);
662
663 q = cur;
664 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000665 if (cur[0] == '&') {
666 int charval = 0;
667 xmlChar tmp;
668
Owen Taylor3473f882001-02-23 17:55:21 +0000669 /*
670 * Save the current text.
671 */
672 if (cur != q) {
673 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
674 xmlNodeAddContentLen(last, q, cur - q);
675 } else {
676 node = xmlNewDocTextLen(doc, q, cur - q);
677 if (node == NULL) return(ret);
678 if (last == NULL)
679 last = ret = node;
680 else {
681 last->next = node;
682 node->prev = last;
683 last = node;
684 }
685 }
686 }
Owen Taylor3473f882001-02-23 17:55:21 +0000687 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000688 if ((cur[1] == '#') && (cur[2] == 'x')) {
689 cur += 3;
690 tmp = *cur;
691 while (tmp != ';') { /* Non input consuming loop */
692 if ((tmp >= '0') && (tmp <= '9'))
693 charval = charval * 16 + (tmp - '0');
694 else if ((tmp >= 'a') && (tmp <= 'f'))
695 charval = charval * 16 + (tmp - 'a') + 10;
696 else if ((tmp >= 'A') && (tmp <= 'F'))
697 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000698 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000699 xmlGenericError(xmlGenericErrorContext,
700 "xmlStringGetNodeList: incharvalid hexadecimal charvalue\n");
701 charval = 0;
702 break;
703 }
704 cur++;
705 tmp = *cur;
706 }
707 if (tmp == ';')
708 cur++;
709 q = cur;
710 } else if (cur[1] == '#') {
711 cur += 2;
712 tmp = *cur;
713 while (tmp != ';') { /* Non input consuming loops */
714 if ((tmp >= '0') && (tmp <= '9'))
715 charval = charval * 10 + (tmp - '0');
716 else {
717 xmlGenericError(xmlGenericErrorContext,
718 "xmlStringGetNodeList: incharvalid decimal charvalue\n");
719 charval = 0;
720 break;
721 }
722 cur++;
723 tmp = *cur;
724 }
725 if (tmp == ';')
726 cur++;
727 q = cur;
728 } else {
729 /*
730 * Read the entity string
731 */
732 cur++;
733 q = cur;
734 while ((*cur != 0) && (*cur != ';')) cur++;
735 if (*cur == 0) {
736#ifdef DEBUG_TREE
737 xmlGenericError(xmlGenericErrorContext,
738 "xmlStringGetNodeList: unterminated entity %30s\n", q);
739#endif
740 return(ret);
741 }
742 if (cur != q) {
743 /*
744 * Predefined entities don't generate nodes
745 */
746 val = xmlStrndup(q, cur - q);
747 ent = xmlGetDocEntity(doc, val);
748 if ((ent != NULL) &&
749 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
750 if (last == NULL) {
751 node = xmlNewDocText(doc, ent->content);
752 last = ret = node;
753 } else
754 xmlNodeAddContent(last, ent->content);
755
756 } else {
757 /*
758 * Create a new REFERENCE_REF node
759 */
760 node = xmlNewReference(doc, val);
761 if (node == NULL) {
762 if (val != NULL) xmlFree(val);
763 return(ret);
764 }
765 if (last == NULL) {
766 last = ret = node;
767 } else {
768 last = xmlAddNextSibling(last, node);
769 }
770 }
771 xmlFree(val);
772 }
773 cur++;
774 q = cur;
775 }
776 if (charval != 0) {
777 xmlChar buf[10];
778 int len;
779
780 len = xmlCopyCharMultiByte(buf, charval);
781 buf[len] = 0;
782 node = xmlNewDocText(doc, buf);
783 if (node != NULL) {
784 if (last == NULL) {
785 last = ret = node;
786 } else {
787 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000788 }
789 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000790
791 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000792 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000793 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000794 cur++;
795 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000796 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000797 /*
798 * Handle the last piece of text.
799 */
800 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
801 xmlNodeAddContentLen(last, q, cur - q);
802 } else {
803 node = xmlNewDocTextLen(doc, q, cur - q);
804 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000805 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000806 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000807 } else {
808 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000809 }
810 }
811 }
812 return(ret);
813}
814
815/**
816 * xmlNodeListGetString:
817 * @doc: the document
818 * @list: a Node list
819 * @inLine: should we replace entity contents or show their external form
820 *
821 * Returns the string equivalent to the text contained in the Node list
822 * made of TEXTs and ENTITY_REFs
823 * Returns a pointer to the string copy, the calller must free it.
824 */
825xmlChar *
826xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
827 xmlNodePtr node = list;
828 xmlChar *ret = NULL;
829 xmlEntityPtr ent;
830
831 if (list == NULL) return(NULL);
832
833 while (node != NULL) {
834 if ((node->type == XML_TEXT_NODE) ||
835 (node->type == XML_CDATA_SECTION_NODE)) {
836 if (inLine) {
837#ifndef XML_USE_BUFFER_CONTENT
838 ret = xmlStrcat(ret, node->content);
839#else
840 ret = xmlStrcat(ret, xmlBufferContent(node->content));
841#endif
842 } else {
843 xmlChar *buffer;
844
845#ifndef XML_USE_BUFFER_CONTENT
846 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
847#else
848 buffer = xmlEncodeEntitiesReentrant(doc,
849 xmlBufferContent(node->content));
850#endif
851 if (buffer != NULL) {
852 ret = xmlStrcat(ret, buffer);
853 xmlFree(buffer);
854 }
855 }
856 } else if (node->type == XML_ENTITY_REF_NODE) {
857 if (inLine) {
858 ent = xmlGetDocEntity(doc, node->name);
859 if (ent != NULL)
860 ret = xmlStrcat(ret, ent->content);
861 else {
862#ifndef XML_USE_BUFFER_CONTENT
863 ret = xmlStrcat(ret, node->content);
864#else
865 ret = xmlStrcat(ret, xmlBufferContent(node->content));
866#endif
867 }
868 } else {
869 xmlChar buf[2];
870 buf[0] = '&'; buf[1] = 0;
871 ret = xmlStrncat(ret, buf, 1);
872 ret = xmlStrcat(ret, node->name);
873 buf[0] = ';'; buf[1] = 0;
874 ret = xmlStrncat(ret, buf, 1);
875 }
876 }
877#if 0
878 else {
879 xmlGenericError(xmlGenericErrorContext,
880 "xmlGetNodeListString : invalide node type %d\n",
881 node->type);
882 }
883#endif
884 node = node->next;
885 }
886 return(ret);
887}
888
889/**
890 * xmlNodeListGetRawString:
891 * @doc: the document
892 * @list: a Node list
893 * @inLine: should we replace entity contents or show their external form
894 *
895 * Returns the string equivalent to the text contained in the Node list
896 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
897 * this function doesn't do any character encoding handling.
898 *
899 * Returns a pointer to the string copy, the calller must free it.
900 */
901xmlChar *
902xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
903 xmlNodePtr node = list;
904 xmlChar *ret = NULL;
905 xmlEntityPtr ent;
906
907 if (list == NULL) return(NULL);
908
909 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000910 if ((node->type == XML_TEXT_NODE) ||
911 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000912 if (inLine) {
913#ifndef XML_USE_BUFFER_CONTENT
914 ret = xmlStrcat(ret, node->content);
915#else
916 ret = xmlStrcat(ret, xmlBufferContent(node->content));
917#endif
918 } else {
919 xmlChar *buffer;
920
921#ifndef XML_USE_BUFFER_CONTENT
922 buffer = xmlEncodeSpecialChars(doc, node->content);
923#else
924 buffer = xmlEncodeSpecialChars(doc,
925 xmlBufferContent(node->content));
926#endif
927 if (buffer != NULL) {
928 ret = xmlStrcat(ret, buffer);
929 xmlFree(buffer);
930 }
931 }
932 } else if (node->type == XML_ENTITY_REF_NODE) {
933 if (inLine) {
934 ent = xmlGetDocEntity(doc, node->name);
935 if (ent != NULL)
936 ret = xmlStrcat(ret, ent->content);
937 else {
938#ifndef XML_USE_BUFFER_CONTENT
939 ret = xmlStrcat(ret, node->content);
940#else
941 ret = xmlStrcat(ret, xmlBufferContent(node->content));
942#endif
943 }
944 } else {
945 xmlChar buf[2];
946 buf[0] = '&'; buf[1] = 0;
947 ret = xmlStrncat(ret, buf, 1);
948 ret = xmlStrcat(ret, node->name);
949 buf[0] = ';'; buf[1] = 0;
950 ret = xmlStrncat(ret, buf, 1);
951 }
952 }
953#if 0
954 else {
955 xmlGenericError(xmlGenericErrorContext,
956 "xmlGetNodeListString : invalide node type %d\n",
957 node->type);
958 }
959#endif
960 node = node->next;
961 }
962 return(ret);
963}
964
965/**
966 * xmlNewProp:
967 * @node: the holding node
968 * @name: the name of the attribute
969 * @value: the value of the attribute
970 *
971 * Create a new property carried by a node.
972 * Returns a pointer to the attribute
973 */
974xmlAttrPtr
975xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
976 xmlAttrPtr cur;
977 xmlDocPtr doc = NULL;
978
979 if (name == NULL) {
980#ifdef DEBUG_TREE
981 xmlGenericError(xmlGenericErrorContext,
982 "xmlNewProp : name == NULL\n");
983#endif
984 return(NULL);
985 }
986
987 /*
988 * Allocate a new property and fill the fields.
989 */
990 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
991 if (cur == NULL) {
992 xmlGenericError(xmlGenericErrorContext,
993 "xmlNewProp : malloc failed\n");
994 return(NULL);
995 }
996 memset(cur, 0, sizeof(xmlAttr));
997 cur->type = XML_ATTRIBUTE_NODE;
998
999 cur->parent = node;
1000 if (node != NULL) {
1001 doc = node->doc;
1002 cur->doc = doc;
1003 }
1004 cur->name = xmlStrdup(name);
1005 if (value != NULL) {
1006 xmlChar *buffer;
1007 xmlNodePtr tmp;
1008
1009 buffer = xmlEncodeEntitiesReentrant(doc, value);
1010 cur->children = xmlStringGetNodeList(doc, buffer);
1011 cur->last = NULL;
1012 tmp = cur->children;
1013 while (tmp != NULL) {
1014 tmp->parent = (xmlNodePtr) cur;
1015 tmp->doc = doc;
1016 if (tmp->next == NULL)
1017 cur->last = tmp;
1018 tmp = tmp->next;
1019 }
1020 xmlFree(buffer);
1021 }
1022
1023 /*
1024 * Add it at the end to preserve parsing order ...
1025 */
1026 if (node != NULL) {
1027 if (node->properties == NULL) {
1028 node->properties = cur;
1029 } else {
1030 xmlAttrPtr prev = node->properties;
1031
1032 while (prev->next != NULL) prev = prev->next;
1033 prev->next = cur;
1034 cur->prev = prev;
1035 }
1036 }
1037 return(cur);
1038}
1039
1040/**
1041 * xmlNewNsProp:
1042 * @node: the holding node
1043 * @ns: the namespace
1044 * @name: the name of the attribute
1045 * @value: the value of the attribute
1046 *
1047 * Create a new property tagged with a namespace and carried by a node.
1048 * Returns a pointer to the attribute
1049 */
1050xmlAttrPtr
1051xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1052 const xmlChar *value) {
1053 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001054 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001055
1056 if (name == NULL) {
1057#ifdef DEBUG_TREE
1058 xmlGenericError(xmlGenericErrorContext,
1059 "xmlNewProp : name == NULL\n");
1060#endif
1061 return(NULL);
1062 }
1063
1064 /*
1065 * Allocate a new property and fill the fields.
1066 */
1067 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1068 if (cur == NULL) {
1069 xmlGenericError(xmlGenericErrorContext,
1070 "xmlNewProp : malloc failed\n");
1071 return(NULL);
1072 }
1073 memset(cur, 0, sizeof(xmlAttr));
1074 cur->type = XML_ATTRIBUTE_NODE;
1075
1076 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001077 if (node != NULL) {
1078 doc = node->doc;
1079 cur->doc = doc;
1080 }
Owen Taylor3473f882001-02-23 17:55:21 +00001081 cur->ns = ns;
1082 cur->name = xmlStrdup(name);
1083 if (value != NULL) {
1084 xmlChar *buffer;
1085 xmlNodePtr tmp;
1086
Daniel Veillarda682b212001-06-07 19:59:42 +00001087 buffer = xmlEncodeEntitiesReentrant(doc, value);
1088 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001089 cur->last = NULL;
1090 tmp = cur->children;
1091 while (tmp != NULL) {
1092 tmp->parent = (xmlNodePtr) cur;
1093 if (tmp->next == NULL)
1094 cur->last = tmp;
1095 tmp = tmp->next;
1096 }
1097 xmlFree(buffer);
1098 }
1099
1100 /*
1101 * Add it at the end to preserve parsing order ...
1102 */
1103 if (node != NULL) {
1104 if (node->properties == NULL) {
1105 node->properties = cur;
1106 } else {
1107 xmlAttrPtr prev = node->properties;
1108
1109 while (prev->next != NULL) prev = prev->next;
1110 prev->next = cur;
1111 cur->prev = prev;
1112 }
1113 }
1114 return(cur);
1115}
1116
1117/**
1118 * xmlNewDocProp:
1119 * @doc: the document
1120 * @name: the name of the attribute
1121 * @value: the value of the attribute
1122 *
1123 * Create a new property carried by a document.
1124 * Returns a pointer to the attribute
1125 */
1126xmlAttrPtr
1127xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1128 xmlAttrPtr cur;
1129
1130 if (name == NULL) {
1131#ifdef DEBUG_TREE
1132 xmlGenericError(xmlGenericErrorContext,
1133 "xmlNewProp : name == NULL\n");
1134#endif
1135 return(NULL);
1136 }
1137
1138 /*
1139 * Allocate a new property and fill the fields.
1140 */
1141 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1142 if (cur == NULL) {
1143 xmlGenericError(xmlGenericErrorContext,
1144 "xmlNewProp : malloc failed\n");
1145 return(NULL);
1146 }
1147 memset(cur, 0, sizeof(xmlAttr));
1148 cur->type = XML_ATTRIBUTE_NODE;
1149
1150 cur->name = xmlStrdup(name);
1151 cur->doc = doc;
1152 if (value != NULL) {
1153 xmlNodePtr tmp;
1154
1155 cur->children = xmlStringGetNodeList(doc, value);
1156 cur->last = NULL;
1157
1158 tmp = cur->children;
1159 while (tmp != NULL) {
1160 tmp->parent = (xmlNodePtr) cur;
1161 if (tmp->next == NULL)
1162 cur->last = tmp;
1163 tmp = tmp->next;
1164 }
1165 }
1166 return(cur);
1167}
1168
1169/**
1170 * xmlFreePropList:
1171 * @cur: the first property in the list
1172 *
1173 * Free a property and all its siblings, all the children are freed too.
1174 */
1175void
1176xmlFreePropList(xmlAttrPtr cur) {
1177 xmlAttrPtr next;
1178 if (cur == NULL) {
1179#ifdef DEBUG_TREE
1180 xmlGenericError(xmlGenericErrorContext,
1181 "xmlFreePropList : property == NULL\n");
1182#endif
1183 return;
1184 }
1185 while (cur != NULL) {
1186 next = cur->next;
1187 xmlFreeProp(cur);
1188 cur = next;
1189 }
1190}
1191
1192/**
1193 * xmlFreeProp:
1194 * @cur: an attribute
1195 *
1196 * Free one attribute, all the content is freed too
1197 */
1198void
1199xmlFreeProp(xmlAttrPtr cur) {
1200 if (cur == NULL) {
1201#ifdef DEBUG_TREE
1202 xmlGenericError(xmlGenericErrorContext,
1203 "xmlFreeProp : property == NULL\n");
1204#endif
1205 return;
1206 }
1207 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001208 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1209 ((cur->parent->doc->intSubset != NULL) ||
1210 (cur->parent->doc->extSubset != NULL))) {
1211 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1212 xmlRemoveID(cur->parent->doc, cur);
1213 }
Owen Taylor3473f882001-02-23 17:55:21 +00001214 if (cur->name != NULL) xmlFree((char *) cur->name);
1215 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001216 xmlFree(cur);
1217}
1218
1219/**
1220 * xmlRemoveProp:
1221 * @cur: an attribute
1222 *
1223 * Unlink and free one attribute, all the content is freed too
1224 * Note this doesn't work for namespace definition attributes
1225 *
1226 * Returns 0 if success and -1 in case of error.
1227 */
1228int
1229xmlRemoveProp(xmlAttrPtr cur) {
1230 xmlAttrPtr tmp;
1231 if (cur == NULL) {
1232#ifdef DEBUG_TREE
1233 xmlGenericError(xmlGenericErrorContext,
1234 "xmlRemoveProp : cur == NULL\n");
1235#endif
1236 return(-1);
1237 }
1238 if (cur->parent == NULL) {
1239#ifdef DEBUG_TREE
1240 xmlGenericError(xmlGenericErrorContext,
1241 "xmlRemoveProp : cur->parent == NULL\n");
1242#endif
1243 return(-1);
1244 }
1245 tmp = cur->parent->properties;
1246 if (tmp == cur) {
1247 cur->parent->properties = cur->next;
1248 xmlFreeProp(cur);
1249 return(0);
1250 }
1251 while (tmp != NULL) {
1252 if (tmp->next == cur) {
1253 tmp->next = cur->next;
1254 if (tmp->next != NULL)
1255 tmp->next->prev = tmp;
1256 xmlFreeProp(cur);
1257 return(0);
1258 }
1259 tmp = tmp->next;
1260 }
1261#ifdef DEBUG_TREE
1262 xmlGenericError(xmlGenericErrorContext,
1263 "xmlRemoveProp : attribute not owned by its node\n");
1264#endif
1265 return(-1);
1266}
1267
1268/**
1269 * xmlNewPI:
1270 * @name: the processing instruction name
1271 * @content: the PI content
1272 *
1273 * Creation of a processing instruction element.
1274 * Returns a pointer to the new node object.
1275 */
1276xmlNodePtr
1277xmlNewPI(const xmlChar *name, const xmlChar *content) {
1278 xmlNodePtr cur;
1279
1280 if (name == NULL) {
1281#ifdef DEBUG_TREE
1282 xmlGenericError(xmlGenericErrorContext,
1283 "xmlNewPI : name == NULL\n");
1284#endif
1285 return(NULL);
1286 }
1287
1288 /*
1289 * Allocate a new node and fill the fields.
1290 */
1291 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1292 if (cur == NULL) {
1293 xmlGenericError(xmlGenericErrorContext,
1294 "xmlNewPI : malloc failed\n");
1295 return(NULL);
1296 }
1297 memset(cur, 0, sizeof(xmlNode));
1298 cur->type = XML_PI_NODE;
1299
1300 cur->name = xmlStrdup(name);
1301 if (content != NULL) {
1302#ifndef XML_USE_BUFFER_CONTENT
1303 cur->content = xmlStrdup(content);
1304#else
1305 cur->content = xmlBufferCreateSize(0);
1306 xmlBufferSetAllocationScheme(cur->content,
1307 xmlGetBufferAllocationScheme());
1308 xmlBufferAdd(cur->content, content, -1);
1309#endif
1310 }
1311 return(cur);
1312}
1313
1314/**
1315 * xmlNewNode:
1316 * @ns: namespace if any
1317 * @name: the node name
1318 *
1319 * Creation of a new node element. @ns is optionnal (NULL).
1320 *
1321 * Returns a pointer to the new node object.
1322 */
1323xmlNodePtr
1324xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1325 xmlNodePtr cur;
1326
1327 if (name == NULL) {
1328#ifdef DEBUG_TREE
1329 xmlGenericError(xmlGenericErrorContext,
1330 "xmlNewNode : name == NULL\n");
1331#endif
1332 return(NULL);
1333 }
1334
1335 /*
1336 * Allocate a new node and fill the fields.
1337 */
1338 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1339 if (cur == NULL) {
1340 xmlGenericError(xmlGenericErrorContext,
1341 "xmlNewNode : malloc failed\n");
1342 return(NULL);
1343 }
1344 memset(cur, 0, sizeof(xmlNode));
1345 cur->type = XML_ELEMENT_NODE;
1346
1347 cur->name = xmlStrdup(name);
1348 cur->ns = ns;
1349 return(cur);
1350}
1351
1352/**
1353 * xmlNewDocNode:
1354 * @doc: the document
1355 * @ns: namespace if any
1356 * @name: the node name
1357 * @content: the XML text content if any
1358 *
1359 * Creation of a new node element within a document. @ns and @content
1360 * are optionnal (NULL).
1361 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1362 * references, but XML special chars need to be escaped first by using
1363 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1364 * need entities support.
1365 *
1366 * Returns a pointer to the new node object.
1367 */
1368xmlNodePtr
1369xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1370 const xmlChar *name, const xmlChar *content) {
1371 xmlNodePtr cur;
1372
1373 cur = xmlNewNode(ns, name);
1374 if (cur != NULL) {
1375 cur->doc = doc;
1376 if (content != NULL) {
1377 cur->children = xmlStringGetNodeList(doc, content);
1378 UPDATE_LAST_CHILD_AND_PARENT(cur)
1379 }
1380 }
1381 return(cur);
1382}
1383
1384
1385/**
1386 * xmlNewDocRawNode:
1387 * @doc: the document
1388 * @ns: namespace if any
1389 * @name: the node name
1390 * @content: the text content if any
1391 *
1392 * Creation of a new node element within a document. @ns and @content
1393 * are optionnal (NULL).
1394 *
1395 * Returns a pointer to the new node object.
1396 */
1397xmlNodePtr
1398xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1399 const xmlChar *name, const xmlChar *content) {
1400 xmlNodePtr cur;
1401
1402 cur = xmlNewNode(ns, name);
1403 if (cur != NULL) {
1404 cur->doc = doc;
1405 if (content != NULL) {
1406 cur->children = xmlNewDocText(doc, content);
1407 UPDATE_LAST_CHILD_AND_PARENT(cur)
1408 }
1409 }
1410 return(cur);
1411}
1412
1413/**
1414 * xmlNewDocFragment:
1415 * @doc: the document owning the fragment
1416 *
1417 * Creation of a new Fragment node.
1418 * Returns a pointer to the new node object.
1419 */
1420xmlNodePtr
1421xmlNewDocFragment(xmlDocPtr doc) {
1422 xmlNodePtr cur;
1423
1424 /*
1425 * Allocate a new DocumentFragment node and fill the fields.
1426 */
1427 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1428 if (cur == NULL) {
1429 xmlGenericError(xmlGenericErrorContext,
1430 "xmlNewDocFragment : malloc failed\n");
1431 return(NULL);
1432 }
1433 memset(cur, 0, sizeof(xmlNode));
1434 cur->type = XML_DOCUMENT_FRAG_NODE;
1435
1436 cur->doc = doc;
1437 return(cur);
1438}
1439
1440/**
1441 * xmlNewText:
1442 * @content: the text content
1443 *
1444 * Creation of a new text node.
1445 * Returns a pointer to the new node object.
1446 */
1447xmlNodePtr
1448xmlNewText(const xmlChar *content) {
1449 xmlNodePtr cur;
1450
1451 /*
1452 * Allocate a new node and fill the fields.
1453 */
1454 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1455 if (cur == NULL) {
1456 xmlGenericError(xmlGenericErrorContext,
1457 "xmlNewText : malloc failed\n");
1458 return(NULL);
1459 }
1460 memset(cur, 0, sizeof(xmlNode));
1461 cur->type = XML_TEXT_NODE;
1462
1463 cur->name = xmlStringText;
1464 if (content != NULL) {
1465#ifndef XML_USE_BUFFER_CONTENT
1466 cur->content = xmlStrdup(content);
1467#else
1468 cur->content = xmlBufferCreateSize(0);
1469 xmlBufferSetAllocationScheme(cur->content,
1470 xmlGetBufferAllocationScheme());
1471 xmlBufferAdd(cur->content, content, -1);
1472#endif
1473 }
1474 return(cur);
1475}
1476
1477/**
1478 * xmlNewTextChild:
1479 * @parent: the parent node
1480 * @ns: a namespace if any
1481 * @name: the name of the child
1482 * @content: the text content of the child if any.
1483 *
1484 * Creation of a new child element, added at the end of @parent children list.
1485 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1486 * a child TEXT node will be created containing the string content.
1487 *
1488 * Returns a pointer to the new node object.
1489 */
1490xmlNodePtr
1491xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1492 const xmlChar *name, const xmlChar *content) {
1493 xmlNodePtr cur, prev;
1494
1495 if (parent == NULL) {
1496#ifdef DEBUG_TREE
1497 xmlGenericError(xmlGenericErrorContext,
1498 "xmlNewTextChild : parent == NULL\n");
1499#endif
1500 return(NULL);
1501 }
1502
1503 if (name == NULL) {
1504#ifdef DEBUG_TREE
1505 xmlGenericError(xmlGenericErrorContext,
1506 "xmlNewTextChild : name == NULL\n");
1507#endif
1508 return(NULL);
1509 }
1510
1511 /*
1512 * Allocate a new node
1513 */
1514 if (ns == NULL)
1515 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1516 else
1517 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1518 if (cur == NULL) return(NULL);
1519
1520 /*
1521 * add the new element at the end of the children list.
1522 */
1523 cur->type = XML_ELEMENT_NODE;
1524 cur->parent = parent;
1525 cur->doc = parent->doc;
1526 if (parent->children == NULL) {
1527 parent->children = cur;
1528 parent->last = cur;
1529 } else {
1530 prev = parent->last;
1531 prev->next = cur;
1532 cur->prev = prev;
1533 parent->last = cur;
1534 }
1535
1536 return(cur);
1537}
1538
1539/**
1540 * xmlNewCharRef:
1541 * @doc: the document
1542 * @name: the char ref string, starting with # or "&# ... ;"
1543 *
1544 * Creation of a new character reference node.
1545 * Returns a pointer to the new node object.
1546 */
1547xmlNodePtr
1548xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1549 xmlNodePtr cur;
1550
1551 /*
1552 * Allocate a new node and fill the fields.
1553 */
1554 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1555 if (cur == NULL) {
1556 xmlGenericError(xmlGenericErrorContext,
1557 "xmlNewText : malloc failed\n");
1558 return(NULL);
1559 }
1560 memset(cur, 0, sizeof(xmlNode));
1561 cur->type = XML_ENTITY_REF_NODE;
1562
1563 cur->doc = doc;
1564 if (name[0] == '&') {
1565 int len;
1566 name++;
1567 len = xmlStrlen(name);
1568 if (name[len - 1] == ';')
1569 cur->name = xmlStrndup(name, len - 1);
1570 else
1571 cur->name = xmlStrndup(name, len);
1572 } else
1573 cur->name = xmlStrdup(name);
1574 return(cur);
1575}
1576
1577/**
1578 * xmlNewReference:
1579 * @doc: the document
1580 * @name: the reference name, or the reference string with & and ;
1581 *
1582 * Creation of a new reference node.
1583 * Returns a pointer to the new node object.
1584 */
1585xmlNodePtr
1586xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1587 xmlNodePtr cur;
1588 xmlEntityPtr ent;
1589
1590 /*
1591 * Allocate a new node and fill the fields.
1592 */
1593 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1594 if (cur == NULL) {
1595 xmlGenericError(xmlGenericErrorContext,
1596 "xmlNewText : malloc failed\n");
1597 return(NULL);
1598 }
1599 memset(cur, 0, sizeof(xmlNode));
1600 cur->type = XML_ENTITY_REF_NODE;
1601
1602 cur->doc = doc;
1603 if (name[0] == '&') {
1604 int len;
1605 name++;
1606 len = xmlStrlen(name);
1607 if (name[len - 1] == ';')
1608 cur->name = xmlStrndup(name, len - 1);
1609 else
1610 cur->name = xmlStrndup(name, len);
1611 } else
1612 cur->name = xmlStrdup(name);
1613
1614 ent = xmlGetDocEntity(doc, cur->name);
1615 if (ent != NULL) {
1616#ifndef XML_USE_BUFFER_CONTENT
1617 cur->content = ent->content;
1618#else
1619 /*
1620 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1621 * a copy of this pointer. Let's hope we don't manipulate it
1622 * later
1623 */
1624 cur->content = xmlBufferCreateSize(0);
1625 xmlBufferSetAllocationScheme(cur->content,
1626 xmlGetBufferAllocationScheme());
1627 if (ent->content != NULL)
1628 xmlBufferAdd(cur->content, ent->content, -1);
1629#endif
1630 /*
1631 * The parent pointer in entity is a Dtd pointer and thus is NOT
1632 * updated. Not sure if this is 100% correct.
1633 * -George
1634 */
1635 cur->children = (xmlNodePtr) ent;
1636 cur->last = (xmlNodePtr) ent;
1637 }
1638 return(cur);
1639}
1640
1641/**
1642 * xmlNewDocText:
1643 * @doc: the document
1644 * @content: the text content
1645 *
1646 * Creation of a new text node within a document.
1647 * Returns a pointer to the new node object.
1648 */
1649xmlNodePtr
1650xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1651 xmlNodePtr cur;
1652
1653 cur = xmlNewText(content);
1654 if (cur != NULL) cur->doc = doc;
1655 return(cur);
1656}
1657
1658/**
1659 * xmlNewTextLen:
1660 * @content: the text content
1661 * @len: the text len.
1662 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001663 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001664 * Returns a pointer to the new node object.
1665 */
1666xmlNodePtr
1667xmlNewTextLen(const xmlChar *content, int len) {
1668 xmlNodePtr cur;
1669
1670 /*
1671 * Allocate a new node and fill the fields.
1672 */
1673 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1674 if (cur == NULL) {
1675 xmlGenericError(xmlGenericErrorContext,
1676 "xmlNewText : malloc failed\n");
1677 return(NULL);
1678 }
1679 memset(cur, 0, sizeof(xmlNode));
1680 cur->type = XML_TEXT_NODE;
1681
1682 cur->name = xmlStringText;
1683 if (content != NULL) {
1684#ifndef XML_USE_BUFFER_CONTENT
1685 cur->content = xmlStrndup(content, len);
1686#else
1687 cur->content = xmlBufferCreateSize(len);
1688 xmlBufferSetAllocationScheme(cur->content,
1689 xmlGetBufferAllocationScheme());
1690 xmlBufferAdd(cur->content, content, len);
1691#endif
1692 }
1693 return(cur);
1694}
1695
1696/**
1697 * xmlNewDocTextLen:
1698 * @doc: the document
1699 * @content: the text content
1700 * @len: the text len.
1701 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001702 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001703 * text node pertain to a given document.
1704 * Returns a pointer to the new node object.
1705 */
1706xmlNodePtr
1707xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1708 xmlNodePtr cur;
1709
1710 cur = xmlNewTextLen(content, len);
1711 if (cur != NULL) cur->doc = doc;
1712 return(cur);
1713}
1714
1715/**
1716 * xmlNewComment:
1717 * @content: the comment content
1718 *
1719 * Creation of a new node containing a comment.
1720 * Returns a pointer to the new node object.
1721 */
1722xmlNodePtr
1723xmlNewComment(const xmlChar *content) {
1724 xmlNodePtr cur;
1725
1726 /*
1727 * Allocate a new node and fill the fields.
1728 */
1729 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1730 if (cur == NULL) {
1731 xmlGenericError(xmlGenericErrorContext,
1732 "xmlNewComment : malloc failed\n");
1733 return(NULL);
1734 }
1735 memset(cur, 0, sizeof(xmlNode));
1736 cur->type = XML_COMMENT_NODE;
1737
1738 cur->name = xmlStringComment;
1739 if (content != NULL) {
1740#ifndef XML_USE_BUFFER_CONTENT
1741 cur->content = xmlStrdup(content);
1742#else
1743 cur->content = xmlBufferCreateSize(0);
1744 xmlBufferSetAllocationScheme(cur->content,
1745 xmlGetBufferAllocationScheme());
1746 xmlBufferAdd(cur->content, content, -1);
1747#endif
1748 }
1749 return(cur);
1750}
1751
1752/**
1753 * xmlNewCDataBlock:
1754 * @doc: the document
1755 * @content: the CData block content content
1756 * @len: the length of the block
1757 *
1758 * Creation of a new node containing a CData block.
1759 * Returns a pointer to the new node object.
1760 */
1761xmlNodePtr
1762xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1763 xmlNodePtr cur;
1764
1765 /*
1766 * Allocate a new node and fill the fields.
1767 */
1768 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1769 if (cur == NULL) {
1770 xmlGenericError(xmlGenericErrorContext,
1771 "xmlNewCDataBlock : malloc failed\n");
1772 return(NULL);
1773 }
1774 memset(cur, 0, sizeof(xmlNode));
1775 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001776 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001777
1778 if (content != NULL) {
1779#ifndef XML_USE_BUFFER_CONTENT
1780 cur->content = xmlStrndup(content, len);
1781#else
1782 cur->content = xmlBufferCreateSize(len);
1783 xmlBufferSetAllocationScheme(cur->content,
1784 xmlGetBufferAllocationScheme());
1785 xmlBufferAdd(cur->content, content, len);
1786#endif
1787 }
1788 return(cur);
1789}
1790
1791/**
1792 * xmlNewDocComment:
1793 * @doc: the document
1794 * @content: the comment content
1795 *
1796 * Creation of a new node containing a commentwithin a document.
1797 * Returns a pointer to the new node object.
1798 */
1799xmlNodePtr
1800xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1801 xmlNodePtr cur;
1802
1803 cur = xmlNewComment(content);
1804 if (cur != NULL) cur->doc = doc;
1805 return(cur);
1806}
1807
1808/**
1809 * xmlSetTreeDoc:
1810 * @tree: the top element
1811 * @doc: the document
1812 *
1813 * update all nodes under the tree to point to the right document
1814 */
1815void
1816xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001817 xmlAttrPtr prop;
1818
Owen Taylor3473f882001-02-23 17:55:21 +00001819 if (tree == NULL)
1820 return;
1821 if (tree->type == XML_ENTITY_DECL)
1822 return;
1823 if (tree->doc != doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001824 prop = tree->properties;
1825 while (prop != NULL) {
1826 prop->doc = doc;
1827 xmlSetListDoc(prop->children, doc);
1828 prop = prop->next;
1829 }
Owen Taylor3473f882001-02-23 17:55:21 +00001830 if (tree->children != NULL)
1831 xmlSetListDoc(tree->children, doc);
1832 tree->doc = doc;
1833 }
1834}
1835
1836/**
1837 * xmlSetListDoc:
1838 * @tree: the first element
1839 * @doc: the document
1840 *
1841 * update all nodes in the list to point to the right document
1842 */
1843void
1844xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1845 xmlNodePtr cur;
1846
1847 if (list == NULL)
1848 return;
1849 cur = list;
1850 while (cur != NULL) {
1851 if (cur->doc != doc)
1852 xmlSetTreeDoc(cur, doc);
1853 cur = cur->next;
1854 }
1855}
1856
1857
1858/**
1859 * xmlNewChild:
1860 * @parent: the parent node
1861 * @ns: a namespace if any
1862 * @name: the name of the child
1863 * @content: the XML content of the child if any.
1864 *
1865 * Creation of a new child element, added at the end of @parent children list.
1866 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1867 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1868 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1869 * references, but XML special chars need to be escaped first by using
1870 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1871 * support is not needed.
1872 *
1873 * Returns a pointer to the new node object.
1874 */
1875xmlNodePtr
1876xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1877 const xmlChar *name, const xmlChar *content) {
1878 xmlNodePtr cur, prev;
1879
1880 if (parent == NULL) {
1881#ifdef DEBUG_TREE
1882 xmlGenericError(xmlGenericErrorContext,
1883 "xmlNewChild : parent == NULL\n");
1884#endif
1885 return(NULL);
1886 }
1887
1888 if (name == NULL) {
1889#ifdef DEBUG_TREE
1890 xmlGenericError(xmlGenericErrorContext,
1891 "xmlNewChild : name == NULL\n");
1892#endif
1893 return(NULL);
1894 }
1895
1896 /*
1897 * Allocate a new node
1898 */
1899 if (ns == NULL)
1900 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1901 else
1902 cur = xmlNewDocNode(parent->doc, ns, name, content);
1903 if (cur == NULL) return(NULL);
1904
1905 /*
1906 * add the new element at the end of the children list.
1907 */
1908 cur->type = XML_ELEMENT_NODE;
1909 cur->parent = parent;
1910 cur->doc = parent->doc;
1911 if (parent->children == NULL) {
1912 parent->children = cur;
1913 parent->last = cur;
1914 } else {
1915 prev = parent->last;
1916 prev->next = cur;
1917 cur->prev = prev;
1918 parent->last = cur;
1919 }
1920
1921 return(cur);
1922}
1923
1924/**
1925 * xmlAddNextSibling:
1926 * @cur: the child node
1927 * @elem: the new node
1928 *
1929 * Add a new element @elem as the next siblings of @cur
1930 * If the new element was already inserted in a document it is
1931 * first unlinked from its existing context.
1932 * As a result of text merging @elem may be freed.
1933 *
1934 * Returns the new element or NULL in case of error.
1935 */
1936xmlNodePtr
1937xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1938 if (cur == NULL) {
1939#ifdef DEBUG_TREE
1940 xmlGenericError(xmlGenericErrorContext,
1941 "xmlAddNextSibling : cur == NULL\n");
1942#endif
1943 return(NULL);
1944 }
1945 if (elem == NULL) {
1946#ifdef DEBUG_TREE
1947 xmlGenericError(xmlGenericErrorContext,
1948 "xmlAddNextSibling : elem == NULL\n");
1949#endif
1950 return(NULL);
1951 }
1952
1953 xmlUnlinkNode(elem);
1954
1955 if (elem->type == XML_TEXT_NODE) {
1956 if (cur->type == XML_TEXT_NODE) {
1957#ifndef XML_USE_BUFFER_CONTENT
1958 xmlNodeAddContent(cur, elem->content);
1959#else
1960 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1961#endif
1962 xmlFreeNode(elem);
1963 return(cur);
1964 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001965 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1966 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001967#ifndef XML_USE_BUFFER_CONTENT
1968 xmlChar *tmp;
1969
1970 tmp = xmlStrdup(elem->content);
1971 tmp = xmlStrcat(tmp, cur->next->content);
1972 xmlNodeSetContent(cur->next, tmp);
1973 xmlFree(tmp);
1974#else
1975 xmlBufferAddHead(cur->next->content,
1976 xmlBufferContent(elem->content),
1977 xmlBufferLength(elem->content));
1978#endif
1979 xmlFreeNode(elem);
1980 return(cur->next);
1981 }
1982 }
1983
1984 if (elem->doc != cur->doc) {
1985 xmlSetTreeDoc(elem, cur->doc);
1986 }
1987 elem->parent = cur->parent;
1988 elem->prev = cur;
1989 elem->next = cur->next;
1990 cur->next = elem;
1991 if (elem->next != NULL)
1992 elem->next->prev = elem;
1993 if ((elem->parent != NULL) && (elem->parent->last == cur))
1994 elem->parent->last = elem;
1995 return(elem);
1996}
1997
1998/**
1999 * xmlAddPrevSibling:
2000 * @cur: the child node
2001 * @elem: the new node
2002 *
2003 * Add a new element @elem as the previous siblings of @cur
2004 * merging adjacent TEXT nodes (@elem may be freed)
2005 * If the new element was already inserted in a document it is
2006 * first unlinked from its existing context.
2007 *
2008 * Returns the new element or NULL in case of error.
2009 */
2010xmlNodePtr
2011xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2012 if (cur == NULL) {
2013#ifdef DEBUG_TREE
2014 xmlGenericError(xmlGenericErrorContext,
2015 "xmlAddPrevSibling : cur == NULL\n");
2016#endif
2017 return(NULL);
2018 }
2019 if (elem == NULL) {
2020#ifdef DEBUG_TREE
2021 xmlGenericError(xmlGenericErrorContext,
2022 "xmlAddPrevSibling : elem == NULL\n");
2023#endif
2024 return(NULL);
2025 }
2026
2027 xmlUnlinkNode(elem);
2028
2029 if (elem->type == XML_TEXT_NODE) {
2030 if (cur->type == XML_TEXT_NODE) {
2031#ifndef XML_USE_BUFFER_CONTENT
2032 xmlChar *tmp;
2033
2034 tmp = xmlStrdup(elem->content);
2035 tmp = xmlStrcat(tmp, cur->content);
2036 xmlNodeSetContent(cur, tmp);
2037 xmlFree(tmp);
2038#else
2039 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2040 xmlBufferLength(elem->content));
2041#endif
2042 xmlFreeNode(elem);
2043 return(cur);
2044 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002045 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2046 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002047#ifndef XML_USE_BUFFER_CONTENT
2048 xmlNodeAddContent(cur->prev, elem->content);
2049#else
2050 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2051#endif
2052 xmlFreeNode(elem);
2053 return(cur->prev);
2054 }
2055 }
2056
2057 if (elem->doc != cur->doc) {
2058 xmlSetTreeDoc(elem, cur->doc);
2059 }
2060 elem->parent = cur->parent;
2061 elem->next = cur;
2062 elem->prev = cur->prev;
2063 cur->prev = elem;
2064 if (elem->prev != NULL)
2065 elem->prev->next = elem;
2066 if ((elem->parent != NULL) && (elem->parent->children == cur))
2067 elem->parent->children = elem;
2068 return(elem);
2069}
2070
2071/**
2072 * xmlAddSibling:
2073 * @cur: the child node
2074 * @elem: the new node
2075 *
2076 * Add a new element @elem to the list of siblings of @cur
2077 * merging adjacent TEXT nodes (@elem may be freed)
2078 * If the new element was already inserted in a document it is
2079 * first unlinked from its existing context.
2080 *
2081 * Returns the new element or NULL in case of error.
2082 */
2083xmlNodePtr
2084xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2085 xmlNodePtr parent;
2086
2087 if (cur == NULL) {
2088#ifdef DEBUG_TREE
2089 xmlGenericError(xmlGenericErrorContext,
2090 "xmlAddSibling : cur == NULL\n");
2091#endif
2092 return(NULL);
2093 }
2094
2095 if (elem == NULL) {
2096#ifdef DEBUG_TREE
2097 xmlGenericError(xmlGenericErrorContext,
2098 "xmlAddSibling : elem == NULL\n");
2099#endif
2100 return(NULL);
2101 }
2102
2103 /*
2104 * Constant time is we can rely on the ->parent->last to find
2105 * the last sibling.
2106 */
2107 if ((cur->parent != NULL) &&
2108 (cur->parent->children != NULL) &&
2109 (cur->parent->last != NULL) &&
2110 (cur->parent->last->next == NULL)) {
2111 cur = cur->parent->last;
2112 } else {
2113 while (cur->next != NULL) cur = cur->next;
2114 }
2115
2116 xmlUnlinkNode(elem);
2117
2118 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2119#ifndef XML_USE_BUFFER_CONTENT
2120 xmlNodeAddContent(cur, elem->content);
2121#else
2122 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2123#endif
2124 xmlFreeNode(elem);
2125 return(cur);
2126 }
2127
2128 if (elem->doc != cur->doc) {
2129 xmlSetTreeDoc(elem, cur->doc);
2130 }
2131 parent = cur->parent;
2132 elem->prev = cur;
2133 elem->next = NULL;
2134 elem->parent = parent;
2135 cur->next = elem;
2136 if (parent != NULL)
2137 parent->last = elem;
2138
2139 return(elem);
2140}
2141
2142/**
2143 * xmlAddChildList:
2144 * @parent: the parent node
2145 * @cur: the first node in the list
2146 *
2147 * Add a list of node at the end of the child list of the parent
2148 * merging adjacent TEXT nodes (@cur may be freed)
2149 *
2150 * Returns the last child or NULL in case of error.
2151 */
2152xmlNodePtr
2153xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2154 xmlNodePtr prev;
2155
2156 if (parent == NULL) {
2157#ifdef DEBUG_TREE
2158 xmlGenericError(xmlGenericErrorContext,
2159 "xmlAddChild : parent == NULL\n");
2160#endif
2161 return(NULL);
2162 }
2163
2164 if (cur == NULL) {
2165#ifdef DEBUG_TREE
2166 xmlGenericError(xmlGenericErrorContext,
2167 "xmlAddChild : child == NULL\n");
2168#endif
2169 return(NULL);
2170 }
2171
2172 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2173 (cur->doc != parent->doc)) {
2174#ifdef DEBUG_TREE
2175 xmlGenericError(xmlGenericErrorContext,
2176 "Elements moved to a different document\n");
2177#endif
2178 }
2179
2180 /*
2181 * add the first element at the end of the children list.
2182 */
2183 if (parent->children == NULL) {
2184 parent->children = cur;
2185 } else {
2186 /*
2187 * If cur and parent->last both are TEXT nodes, then merge them.
2188 */
2189 if ((cur->type == XML_TEXT_NODE) &&
2190 (parent->last->type == XML_TEXT_NODE) &&
2191 (cur->name == parent->last->name)) {
2192#ifndef XML_USE_BUFFER_CONTENT
2193 xmlNodeAddContent(parent->last, cur->content);
2194#else
2195 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2196#endif
2197 /*
2198 * if it's the only child, nothing more to be done.
2199 */
2200 if (cur->next == NULL) {
2201 xmlFreeNode(cur);
2202 return(parent->last);
2203 }
2204 prev = cur;
2205 cur = cur->next;
2206 xmlFreeNode(prev);
2207 }
2208 prev = parent->last;
2209 prev->next = cur;
2210 cur->prev = prev;
2211 }
2212 while (cur->next != NULL) {
2213 cur->parent = parent;
2214 if (cur->doc != parent->doc) {
2215 xmlSetTreeDoc(cur, parent->doc);
2216 }
2217 cur = cur->next;
2218 }
2219 cur->parent = parent;
2220 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2221 parent->last = cur;
2222
2223 return(cur);
2224}
2225
2226/**
2227 * xmlAddChild:
2228 * @parent: the parent node
2229 * @cur: the child node
2230 *
2231 * Add a new child element, to @parent, at the end of the child list
2232 * merging adjacent TEXT nodes (in which case @cur is freed)
2233 * Returns the child or NULL in case of error.
2234 */
2235xmlNodePtr
2236xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2237 xmlNodePtr prev;
2238
2239 if (parent == NULL) {
2240#ifdef DEBUG_TREE
2241 xmlGenericError(xmlGenericErrorContext,
2242 "xmlAddChild : parent == NULL\n");
2243#endif
2244 return(NULL);
2245 }
2246
2247 if (cur == NULL) {
2248#ifdef DEBUG_TREE
2249 xmlGenericError(xmlGenericErrorContext,
2250 "xmlAddChild : child == NULL\n");
2251#endif
2252 return(NULL);
2253 }
2254
Owen Taylor3473f882001-02-23 17:55:21 +00002255 /*
2256 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002257 * cur is then freed.
2258 */
2259 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002260 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002261 (parent->content != NULL)) {
2262#ifndef XML_USE_BUFFER_CONTENT
2263 xmlNodeAddContent(parent, cur->content);
2264#else
2265 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2266#endif
2267 xmlFreeNode(cur);
2268 return(parent);
2269 }
2270 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2271 (parent->last->name == cur->name)) {
2272#ifndef XML_USE_BUFFER_CONTENT
2273 xmlNodeAddContent(parent->last, cur->content);
2274#else
2275 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2276#endif
2277 xmlFreeNode(cur);
2278 return(parent->last);
2279 }
2280 }
2281
2282 /*
2283 * add the new element at the end of the children list.
2284 */
2285 cur->parent = parent;
2286 if (cur->doc != parent->doc) {
2287 xmlSetTreeDoc(cur, parent->doc);
2288 }
2289
2290 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002291 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002292 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002293 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002294 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002295#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002296 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002297#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002298 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002299#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002300 xmlFreeNode(cur);
2301 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002302 }
2303 if (parent->children == NULL) {
2304 parent->children = cur;
2305 parent->last = cur;
2306 } else {
2307 prev = parent->last;
2308 prev->next = cur;
2309 cur->prev = prev;
2310 parent->last = cur;
2311 }
2312
2313 return(cur);
2314}
2315
2316/**
2317 * xmlGetLastChild:
2318 * @parent: the parent node
2319 *
2320 * Search the last child of a node.
2321 * Returns the last child or NULL if none.
2322 */
2323xmlNodePtr
2324xmlGetLastChild(xmlNodePtr parent) {
2325 if (parent == NULL) {
2326#ifdef DEBUG_TREE
2327 xmlGenericError(xmlGenericErrorContext,
2328 "xmlGetLastChild : parent == NULL\n");
2329#endif
2330 return(NULL);
2331 }
2332 return(parent->last);
2333}
2334
2335/**
2336 * xmlFreeNodeList:
2337 * @cur: the first node in the list
2338 *
2339 * Free a node and all its siblings, this is a recursive behaviour, all
2340 * the children are freed too.
2341 */
2342void
2343xmlFreeNodeList(xmlNodePtr cur) {
2344 xmlNodePtr next;
2345 if (cur == NULL) {
2346#ifdef DEBUG_TREE
2347 xmlGenericError(xmlGenericErrorContext,
2348 "xmlFreeNodeList : node == NULL\n");
2349#endif
2350 return;
2351 }
2352 while (cur != NULL) {
2353 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002354 /* unroll to speed up freeing the document */
2355 if (cur->type != XML_DTD_NODE) {
2356 if ((cur->children != NULL) &&
2357 (cur->type != XML_ENTITY_REF_NODE))
2358 xmlFreeNodeList(cur->children);
2359 if (cur->properties != NULL)
2360 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002361 if ((cur->type != XML_ELEMENT_NODE) &&
2362 (cur->type != XML_XINCLUDE_START) &&
2363 (cur->type != XML_XINCLUDE_END) &&
2364 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002365#ifndef XML_USE_BUFFER_CONTENT
2366 if (cur->content != NULL) xmlFree(cur->content);
2367#else
2368 if (cur->content != NULL) xmlBufferFree(cur->content);
2369#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002370 }
2371 if (((cur->type == XML_ELEMENT_NODE) ||
2372 (cur->type == XML_XINCLUDE_START) ||
2373 (cur->type == XML_XINCLUDE_END)) &&
2374 (cur->nsDef != NULL))
2375 xmlFreeNsList(cur->nsDef);
2376
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002377 /*
2378 * When a node is a text node or a comment, it uses a global static
2379 * variable for the name of the node.
2380 *
2381 * The xmlStrEqual comparisons need to be done when (happened with
2382 * XML::libXML and XML::libXSLT) the library is included twice
2383 * statically in the binary and a tree allocated by one occurent
2384 * of the lib gets freed by the other occurence, in this case
2385 * the string addresses compare are not sufficient.
2386 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002387 if ((cur->name != NULL) &&
2388 (cur->name != xmlStringText) &&
2389 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002390 (cur->name != xmlStringComment)) {
2391 if (cur->type == XML_TEXT_NODE) {
2392 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2393 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2394 xmlFree((char *) cur->name);
2395 } else if (cur->type == XML_COMMENT_NODE) {
2396 if (!xmlStrEqual(cur->name, xmlStringComment))
2397 xmlFree((char *) cur->name);
2398 } else
2399 xmlFree((char *) cur->name);
2400 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002401 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002402 xmlFree(cur);
2403 }
Owen Taylor3473f882001-02-23 17:55:21 +00002404 cur = next;
2405 }
2406}
2407
2408/**
2409 * xmlFreeNode:
2410 * @cur: the node
2411 *
2412 * Free a node, this is a recursive behaviour, all the children are freed too.
2413 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2414 */
2415void
2416xmlFreeNode(xmlNodePtr cur) {
2417 if (cur == NULL) {
2418#ifdef DEBUG_TREE
2419 xmlGenericError(xmlGenericErrorContext,
2420 "xmlFreeNode : node == NULL\n");
2421#endif
2422 return;
2423 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002424 /* use xmlFreeDtd for DTD nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002425 if (cur->type == XML_DTD_NODE)
2426 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002427 if ((cur->children != NULL) &&
2428 (cur->type != XML_ENTITY_REF_NODE))
2429 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002430 if (cur->properties != NULL)
2431 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002432 if ((cur->type != XML_ELEMENT_NODE) &&
2433 (cur->content != NULL) &&
2434 (cur->type != XML_ENTITY_REF_NODE) &&
2435 (cur->type != XML_XINCLUDE_END) &&
2436 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002437#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002438 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002439#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002440 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002441#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002442 }
2443
Daniel Veillardacd370f2001-06-09 17:17:51 +00002444 /*
2445 * When a node is a text node or a comment, it uses a global static
2446 * variable for the name of the node.
2447 *
2448 * The xmlStrEqual comparisons need to be done when (happened with
2449 * XML::libXML and XML::libXSLT) the library is included twice statically
2450 * in the binary and a tree allocated by one occurent of the lib gets
2451 * freed by the other occurence, in this case the string addresses compare
2452 * are not sufficient.
2453 */
Owen Taylor3473f882001-02-23 17:55:21 +00002454 if ((cur->name != NULL) &&
2455 (cur->name != xmlStringText) &&
2456 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002457 (cur->name != xmlStringComment)) {
2458 if (cur->type == XML_TEXT_NODE) {
2459 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2460 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2461 xmlFree((char *) cur->name);
2462 } else if (cur->type == XML_COMMENT_NODE) {
2463 if (!xmlStrEqual(cur->name, xmlStringComment))
2464 xmlFree((char *) cur->name);
2465 } else
2466 xmlFree((char *) cur->name);
2467 }
2468
Owen Taylor3473f882001-02-23 17:55:21 +00002469 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002470 xmlFree(cur);
2471}
2472
2473/**
2474 * xmlUnlinkNode:
2475 * @cur: the node
2476 *
2477 * Unlink a node from it's current context, the node is not freed
2478 */
2479void
2480xmlUnlinkNode(xmlNodePtr cur) {
2481 if (cur == NULL) {
2482#ifdef DEBUG_TREE
2483 xmlGenericError(xmlGenericErrorContext,
2484 "xmlUnlinkNode : node == NULL\n");
2485#endif
2486 return;
2487 }
2488 if ((cur->parent != NULL) && (cur->parent->children == cur))
2489 cur->parent->children = cur->next;
2490 if ((cur->parent != NULL) && (cur->parent->last == cur))
2491 cur->parent->last = cur->prev;
2492 if (cur->next != NULL)
2493 cur->next->prev = cur->prev;
2494 if (cur->prev != NULL)
2495 cur->prev->next = cur->next;
2496 cur->next = cur->prev = NULL;
2497 cur->parent = NULL;
2498}
2499
2500/**
2501 * xmlReplaceNode:
2502 * @old: the old node
2503 * @cur: the node
2504 *
2505 * Unlink the old node from it's current context, prune the new one
2506 * at the same place. If cur was already inserted in a document it is
2507 * first unlinked from its existing context.
2508 *
2509 * Returns the old node
2510 */
2511xmlNodePtr
2512xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2513 if (old == NULL) {
2514#ifdef DEBUG_TREE
2515 xmlGenericError(xmlGenericErrorContext,
2516 "xmlReplaceNode : old == NULL\n");
2517#endif
2518 return(NULL);
2519 }
2520 if (cur == NULL) {
2521 xmlUnlinkNode(old);
2522 return(old);
2523 }
2524 if (cur == old) {
2525 return(old);
2526 }
2527 xmlUnlinkNode(cur);
2528 cur->doc = old->doc;
2529 cur->parent = old->parent;
2530 cur->next = old->next;
2531 if (cur->next != NULL)
2532 cur->next->prev = cur;
2533 cur->prev = old->prev;
2534 if (cur->prev != NULL)
2535 cur->prev->next = cur;
2536 if (cur->parent != NULL) {
2537 if (cur->parent->children == old)
2538 cur->parent->children = cur;
2539 if (cur->parent->last == old)
2540 cur->parent->last = cur;
2541 }
2542 old->next = old->prev = NULL;
2543 old->parent = NULL;
2544 return(old);
2545}
2546
2547/************************************************************************
2548 * *
2549 * Copy operations *
2550 * *
2551 ************************************************************************/
2552
2553/**
2554 * xmlCopyNamespace:
2555 * @cur: the namespace
2556 *
2557 * Do a copy of the namespace.
2558 *
2559 * Returns: a new xmlNsPtr, or NULL in case of error.
2560 */
2561xmlNsPtr
2562xmlCopyNamespace(xmlNsPtr cur) {
2563 xmlNsPtr ret;
2564
2565 if (cur == NULL) return(NULL);
2566 switch (cur->type) {
2567 case XML_LOCAL_NAMESPACE:
2568 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2569 break;
2570 default:
2571#ifdef DEBUG_TREE
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlCopyNamespace: invalid type %d\n", cur->type);
2574#endif
2575 return(NULL);
2576 }
2577 return(ret);
2578}
2579
2580/**
2581 * xmlCopyNamespaceList:
2582 * @cur: the first namespace
2583 *
2584 * Do a copy of an namespace list.
2585 *
2586 * Returns: a new xmlNsPtr, or NULL in case of error.
2587 */
2588xmlNsPtr
2589xmlCopyNamespaceList(xmlNsPtr cur) {
2590 xmlNsPtr ret = NULL;
2591 xmlNsPtr p = NULL,q;
2592
2593 while (cur != NULL) {
2594 q = xmlCopyNamespace(cur);
2595 if (p == NULL) {
2596 ret = p = q;
2597 } else {
2598 p->next = q;
2599 p = q;
2600 }
2601 cur = cur->next;
2602 }
2603 return(ret);
2604}
2605
2606static xmlNodePtr
2607xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2608/**
2609 * xmlCopyProp:
2610 * @target: the element where the attribute will be grafted
2611 * @cur: the attribute
2612 *
2613 * Do a copy of the attribute.
2614 *
2615 * Returns: a new xmlAttrPtr, or NULL in case of error.
2616 */
2617xmlAttrPtr
2618xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2619 xmlAttrPtr ret;
2620
2621 if (cur == NULL) return(NULL);
2622 if (target != NULL)
2623 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2624 else if (cur->parent != NULL)
2625 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2626 else if (cur->children != NULL)
2627 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2628 else
2629 ret = xmlNewDocProp(NULL, cur->name, NULL);
2630 if (ret == NULL) return(NULL);
2631 ret->parent = target;
2632
2633 if ((cur->ns != NULL) && (target != NULL)) {
2634 xmlNsPtr ns;
2635
2636 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2637 ret->ns = ns;
2638 } else
2639 ret->ns = NULL;
2640
2641 if (cur->children != NULL) {
2642 xmlNodePtr tmp;
2643
2644 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2645 ret->last = NULL;
2646 tmp = ret->children;
2647 while (tmp != NULL) {
2648 /* tmp->parent = (xmlNodePtr)ret; */
2649 if (tmp->next == NULL)
2650 ret->last = tmp;
2651 tmp = tmp->next;
2652 }
2653 }
2654 return(ret);
2655}
2656
2657/**
2658 * xmlCopyPropList:
2659 * @target: the element where the attributes will be grafted
2660 * @cur: the first attribute
2661 *
2662 * Do a copy of an attribute list.
2663 *
2664 * Returns: a new xmlAttrPtr, or NULL in case of error.
2665 */
2666xmlAttrPtr
2667xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2668 xmlAttrPtr ret = NULL;
2669 xmlAttrPtr p = NULL,q;
2670
2671 while (cur != NULL) {
2672 q = xmlCopyProp(target, cur);
2673 if (p == NULL) {
2674 ret = p = q;
2675 } else {
2676 p->next = q;
2677 q->prev = p;
2678 p = q;
2679 }
2680 cur = cur->next;
2681 }
2682 return(ret);
2683}
2684
2685/*
2686 * NOTE abeut the CopyNode operations !
2687 *
2688 * They are splitted into external and internal parts for one
2689 * tricky reason: namespaces. Doing a direct copy of a node
2690 * say RPM:Copyright without changing the namespace pointer to
2691 * something else can produce stale links. One way to do it is
2692 * to keep a reference counter but this doesn't work as soon
2693 * as one move the element or the subtree out of the scope of
2694 * the existing namespace. The actual solution seems to add
2695 * a copy of the namespace at the top of the copied tree if
2696 * not available in the subtree.
2697 * Hence two functions, the public front-end call the inner ones
2698 */
2699
2700static xmlNodePtr
2701xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2702
2703static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002704xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002705 int recursive) {
2706 xmlNodePtr ret;
2707
2708 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002709 switch (node->type) {
2710 case XML_TEXT_NODE:
2711 case XML_CDATA_SECTION_NODE:
2712 case XML_ELEMENT_NODE:
2713 case XML_ENTITY_REF_NODE:
2714 case XML_ENTITY_NODE:
2715 case XML_PI_NODE:
2716 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002717 case XML_XINCLUDE_START:
2718 case XML_XINCLUDE_END:
2719 break;
2720 case XML_ATTRIBUTE_NODE:
2721 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2722 case XML_NAMESPACE_DECL:
2723 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2724
Daniel Veillard39196eb2001-06-19 18:09:42 +00002725 case XML_DOCUMENT_NODE:
2726 case XML_HTML_DOCUMENT_NODE:
2727#ifdef LIBXML_DOCB_ENABLED
2728 case XML_DOCB_DOCUMENT_NODE:
2729#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002730 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002731 case XML_DOCUMENT_TYPE_NODE:
2732 case XML_DOCUMENT_FRAG_NODE:
2733 case XML_NOTATION_NODE:
2734 case XML_DTD_NODE:
2735 case XML_ELEMENT_DECL:
2736 case XML_ATTRIBUTE_DECL:
2737 case XML_ENTITY_DECL:
2738 return(NULL);
2739 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002740
Owen Taylor3473f882001-02-23 17:55:21 +00002741 /*
2742 * Allocate a new node and fill the fields.
2743 */
2744 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2745 if (ret == NULL) {
2746 xmlGenericError(xmlGenericErrorContext,
2747 "xmlStaticCopyNode : malloc failed\n");
2748 return(NULL);
2749 }
2750 memset(ret, 0, sizeof(xmlNode));
2751 ret->type = node->type;
2752
2753 ret->doc = doc;
2754 ret->parent = parent;
2755 if (node->name == xmlStringText)
2756 ret->name = xmlStringText;
2757 else if (node->name == xmlStringTextNoenc)
2758 ret->name = xmlStringTextNoenc;
2759 else if (node->name == xmlStringComment)
2760 ret->name = xmlStringComment;
2761 else if (node->name != NULL)
2762 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002763 if ((node->type != XML_ELEMENT_NODE) &&
2764 (node->content != NULL) &&
2765 (node->type != XML_ENTITY_REF_NODE) &&
2766 (node->type != XML_XINCLUDE_END) &&
2767 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002768#ifndef XML_USE_BUFFER_CONTENT
2769 ret->content = xmlStrdup(node->content);
2770#else
2771 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2772 xmlBufferSetAllocationScheme(ret->content,
2773 xmlGetBufferAllocationScheme());
2774 xmlBufferAdd(ret->content,
2775 xmlBufferContent(node->content),
2776 xmlBufferLength(node->content));
2777#endif
2778 }
2779 if (parent != NULL)
2780 xmlAddChild(parent, ret);
2781
2782 if (!recursive) return(ret);
2783 if (node->nsDef != NULL)
2784 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2785
2786 if (node->ns != NULL) {
2787 xmlNsPtr ns;
2788
2789 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2790 if (ns == NULL) {
2791 /*
2792 * Humm, we are copying an element whose namespace is defined
2793 * out of the new tree scope. Search it in the original tree
2794 * and add it at the top of the new tree
2795 */
2796 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2797 if (ns != NULL) {
2798 xmlNodePtr root = ret;
2799
2800 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002801 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002802 }
2803 } else {
2804 /*
2805 * reference the existing namespace definition in our own tree.
2806 */
2807 ret->ns = ns;
2808 }
2809 }
2810 if (node->properties != NULL)
2811 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002812 if (node->type == XML_ENTITY_REF_NODE) {
2813 if ((doc == NULL) || (node->doc != doc)) {
2814 /*
2815 * The copied node will go into a separate document, so
2816 * to havoid dandling references to the ENTITY_DECL node
2817 * we cannot keep the reference. Try to find it in the
2818 * target document.
2819 */
2820 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2821 } else {
2822 ret->children = node->children;
2823 }
2824 } else if (node->children != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002825 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
2826 UPDATE_LAST_CHILD_AND_PARENT(ret)
2827 return(ret);
2828}
2829
2830static xmlNodePtr
2831xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2832 xmlNodePtr ret = NULL;
2833 xmlNodePtr p = NULL,q;
2834
2835 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002836 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002837 if (doc == NULL) {
2838 node = node->next;
2839 continue;
2840 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002841 if (doc->intSubset == NULL) {
2842 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2843 q->doc = doc;
2844 q->parent = parent;
2845 doc->intSubset = (xmlDtdPtr) q;
2846 } else {
2847 q = (xmlNodePtr) doc->intSubset;
2848 }
2849 } else
2850 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002851 if (ret == NULL) {
2852 q->prev = NULL;
2853 ret = p = q;
2854 } else {
2855 p->next = q;
2856 q->prev = p;
2857 p = q;
2858 }
2859 node = node->next;
2860 }
2861 return(ret);
2862}
2863
2864/**
2865 * xmlCopyNode:
2866 * @node: the node
2867 * @recursive: if 1 do a recursive copy.
2868 *
2869 * Do a copy of the node.
2870 *
2871 * Returns: a new xmlNodePtr, or NULL in case of error.
2872 */
2873xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002874xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002875 xmlNodePtr ret;
2876
2877 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2878 return(ret);
2879}
2880
2881/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002882 * xmlDocCopyNode:
2883 * @node: the node
2884 * @recursive: if 1 do a recursive copy.
2885 *
2886 * Do a copy of the node to a given document.
2887 *
2888 * Returns: a new xmlNodePtr, or NULL in case of error.
2889 */
2890xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002891xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002892 xmlNodePtr ret;
2893
2894 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2895 return(ret);
2896}
2897
2898/**
Owen Taylor3473f882001-02-23 17:55:21 +00002899 * xmlCopyNodeList:
2900 * @node: the first node in the list.
2901 *
2902 * Do a recursive copy of the node list.
2903 *
2904 * Returns: a new xmlNodePtr, or NULL in case of error.
2905 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002906xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002907 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2908 return(ret);
2909}
2910
2911/**
Owen Taylor3473f882001-02-23 17:55:21 +00002912 * xmlCopyDtd:
2913 * @dtd: the dtd
2914 *
2915 * Do a copy of the dtd.
2916 *
2917 * Returns: a new xmlDtdPtr, or NULL in case of error.
2918 */
2919xmlDtdPtr
2920xmlCopyDtd(xmlDtdPtr dtd) {
2921 xmlDtdPtr ret;
2922
2923 if (dtd == NULL) return(NULL);
2924 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2925 if (ret == NULL) return(NULL);
2926 if (dtd->entities != NULL)
2927 ret->entities = (void *) xmlCopyEntitiesTable(
2928 (xmlEntitiesTablePtr) dtd->entities);
2929 if (dtd->notations != NULL)
2930 ret->notations = (void *) xmlCopyNotationTable(
2931 (xmlNotationTablePtr) dtd->notations);
2932 if (dtd->elements != NULL)
2933 ret->elements = (void *) xmlCopyElementTable(
2934 (xmlElementTablePtr) dtd->elements);
2935 if (dtd->attributes != NULL)
2936 ret->attributes = (void *) xmlCopyAttributeTable(
2937 (xmlAttributeTablePtr) dtd->attributes);
2938 return(ret);
2939}
2940
2941/**
2942 * xmlCopyDoc:
2943 * @doc: the document
2944 * @recursive: if 1 do a recursive copy.
2945 *
2946 * Do a copy of the document info. If recursive, the content tree will
2947 * be copied too as well as Dtd, namespaces and entities.
2948 *
2949 * Returns: a new xmlDocPtr, or NULL in case of error.
2950 */
2951xmlDocPtr
2952xmlCopyDoc(xmlDocPtr doc, int recursive) {
2953 xmlDocPtr ret;
2954
2955 if (doc == NULL) return(NULL);
2956 ret = xmlNewDoc(doc->version);
2957 if (ret == NULL) return(NULL);
2958 if (doc->name != NULL)
2959 ret->name = xmlMemStrdup(doc->name);
2960 if (doc->encoding != NULL)
2961 ret->encoding = xmlStrdup(doc->encoding);
2962 ret->charset = doc->charset;
2963 ret->compression = doc->compression;
2964 ret->standalone = doc->standalone;
2965 if (!recursive) return(ret);
2966
Daniel Veillardb33c2012001-04-25 12:59:04 +00002967 ret->last = NULL;
2968 ret->children = NULL;
2969 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002970 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002971 ret->intSubset->doc = ret;
2972 ret->intSubset->parent = ret;
2973 }
Owen Taylor3473f882001-02-23 17:55:21 +00002974 if (doc->oldNs != NULL)
2975 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2976 if (doc->children != NULL) {
2977 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002978
2979 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2980 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002981 ret->last = NULL;
2982 tmp = ret->children;
2983 while (tmp != NULL) {
2984 if (tmp->next == NULL)
2985 ret->last = tmp;
2986 tmp = tmp->next;
2987 }
2988 }
2989 return(ret);
2990}
2991
2992/************************************************************************
2993 * *
2994 * Content access functions *
2995 * *
2996 ************************************************************************/
2997
2998/**
2999 * xmlDocGetRootElement:
3000 * @doc: the document
3001 *
3002 * Get the root element of the document (doc->children is a list
3003 * containing possibly comments, PIs, etc ...).
3004 *
3005 * Returns the xmlNodePtr for the root or NULL
3006 */
3007xmlNodePtr
3008xmlDocGetRootElement(xmlDocPtr doc) {
3009 xmlNodePtr ret;
3010
3011 if (doc == NULL) return(NULL);
3012 ret = doc->children;
3013 while (ret != NULL) {
3014 if (ret->type == XML_ELEMENT_NODE)
3015 return(ret);
3016 ret = ret->next;
3017 }
3018 return(ret);
3019}
3020
3021/**
3022 * xmlDocSetRootElement:
3023 * @doc: the document
3024 * @root: the new document root element
3025 *
3026 * Set the root element of the document (doc->children is a list
3027 * containing possibly comments, PIs, etc ...).
3028 *
3029 * Returns the old root element if any was found
3030 */
3031xmlNodePtr
3032xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3033 xmlNodePtr old = NULL;
3034
3035 if (doc == NULL) return(NULL);
3036 old = doc->children;
3037 while (old != NULL) {
3038 if (old->type == XML_ELEMENT_NODE)
3039 break;
3040 old = old->next;
3041 }
3042 if (old == NULL) {
3043 if (doc->children == NULL) {
3044 doc->children = root;
3045 doc->last = root;
3046 } else {
3047 xmlAddSibling(doc->children, root);
3048 }
3049 } else {
3050 xmlReplaceNode(old, root);
3051 }
3052 return(old);
3053}
3054
3055/**
3056 * xmlNodeSetLang:
3057 * @cur: the node being changed
3058 * @lang: the langage description
3059 *
3060 * Set the language of a node, i.e. the values of the xml:lang
3061 * attribute.
3062 */
3063void
3064xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3065 if (cur == NULL) return;
3066 switch(cur->type) {
3067 case XML_TEXT_NODE:
3068 case XML_CDATA_SECTION_NODE:
3069 case XML_COMMENT_NODE:
3070 case XML_DOCUMENT_NODE:
3071 case XML_DOCUMENT_TYPE_NODE:
3072 case XML_DOCUMENT_FRAG_NODE:
3073 case XML_NOTATION_NODE:
3074 case XML_HTML_DOCUMENT_NODE:
3075 case XML_DTD_NODE:
3076 case XML_ELEMENT_DECL:
3077 case XML_ATTRIBUTE_DECL:
3078 case XML_ENTITY_DECL:
3079 case XML_PI_NODE:
3080 case XML_ENTITY_REF_NODE:
3081 case XML_ENTITY_NODE:
3082 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003083#ifdef LIBXML_DOCB_ENABLED
3084 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003085#endif
3086 case XML_XINCLUDE_START:
3087 case XML_XINCLUDE_END:
3088 return;
3089 case XML_ELEMENT_NODE:
3090 case XML_ATTRIBUTE_NODE:
3091 break;
3092 }
3093 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3094}
3095
3096/**
3097 * xmlNodeGetLang:
3098 * @cur: the node being checked
3099 *
3100 * Searches the language of a node, i.e. the values of the xml:lang
3101 * attribute or the one carried by the nearest ancestor.
3102 *
3103 * Returns a pointer to the lang value, or NULL if not found
3104 * It's up to the caller to free the memory.
3105 */
3106xmlChar *
3107xmlNodeGetLang(xmlNodePtr cur) {
3108 xmlChar *lang;
3109
3110 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003111 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003112 if (lang != NULL)
3113 return(lang);
3114 cur = cur->parent;
3115 }
3116 return(NULL);
3117}
3118
3119
3120/**
3121 * xmlNodeSetSpacePreserve:
3122 * @cur: the node being changed
3123 * @val: the xml:space value ("0": default, 1: "preserve")
3124 *
3125 * Set (or reset) the space preserving behaviour of a node, i.e. the
3126 * value of the xml:space attribute.
3127 */
3128void
3129xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3130 if (cur == NULL) return;
3131 switch(cur->type) {
3132 case XML_TEXT_NODE:
3133 case XML_CDATA_SECTION_NODE:
3134 case XML_COMMENT_NODE:
3135 case XML_DOCUMENT_NODE:
3136 case XML_DOCUMENT_TYPE_NODE:
3137 case XML_DOCUMENT_FRAG_NODE:
3138 case XML_NOTATION_NODE:
3139 case XML_HTML_DOCUMENT_NODE:
3140 case XML_DTD_NODE:
3141 case XML_ELEMENT_DECL:
3142 case XML_ATTRIBUTE_DECL:
3143 case XML_ENTITY_DECL:
3144 case XML_PI_NODE:
3145 case XML_ENTITY_REF_NODE:
3146 case XML_ENTITY_NODE:
3147 case XML_NAMESPACE_DECL:
3148 case XML_XINCLUDE_START:
3149 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003150#ifdef LIBXML_DOCB_ENABLED
3151 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003152#endif
3153 return;
3154 case XML_ELEMENT_NODE:
3155 case XML_ATTRIBUTE_NODE:
3156 break;
3157 }
3158 switch (val) {
3159 case 0:
3160 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3161 break;
3162 case 1:
3163 xmlSetProp(cur, BAD_CAST "xml:space",
3164 BAD_CAST "preserve");
3165 break;
3166 }
3167}
3168
3169/**
3170 * xmlNodeGetSpacePreserve:
3171 * @cur: the node being checked
3172 *
3173 * Searches the space preserving behaviour of a node, i.e. the values
3174 * of the xml:space attribute or the one carried by the nearest
3175 * ancestor.
3176 *
3177 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
3178 */
3179int
3180xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3181 xmlChar *space;
3182
3183 while (cur != NULL) {
3184 space = xmlGetProp(cur, BAD_CAST "xml:space");
3185 if (space != NULL) {
3186 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3187 xmlFree(space);
3188 return(1);
3189 }
3190 if (xmlStrEqual(space, BAD_CAST "default")) {
3191 xmlFree(space);
3192 return(0);
3193 }
3194 xmlFree(space);
3195 }
3196 cur = cur->parent;
3197 }
3198 return(-1);
3199}
3200
3201/**
3202 * xmlNodeSetName:
3203 * @cur: the node being changed
3204 * @name: the new tag name
3205 *
3206 * Set (or reset) the name of a node.
3207 */
3208void
3209xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3210 if (cur == NULL) return;
3211 if (name == NULL) return;
3212 switch(cur->type) {
3213 case XML_TEXT_NODE:
3214 case XML_CDATA_SECTION_NODE:
3215 case XML_COMMENT_NODE:
3216 case XML_DOCUMENT_TYPE_NODE:
3217 case XML_DOCUMENT_FRAG_NODE:
3218 case XML_NOTATION_NODE:
3219 case XML_HTML_DOCUMENT_NODE:
3220 case XML_NAMESPACE_DECL:
3221 case XML_XINCLUDE_START:
3222 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003223#ifdef LIBXML_DOCB_ENABLED
3224 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003225#endif
3226 return;
3227 case XML_ELEMENT_NODE:
3228 case XML_ATTRIBUTE_NODE:
3229 case XML_PI_NODE:
3230 case XML_ENTITY_REF_NODE:
3231 case XML_ENTITY_NODE:
3232 case XML_DTD_NODE:
3233 case XML_DOCUMENT_NODE:
3234 case XML_ELEMENT_DECL:
3235 case XML_ATTRIBUTE_DECL:
3236 case XML_ENTITY_DECL:
3237 break;
3238 }
3239 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3240 cur->name = xmlStrdup(name);
3241}
3242
3243/**
3244 * xmlNodeSetBase:
3245 * @cur: the node being changed
3246 * @uri: the new base URI
3247 *
3248 * Set (or reset) the base URI of a node, i.e. the value of the
3249 * xml:base attribute.
3250 */
3251void
3252xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3253 if (cur == NULL) return;
3254 switch(cur->type) {
3255 case XML_TEXT_NODE:
3256 case XML_CDATA_SECTION_NODE:
3257 case XML_COMMENT_NODE:
3258 case XML_DOCUMENT_NODE:
3259 case XML_DOCUMENT_TYPE_NODE:
3260 case XML_DOCUMENT_FRAG_NODE:
3261 case XML_NOTATION_NODE:
3262 case XML_HTML_DOCUMENT_NODE:
3263 case XML_DTD_NODE:
3264 case XML_ELEMENT_DECL:
3265 case XML_ATTRIBUTE_DECL:
3266 case XML_ENTITY_DECL:
3267 case XML_PI_NODE:
3268 case XML_ENTITY_REF_NODE:
3269 case XML_ENTITY_NODE:
3270 case XML_NAMESPACE_DECL:
3271 case XML_XINCLUDE_START:
3272 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003273#ifdef LIBXML_DOCB_ENABLED
3274 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003275#endif
3276 return;
3277 case XML_ELEMENT_NODE:
3278 case XML_ATTRIBUTE_NODE:
3279 break;
3280 }
3281 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3282}
3283
3284/**
Owen Taylor3473f882001-02-23 17:55:21 +00003285 * xmlNodeGetBase:
3286 * @doc: the document the node pertains to
3287 * @cur: the node being checked
3288 *
3289 * Searches for the BASE URL. The code should work on both XML
3290 * and HTML document even if base mechanisms are completely different.
3291 * It returns the base as defined in RFC 2396 sections
3292 * 5.1.1. Base URI within Document Content
3293 * and
3294 * 5.1.2. Base URI from the Encapsulating Entity
3295 * However it does not return the document base (5.1.3), use
3296 * xmlDocumentGetBase() for this
3297 *
3298 * Returns a pointer to the base URL, or NULL if not found
3299 * It's up to the caller to free the memory.
3300 */
3301xmlChar *
3302xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003303 xmlChar *oldbase = NULL;
3304 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003305
3306 if ((cur == NULL) && (doc == NULL))
3307 return(NULL);
3308 if (doc == NULL) doc = cur->doc;
3309 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3310 cur = doc->children;
3311 while ((cur != NULL) && (cur->name != NULL)) {
3312 if (cur->type != XML_ELEMENT_NODE) {
3313 cur = cur->next;
3314 continue;
3315 }
3316 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3317 cur = cur->children;
3318 continue;
3319 }
3320 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3321 cur = cur->children;
3322 continue;
3323 }
3324 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3325 return(xmlGetProp(cur, BAD_CAST "href"));
3326 }
3327 cur = cur->next;
3328 }
3329 return(NULL);
3330 }
3331 while (cur != NULL) {
3332 if (cur->type == XML_ENTITY_DECL) {
3333 xmlEntityPtr ent = (xmlEntityPtr) cur;
3334 return(xmlStrdup(ent->URI));
3335 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003336 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003337 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003338 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003339 if (oldbase != NULL) {
3340 newbase = xmlBuildURI(oldbase, base);
3341 if (newbase != NULL) {
3342 xmlFree(oldbase);
3343 xmlFree(base);
3344 oldbase = newbase;
3345 } else {
3346 xmlFree(oldbase);
3347 xmlFree(base);
3348 return(NULL);
3349 }
3350 } else {
3351 oldbase = base;
3352 }
3353 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3354 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3355 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3356 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003357 }
3358 }
Owen Taylor3473f882001-02-23 17:55:21 +00003359 cur = cur->parent;
3360 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003361 if ((doc != NULL) && (doc->URL != NULL)) {
3362 if (oldbase == NULL)
3363 return(xmlStrdup(doc->URL));
3364 newbase = xmlBuildURI(oldbase, doc->URL);
3365 xmlFree(oldbase);
3366 return(newbase);
3367 }
3368 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003369}
3370
3371/**
3372 * xmlNodeGetContent:
3373 * @cur: the node being read
3374 *
3375 * Read the value of a node, this can be either the text carried
3376 * directly by this node if it's a TEXT node or the aggregate string
3377 * of the values carried by this node child's (TEXT and ENTITY_REF).
3378 * Entity references are substitued.
3379 * Returns a new xmlChar * or NULL if no content is available.
3380 * It's up to the caller to free the memory.
3381 */
3382xmlChar *
3383xmlNodeGetContent(xmlNodePtr cur) {
3384 if (cur == NULL) return(NULL);
3385 switch (cur->type) {
3386 case XML_DOCUMENT_FRAG_NODE:
3387 case XML_ELEMENT_NODE: {
3388 xmlNodePtr tmp = cur;
3389 xmlBufferPtr buffer;
3390 xmlChar *ret;
3391
3392 buffer = xmlBufferCreate();
3393 if (buffer == NULL)
3394 return(NULL);
3395 while (tmp != NULL) {
3396 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003397 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003398 case XML_TEXT_NODE:
3399 if (tmp->content != NULL)
3400#ifndef XML_USE_BUFFER_CONTENT
3401 xmlBufferCat(buffer, tmp->content);
3402#else
3403 xmlBufferCat(buffer,
3404 xmlBufferContent(tmp->content));
3405#endif
3406 break;
3407 case XML_ENTITY_REF_NODE: {
3408 xmlEntityPtr ent;
3409
3410 ent = xmlGetDocEntity(cur->doc, tmp->name);
3411 if (ent != NULL)
3412 xmlBufferCat(buffer, ent->content);
3413 }
3414 default:
3415 break;
3416 }
3417 /*
3418 * Skip to next node
3419 */
3420 if (tmp->children != NULL) {
3421 if (tmp->children->type != XML_ENTITY_DECL) {
3422 tmp = tmp->children;
3423 continue;
3424 }
3425 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003426 if (tmp == cur)
3427 break;
3428
Owen Taylor3473f882001-02-23 17:55:21 +00003429 if (tmp->next != NULL) {
3430 tmp = tmp->next;
3431 continue;
3432 }
3433
3434 do {
3435 tmp = tmp->parent;
3436 if (tmp == NULL)
3437 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003438 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003439 tmp = NULL;
3440 break;
3441 }
3442 if (tmp->next != NULL) {
3443 tmp = tmp->next;
3444 break;
3445 }
3446 } while (tmp != NULL);
3447 }
3448 ret = buffer->content;
3449 buffer->content = NULL;
3450 xmlBufferFree(buffer);
3451 return(ret);
3452 }
3453 case XML_ATTRIBUTE_NODE: {
3454 xmlAttrPtr attr = (xmlAttrPtr) cur;
3455 if (attr->parent != NULL)
3456 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3457 else
3458 return(xmlNodeListGetString(NULL, attr->children, 1));
3459 break;
3460 }
3461 case XML_COMMENT_NODE:
3462 case XML_PI_NODE:
3463 if (cur->content != NULL)
3464#ifndef XML_USE_BUFFER_CONTENT
3465 return(xmlStrdup(cur->content));
3466#else
3467 return(xmlStrdup(xmlBufferContent(cur->content)));
3468#endif
3469 return(NULL);
3470 case XML_ENTITY_REF_NODE:
3471 /*
3472 * Locate the entity, and get it's content
3473 * @@@
3474 */
3475 return(NULL);
3476 case XML_ENTITY_NODE:
3477 case XML_DOCUMENT_NODE:
3478 case XML_HTML_DOCUMENT_NODE:
3479 case XML_DOCUMENT_TYPE_NODE:
3480 case XML_NOTATION_NODE:
3481 case XML_DTD_NODE:
3482 case XML_XINCLUDE_START:
3483 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003484#ifdef LIBXML_DOCB_ENABLED
3485 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003486#endif
3487 return(NULL);
3488 case XML_NAMESPACE_DECL:
3489 return(xmlStrdup(((xmlNsPtr)cur)->href));
3490 case XML_ELEMENT_DECL:
3491 /* TODO !!! */
3492 return(NULL);
3493 case XML_ATTRIBUTE_DECL:
3494 /* TODO !!! */
3495 return(NULL);
3496 case XML_ENTITY_DECL:
3497 /* TODO !!! */
3498 return(NULL);
3499 case XML_CDATA_SECTION_NODE:
3500 case XML_TEXT_NODE:
3501 if (cur->content != NULL)
3502#ifndef XML_USE_BUFFER_CONTENT
3503 return(xmlStrdup(cur->content));
3504#else
3505 return(xmlStrdup(xmlBufferContent(cur->content)));
3506#endif
3507 return(NULL);
3508 }
3509 return(NULL);
3510}
3511
3512/**
3513 * xmlNodeSetContent:
3514 * @cur: the node being modified
3515 * @content: the new value of the content
3516 *
3517 * Replace the content of a node.
3518 */
3519void
3520xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3521 if (cur == NULL) {
3522#ifdef DEBUG_TREE
3523 xmlGenericError(xmlGenericErrorContext,
3524 "xmlNodeSetContent : node == NULL\n");
3525#endif
3526 return;
3527 }
3528 switch (cur->type) {
3529 case XML_DOCUMENT_FRAG_NODE:
3530 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003531 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3532 cur->children = xmlStringGetNodeList(cur->doc, content);
3533 UPDATE_LAST_CHILD_AND_PARENT(cur)
3534 break;
3535 case XML_ATTRIBUTE_NODE:
3536 break;
3537 case XML_TEXT_NODE:
3538 case XML_CDATA_SECTION_NODE:
3539 case XML_ENTITY_REF_NODE:
3540 case XML_ENTITY_NODE:
3541 case XML_PI_NODE:
3542 case XML_COMMENT_NODE:
3543 if (cur->content != NULL) {
3544#ifndef XML_USE_BUFFER_CONTENT
3545 xmlFree(cur->content);
3546#else
3547 xmlBufferFree(cur->content);
3548#endif
3549 }
3550 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3551 cur->last = cur->children = NULL;
3552 if (content != NULL) {
3553#ifndef XML_USE_BUFFER_CONTENT
3554 cur->content = xmlStrdup(content);
3555#else
3556 cur->content = xmlBufferCreateSize(0);
3557 xmlBufferSetAllocationScheme(cur->content,
3558 xmlGetBufferAllocationScheme());
3559 xmlBufferAdd(cur->content, content, -1);
3560#endif
3561 } else
3562 cur->content = NULL;
3563 break;
3564 case XML_DOCUMENT_NODE:
3565 case XML_HTML_DOCUMENT_NODE:
3566 case XML_DOCUMENT_TYPE_NODE:
3567 case XML_XINCLUDE_START:
3568 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003569#ifdef LIBXML_DOCB_ENABLED
3570 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003571#endif
3572 break;
3573 case XML_NOTATION_NODE:
3574 break;
3575 case XML_DTD_NODE:
3576 break;
3577 case XML_NAMESPACE_DECL:
3578 break;
3579 case XML_ELEMENT_DECL:
3580 /* TODO !!! */
3581 break;
3582 case XML_ATTRIBUTE_DECL:
3583 /* TODO !!! */
3584 break;
3585 case XML_ENTITY_DECL:
3586 /* TODO !!! */
3587 break;
3588 }
3589}
3590
3591/**
3592 * xmlNodeSetContentLen:
3593 * @cur: the node being modified
3594 * @content: the new value of the content
3595 * @len: the size of @content
3596 *
3597 * Replace the content of a node.
3598 */
3599void
3600xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3601 if (cur == NULL) {
3602#ifdef DEBUG_TREE
3603 xmlGenericError(xmlGenericErrorContext,
3604 "xmlNodeSetContentLen : node == NULL\n");
3605#endif
3606 return;
3607 }
3608 switch (cur->type) {
3609 case XML_DOCUMENT_FRAG_NODE:
3610 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003611 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3612 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3613 UPDATE_LAST_CHILD_AND_PARENT(cur)
3614 break;
3615 case XML_ATTRIBUTE_NODE:
3616 break;
3617 case XML_TEXT_NODE:
3618 case XML_CDATA_SECTION_NODE:
3619 case XML_ENTITY_REF_NODE:
3620 case XML_ENTITY_NODE:
3621 case XML_PI_NODE:
3622 case XML_COMMENT_NODE:
3623 case XML_NOTATION_NODE:
3624 if (cur->content != NULL) {
3625#ifndef XML_USE_BUFFER_CONTENT
3626 xmlFree(cur->content);
3627#else
3628 xmlBufferFree(cur->content);
3629#endif
3630 }
3631 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3632 cur->children = cur->last = NULL;
3633 if (content != NULL) {
3634#ifndef XML_USE_BUFFER_CONTENT
3635 cur->content = xmlStrndup(content, len);
3636#else
3637 cur->content = xmlBufferCreateSize(len);
3638 xmlBufferSetAllocationScheme(cur->content,
3639 xmlGetBufferAllocationScheme());
3640 xmlBufferAdd(cur->content, content, len);
3641#endif
3642 } else
3643 cur->content = NULL;
3644 break;
3645 case XML_DOCUMENT_NODE:
3646 case XML_DTD_NODE:
3647 case XML_HTML_DOCUMENT_NODE:
3648 case XML_DOCUMENT_TYPE_NODE:
3649 case XML_NAMESPACE_DECL:
3650 case XML_XINCLUDE_START:
3651 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003652#ifdef LIBXML_DOCB_ENABLED
3653 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003654#endif
3655 break;
3656 case XML_ELEMENT_DECL:
3657 /* TODO !!! */
3658 break;
3659 case XML_ATTRIBUTE_DECL:
3660 /* TODO !!! */
3661 break;
3662 case XML_ENTITY_DECL:
3663 /* TODO !!! */
3664 break;
3665 }
3666}
3667
3668/**
3669 * xmlNodeAddContentLen:
3670 * @cur: the node being modified
3671 * @content: extra content
3672 * @len: the size of @content
3673 *
3674 * Append the extra substring to the node content.
3675 */
3676void
3677xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3678 if (cur == NULL) {
3679#ifdef DEBUG_TREE
3680 xmlGenericError(xmlGenericErrorContext,
3681 "xmlNodeAddContentLen : node == NULL\n");
3682#endif
3683 return;
3684 }
3685 if (len <= 0) return;
3686 switch (cur->type) {
3687 case XML_DOCUMENT_FRAG_NODE:
3688 case XML_ELEMENT_NODE: {
Daniel Veillard7db37732001-07-12 01:20:08 +00003689 xmlNodePtr last, newNode;
Owen Taylor3473f882001-02-23 17:55:21 +00003690
Daniel Veillard7db37732001-07-12 01:20:08 +00003691 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003692 newNode = xmlNewTextLen(content, len);
3693 if (newNode != NULL) {
3694 xmlAddChild(cur, newNode);
3695 if ((last != NULL) && (last->next == newNode)) {
3696 xmlTextMerge(last, newNode);
3697 }
3698 }
3699 break;
3700 }
3701 case XML_ATTRIBUTE_NODE:
3702 break;
3703 case XML_TEXT_NODE:
3704 case XML_CDATA_SECTION_NODE:
3705 case XML_ENTITY_REF_NODE:
3706 case XML_ENTITY_NODE:
3707 case XML_PI_NODE:
3708 case XML_COMMENT_NODE:
3709 case XML_NOTATION_NODE:
3710 if (content != NULL) {
3711#ifndef XML_USE_BUFFER_CONTENT
3712 cur->content = xmlStrncat(cur->content, content, len);
3713#else
3714 xmlBufferAdd(cur->content, content, len);
3715#endif
3716 }
3717 case XML_DOCUMENT_NODE:
3718 case XML_DTD_NODE:
3719 case XML_HTML_DOCUMENT_NODE:
3720 case XML_DOCUMENT_TYPE_NODE:
3721 case XML_NAMESPACE_DECL:
3722 case XML_XINCLUDE_START:
3723 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003724#ifdef LIBXML_DOCB_ENABLED
3725 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003726#endif
3727 break;
3728 case XML_ELEMENT_DECL:
3729 case XML_ATTRIBUTE_DECL:
3730 case XML_ENTITY_DECL:
3731 break;
3732 }
3733}
3734
3735/**
3736 * xmlNodeAddContent:
3737 * @cur: the node being modified
3738 * @content: extra content
3739 *
3740 * Append the extra substring to the node content.
3741 */
3742void
3743xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3744 int len;
3745
3746 if (cur == NULL) {
3747#ifdef DEBUG_TREE
3748 xmlGenericError(xmlGenericErrorContext,
3749 "xmlNodeAddContent : node == NULL\n");
3750#endif
3751 return;
3752 }
3753 if (content == NULL) return;
3754 len = xmlStrlen(content);
3755 xmlNodeAddContentLen(cur, content, len);
3756}
3757
3758/**
3759 * xmlTextMerge:
3760 * @first: the first text node
3761 * @second: the second text node being merged
3762 *
3763 * Merge two text nodes into one
3764 * Returns the first text node augmented
3765 */
3766xmlNodePtr
3767xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3768 if (first == NULL) return(second);
3769 if (second == NULL) return(first);
3770 if (first->type != XML_TEXT_NODE) return(first);
3771 if (second->type != XML_TEXT_NODE) return(first);
3772 if (second->name != first->name)
3773 return(first);
3774#ifndef XML_USE_BUFFER_CONTENT
3775 xmlNodeAddContent(first, second->content);
3776#else
3777 xmlNodeAddContent(first, xmlBufferContent(second->content));
3778#endif
3779 xmlUnlinkNode(second);
3780 xmlFreeNode(second);
3781 return(first);
3782}
3783
3784/**
3785 * xmlGetNsList:
3786 * @doc: the document
3787 * @node: the current node
3788 *
3789 * Search all the namespace applying to a given element.
3790 * Returns an NULL terminated array of all the xmlNsPtr found
3791 * that need to be freed by the caller or NULL if no
3792 * namespace if defined
3793 */
3794xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003795xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3796{
Owen Taylor3473f882001-02-23 17:55:21 +00003797 xmlNsPtr cur;
3798 xmlNsPtr *ret = NULL;
3799 int nbns = 0;
3800 int maxns = 10;
3801 int i;
3802
3803 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00003804 if (node->type == XML_ELEMENT_NODE) {
3805 cur = node->nsDef;
3806 while (cur != NULL) {
3807 if (ret == NULL) {
3808 ret =
3809 (xmlNsPtr *) xmlMalloc((maxns + 1) *
3810 sizeof(xmlNsPtr));
3811 if (ret == NULL) {
3812 xmlGenericError(xmlGenericErrorContext,
3813 "xmlGetNsList : out of memory!\n");
3814 return (NULL);
3815 }
3816 ret[nbns] = NULL;
3817 }
3818 for (i = 0; i < nbns; i++) {
3819 if ((cur->prefix == ret[i]->prefix) ||
3820 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
3821 break;
3822 }
3823 if (i >= nbns) {
3824 if (nbns >= maxns) {
3825 maxns *= 2;
3826 ret = (xmlNsPtr *) xmlRealloc(ret,
3827 (maxns +
3828 1) *
3829 sizeof(xmlNsPtr));
3830 if (ret == NULL) {
3831 xmlGenericError(xmlGenericErrorContext,
3832 "xmlGetNsList : realloc failed!\n");
3833 return (NULL);
3834 }
3835 }
3836 ret[nbns++] = cur;
3837 ret[nbns] = NULL;
3838 }
Owen Taylor3473f882001-02-23 17:55:21 +00003839
Daniel Veillard77044732001-06-29 21:31:07 +00003840 cur = cur->next;
3841 }
3842 }
3843 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003844 }
Daniel Veillard77044732001-06-29 21:31:07 +00003845 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003846}
3847
3848/**
3849 * xmlSearchNs:
3850 * @doc: the document
3851 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00003852 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00003853 *
3854 * Search a Ns registered under a given name space for a document.
3855 * recurse on the parents until it finds the defined namespace
3856 * or return NULL otherwise.
3857 * @nameSpace can be NULL, this is a search for the default namespace.
3858 * We don't allow to cross entities boundaries. If you don't declare
3859 * the namespace within those you will be in troubles !!! A warning
3860 * is generated to cover this case.
3861 *
3862 * Returns the namespace pointer or NULL.
3863 */
3864xmlNsPtr
3865xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
3866 xmlNsPtr cur;
3867
3868 if (node == NULL) return(NULL);
3869 if ((nameSpace != NULL) &&
3870 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
3871 if (doc->oldNs == NULL) {
3872 /*
3873 * Allocate a new Namespace and fill the fields.
3874 */
3875 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3876 if (doc->oldNs == NULL) {
3877 xmlGenericError(xmlGenericErrorContext,
3878 "xmlSearchNsByHref : malloc failed\n");
3879 return(NULL);
3880 }
3881 memset(doc->oldNs, 0, sizeof(xmlNs));
3882 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3883
3884 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3885 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3886 }
3887 return(doc->oldNs);
3888 }
3889 while (node != NULL) {
3890 if ((node->type == XML_ENTITY_REF_NODE) ||
3891 (node->type == XML_ENTITY_NODE) ||
3892 (node->type == XML_ENTITY_DECL))
3893 return(NULL);
3894 if (node->type == XML_ELEMENT_NODE) {
3895 cur = node->nsDef;
3896 while (cur != NULL) {
3897 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3898 (cur->href != NULL))
3899 return(cur);
3900 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
3901 (cur->href != NULL) &&
3902 (xmlStrEqual(cur->prefix, nameSpace)))
3903 return(cur);
3904 cur = cur->next;
3905 }
3906 }
3907 node = node->parent;
3908 }
3909 return(NULL);
3910}
3911
3912/**
3913 * xmlSearchNsByHref:
3914 * @doc: the document
3915 * @node: the current node
3916 * @href: the namespace value
3917 *
3918 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3919 * the defined namespace or return NULL otherwise.
3920 * Returns the namespace pointer or NULL.
3921 */
3922xmlNsPtr
3923xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
3924 xmlNsPtr cur;
3925 xmlNodePtr orig = node;
3926
3927 if ((node == NULL) || (href == NULL)) return(NULL);
3928 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
3929 if (doc->oldNs == NULL) {
3930 /*
3931 * Allocate a new Namespace and fill the fields.
3932 */
3933 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3934 if (doc->oldNs == NULL) {
3935 xmlGenericError(xmlGenericErrorContext,
3936 "xmlSearchNsByHref : malloc failed\n");
3937 return(NULL);
3938 }
3939 memset(doc->oldNs, 0, sizeof(xmlNs));
3940 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3941
3942 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3943 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3944 }
3945 return(doc->oldNs);
3946 }
3947 while (node != NULL) {
3948 cur = node->nsDef;
3949 while (cur != NULL) {
3950 if ((cur->href != NULL) && (href != NULL) &&
3951 (xmlStrEqual(cur->href, href))) {
3952 /*
3953 * Check that the prefix is not shadowed between orig and node
3954 */
3955 xmlNodePtr check = orig;
3956 xmlNsPtr tst;
3957
3958 while (check != node) {
3959 tst = check->nsDef;
3960 while (tst != NULL) {
3961 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3962 goto shadowed;
3963 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
3964 (xmlStrEqual(tst->prefix, cur->prefix)))
3965 goto shadowed;
3966 tst = tst->next;
3967 }
3968 check = check->parent;
3969 }
3970 return(cur);
3971 }
3972shadowed:
3973 cur = cur->next;
3974 }
3975 node = node->parent;
3976 }
3977 return(NULL);
3978}
3979
3980/**
3981 * xmlNewReconciliedNs
3982 * @doc: the document
3983 * @tree: a node expected to hold the new namespace
3984 * @ns: the original namespace
3985 *
3986 * This function tries to locate a namespace definition in a tree
3987 * ancestors, or create a new namespace definition node similar to
3988 * @ns trying to reuse the same prefix. However if the given prefix is
3989 * null (default namespace) or reused within the subtree defined by
3990 * @tree or on one of its ancestors then a new prefix is generated.
3991 * Returns the (new) namespace definition or NULL in case of error
3992 */
3993xmlNsPtr
3994xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3995 xmlNsPtr def;
3996 xmlChar prefix[50];
3997 int counter = 1;
3998
3999 if (tree == NULL) {
4000#ifdef DEBUG_TREE
4001 xmlGenericError(xmlGenericErrorContext,
4002 "xmlNewReconciliedNs : tree == NULL\n");
4003#endif
4004 return(NULL);
4005 }
4006 if (ns == NULL) {
4007#ifdef DEBUG_TREE
4008 xmlGenericError(xmlGenericErrorContext,
4009 "xmlNewReconciliedNs : ns == NULL\n");
4010#endif
4011 return(NULL);
4012 }
4013 /*
4014 * Search an existing namespace definition inherited.
4015 */
4016 def = xmlSearchNsByHref(doc, tree, ns->href);
4017 if (def != NULL)
4018 return(def);
4019
4020 /*
4021 * Find a close prefix which is not already in use.
4022 * Let's strip namespace prefixes longer than 20 chars !
4023 */
4024 sprintf((char *) prefix, "%.20s", ns->prefix);
4025 def = xmlSearchNs(doc, tree, prefix);
4026 while (def != NULL) {
4027 if (counter > 1000) return(NULL);
4028 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4029 def = xmlSearchNs(doc, tree, prefix);
4030 }
4031
4032 /*
4033 * Ok, now we are ready to create a new one.
4034 */
4035 def = xmlNewNs(tree, ns->href, prefix);
4036 return(def);
4037}
4038
4039/**
4040 * xmlReconciliateNs
4041 * @doc: the document
4042 * @tree: a node defining the subtree to reconciliate
4043 *
4044 * This function checks that all the namespaces declared within the given
4045 * tree are properly declared. This is needed for example after Copy or Cut
4046 * and then paste operations. The subtree may still hold pointers to
4047 * namespace declarations outside the subtree or invalid/masked. As much
4048 * as possible the function try tu reuse the existing namespaces found in
4049 * the new environment. If not possible the new namespaces are redeclared
4050 * on @tree at the top of the given subtree.
4051 * Returns the number of namespace declarations created or -1 in case of error.
4052 */
4053int
4054xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4055 xmlNsPtr *oldNs = NULL;
4056 xmlNsPtr *newNs = NULL;
4057 int sizeCache = 0;
4058 int nbCache = 0;
4059
4060 xmlNsPtr n;
4061 xmlNodePtr node = tree;
4062 xmlAttrPtr attr;
4063 int ret = 0, i;
4064
4065 while (node != NULL) {
4066 /*
4067 * Reconciliate the node namespace
4068 */
4069 if (node->ns != NULL) {
4070 /*
4071 * initialize the cache if needed
4072 */
4073 if (sizeCache == 0) {
4074 sizeCache = 10;
4075 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4076 sizeof(xmlNsPtr));
4077 if (oldNs == NULL) {
4078 xmlGenericError(xmlGenericErrorContext,
4079 "xmlReconciliateNs : memory pbm\n");
4080 return(-1);
4081 }
4082 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4083 sizeof(xmlNsPtr));
4084 if (newNs == NULL) {
4085 xmlGenericError(xmlGenericErrorContext,
4086 "xmlReconciliateNs : memory pbm\n");
4087 xmlFree(oldNs);
4088 return(-1);
4089 }
4090 }
4091 for (i = 0;i < nbCache;i++) {
4092 if (oldNs[i] == node->ns) {
4093 node->ns = newNs[i];
4094 break;
4095 }
4096 }
4097 if (i == nbCache) {
4098 /*
4099 * Ok we need to recreate a new namespace definition
4100 */
4101 n = xmlNewReconciliedNs(doc, tree, node->ns);
4102 if (n != NULL) { /* :-( what if else ??? */
4103 /*
4104 * check if we need to grow the cache buffers.
4105 */
4106 if (sizeCache <= nbCache) {
4107 sizeCache *= 2;
4108 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4109 sizeof(xmlNsPtr));
4110 if (oldNs == NULL) {
4111 xmlGenericError(xmlGenericErrorContext,
4112 "xmlReconciliateNs : memory pbm\n");
4113 xmlFree(newNs);
4114 return(-1);
4115 }
4116 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4117 sizeof(xmlNsPtr));
4118 if (newNs == NULL) {
4119 xmlGenericError(xmlGenericErrorContext,
4120 "xmlReconciliateNs : memory pbm\n");
4121 xmlFree(oldNs);
4122 return(-1);
4123 }
4124 }
4125 newNs[nbCache] = n;
4126 oldNs[nbCache++] = node->ns;
4127 node->ns = n;
4128 }
4129 }
4130 }
4131 /*
4132 * now check for namespace hold by attributes on the node.
4133 */
4134 attr = node->properties;
4135 while (attr != NULL) {
4136 if (attr->ns != NULL) {
4137 /*
4138 * initialize the cache if needed
4139 */
4140 if (sizeCache == 0) {
4141 sizeCache = 10;
4142 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4143 sizeof(xmlNsPtr));
4144 if (oldNs == NULL) {
4145 xmlGenericError(xmlGenericErrorContext,
4146 "xmlReconciliateNs : memory pbm\n");
4147 return(-1);
4148 }
4149 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4150 sizeof(xmlNsPtr));
4151 if (newNs == NULL) {
4152 xmlGenericError(xmlGenericErrorContext,
4153 "xmlReconciliateNs : memory pbm\n");
4154 xmlFree(oldNs);
4155 return(-1);
4156 }
4157 }
4158 for (i = 0;i < nbCache;i++) {
4159 if (oldNs[i] == attr->ns) {
4160 node->ns = newNs[i];
4161 break;
4162 }
4163 }
4164 if (i == nbCache) {
4165 /*
4166 * Ok we need to recreate a new namespace definition
4167 */
4168 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4169 if (n != NULL) { /* :-( what if else ??? */
4170 /*
4171 * check if we need to grow the cache buffers.
4172 */
4173 if (sizeCache <= nbCache) {
4174 sizeCache *= 2;
4175 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4176 sizeof(xmlNsPtr));
4177 if (oldNs == NULL) {
4178 xmlGenericError(xmlGenericErrorContext,
4179 "xmlReconciliateNs : memory pbm\n");
4180 xmlFree(newNs);
4181 return(-1);
4182 }
4183 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4184 sizeof(xmlNsPtr));
4185 if (newNs == NULL) {
4186 xmlGenericError(xmlGenericErrorContext,
4187 "xmlReconciliateNs : memory pbm\n");
4188 xmlFree(oldNs);
4189 return(-1);
4190 }
4191 }
4192 newNs[nbCache] = n;
4193 oldNs[nbCache++] = attr->ns;
4194 attr->ns = n;
4195 }
4196 }
4197 }
4198 attr = attr->next;
4199 }
4200
4201 /*
4202 * Browse the full subtree, deep first
4203 */
4204 if (node->children != NULL) {
4205 /* deep first */
4206 node = node->children;
4207 } else if ((node != tree) && (node->next != NULL)) {
4208 /* then siblings */
4209 node = node->next;
4210 } else if (node != tree) {
4211 /* go up to parents->next if needed */
4212 while (node != tree) {
4213 if (node->parent != NULL)
4214 node = node->parent;
4215 if ((node != tree) && (node->next != NULL)) {
4216 node = node->next;
4217 break;
4218 }
4219 if (node->parent == NULL) {
4220 node = NULL;
4221 break;
4222 }
4223 }
4224 /* exit condition */
4225 if (node == tree)
4226 node = NULL;
4227 }
4228 }
4229 return(ret);
4230}
4231
4232/**
4233 * xmlHasProp:
4234 * @node: the node
4235 * @name: the attribute name
4236 *
4237 * Search an attribute associated to a node
4238 * This function also looks in DTD attribute declaration for #FIXED or
4239 * default declaration values unless DTD use has been turned off.
4240 *
4241 * Returns the attribute or the attribute declaration or NULL if
4242 * neither was found.
4243 */
4244xmlAttrPtr
4245xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4246 xmlAttrPtr prop;
4247 xmlDocPtr doc;
4248
4249 if ((node == NULL) || (name == NULL)) return(NULL);
4250 /*
4251 * Check on the properties attached to the node
4252 */
4253 prop = node->properties;
4254 while (prop != NULL) {
4255 if (xmlStrEqual(prop->name, name)) {
4256 return(prop);
4257 }
4258 prop = prop->next;
4259 }
4260 if (!xmlCheckDTD) return(NULL);
4261
4262 /*
4263 * Check if there is a default declaration in the internal
4264 * or external subsets
4265 */
4266 doc = node->doc;
4267 if (doc != NULL) {
4268 xmlAttributePtr attrDecl;
4269 if (doc->intSubset != NULL) {
4270 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4271 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4272 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4273 if (attrDecl != NULL)
4274 return((xmlAttrPtr) attrDecl);
4275 }
4276 }
4277 return(NULL);
4278}
4279
4280/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004281 * xmlHasNsProp:
4282 * @node: the node
4283 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004284 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004285 *
4286 * Search for an attribute associated to a node
4287 * This attribute has to be anchored in the namespace specified.
4288 * This does the entity substitution.
4289 * This function looks in DTD attribute declaration for #FIXED or
4290 * default declaration values unless DTD use has been turned off.
4291 *
4292 * Returns the attribute or the attribute declaration or NULL
4293 * if neither was found.
4294 */
4295xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004296xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004297 xmlAttrPtr prop;
4298 xmlDocPtr doc;
4299 xmlNsPtr ns;
4300
4301 if (node == NULL)
4302 return(NULL);
4303
4304 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004305 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004306 return(xmlHasProp(node, name));
4307 while (prop != NULL) {
4308 /*
4309 * One need to have
4310 * - same attribute names
4311 * - and the attribute carrying that namespace
4312 * or
4313 * no namespace on the attribute and the element carrying it
4314 */
4315 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004316 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4317 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004318 }
4319 prop = prop->next;
4320 }
4321 if (!xmlCheckDTD) return(NULL);
4322
4323 /*
4324 * Check if there is a default declaration in the internal
4325 * or external subsets
4326 */
4327 doc = node->doc;
4328 if (doc != NULL) {
4329 if (doc->intSubset != NULL) {
4330 xmlAttributePtr attrDecl;
4331
4332 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4333 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4334 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4335
4336 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4337 /*
4338 * The DTD declaration only allows a prefix search
4339 */
4340 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004341 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004342 return((xmlAttrPtr) attrDecl);
4343 }
4344 }
4345 }
4346 return(NULL);
4347}
4348
4349/**
Owen Taylor3473f882001-02-23 17:55:21 +00004350 * xmlGetProp:
4351 * @node: the node
4352 * @name: the attribute name
4353 *
4354 * Search and get the value of an attribute associated to a node
4355 * This does the entity substitution.
4356 * This function looks in DTD attribute declaration for #FIXED or
4357 * default declaration values unless DTD use has been turned off.
4358 *
4359 * Returns the attribute value or NULL if not found.
4360 * It's up to the caller to free the memory.
4361 */
4362xmlChar *
4363xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4364 xmlAttrPtr prop;
4365 xmlDocPtr doc;
4366
4367 if ((node == NULL) || (name == NULL)) return(NULL);
4368 /*
4369 * Check on the properties attached to the node
4370 */
4371 prop = node->properties;
4372 while (prop != NULL) {
4373 if (xmlStrEqual(prop->name, name)) {
4374 xmlChar *ret;
4375
4376 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4377 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4378 return(ret);
4379 }
4380 prop = prop->next;
4381 }
4382 if (!xmlCheckDTD) return(NULL);
4383
4384 /*
4385 * Check if there is a default declaration in the internal
4386 * or external subsets
4387 */
4388 doc = node->doc;
4389 if (doc != NULL) {
4390 xmlAttributePtr attrDecl;
4391 if (doc->intSubset != NULL) {
4392 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4393 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4394 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4395 if (attrDecl != NULL)
4396 return(xmlStrdup(attrDecl->defaultValue));
4397 }
4398 }
4399 return(NULL);
4400}
4401
4402/**
4403 * xmlGetNsProp:
4404 * @node: the node
4405 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004406 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004407 *
4408 * Search and get the value of an attribute associated to a node
4409 * This attribute has to be anchored in the namespace specified.
4410 * This does the entity substitution.
4411 * This function looks in DTD attribute declaration for #FIXED or
4412 * default declaration values unless DTD use has been turned off.
4413 *
4414 * Returns the attribute value or NULL if not found.
4415 * It's up to the caller to free the memory.
4416 */
4417xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004418xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004419 xmlAttrPtr prop;
4420 xmlDocPtr doc;
4421 xmlNsPtr ns;
4422
4423 if (node == NULL)
4424 return(NULL);
4425
4426 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004427 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004428 return(xmlGetProp(node, name));
4429 while (prop != NULL) {
4430 /*
4431 * One need to have
4432 * - same attribute names
4433 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004434 */
4435 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004436 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004437 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004438 xmlChar *ret;
4439
4440 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4441 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4442 return(ret);
4443 }
4444 prop = prop->next;
4445 }
4446 if (!xmlCheckDTD) return(NULL);
4447
4448 /*
4449 * Check if there is a default declaration in the internal
4450 * or external subsets
4451 */
4452 doc = node->doc;
4453 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004454 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004455 xmlAttributePtr attrDecl;
4456
Owen Taylor3473f882001-02-23 17:55:21 +00004457 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4458 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4459 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4460
4461 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4462 /*
4463 * The DTD declaration only allows a prefix search
4464 */
4465 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004466 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004467 return(xmlStrdup(attrDecl->defaultValue));
4468 }
4469 }
4470 }
4471 return(NULL);
4472}
4473
4474/**
4475 * xmlSetProp:
4476 * @node: the node
4477 * @name: the attribute name
4478 * @value: the attribute value
4479 *
4480 * Set (or reset) an attribute carried by a node.
4481 * Returns the attribute pointer.
4482 */
4483xmlAttrPtr
4484xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
4485 xmlAttrPtr prop = node->properties;
4486 xmlDocPtr doc = NULL;
4487
4488 if ((node == NULL) || (name == NULL))
4489 return(NULL);
4490 doc = node->doc;
4491 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004492 if ((xmlStrEqual(prop->name, name)) &&
4493 (prop->ns == NULL)){
Owen Taylor3473f882001-02-23 17:55:21 +00004494 if (prop->children != NULL)
4495 xmlFreeNodeList(prop->children);
4496 prop->children = NULL;
4497 prop->last = NULL;
4498 if (value != NULL) {
4499 xmlChar *buffer;
4500 xmlNodePtr tmp;
4501
4502 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4503 prop->children = xmlStringGetNodeList(node->doc, buffer);
4504 prop->last = NULL;
4505 prop->doc = doc;
4506 tmp = prop->children;
4507 while (tmp != NULL) {
4508 tmp->parent = (xmlNodePtr) prop;
4509 tmp->doc = doc;
4510 if (tmp->next == NULL)
4511 prop->last = tmp;
4512 tmp = tmp->next;
4513 }
4514 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004515 }
Owen Taylor3473f882001-02-23 17:55:21 +00004516 return(prop);
4517 }
4518 prop = prop->next;
4519 }
4520 prop = xmlNewProp(node, name, value);
4521 return(prop);
4522}
4523
4524/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004525 * xmlUnsetProp:
4526 * @node: the node
4527 * @name: the attribute name
4528 *
4529 * Remove an attribute carried by a node.
4530 * Returns 0 if successful, -1 if not found
4531 */
4532int
4533xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4534 xmlAttrPtr prop = node->properties, prev = NULL;;
4535
4536 if ((node == NULL) || (name == NULL))
4537 return(-1);
4538 while (prop != NULL) {
4539 if ((xmlStrEqual(prop->name, name)) &&
4540 (prop->ns == NULL)) {
4541 if (prev == NULL)
4542 node->properties = prop->next;
4543 else
4544 prev->next = prop->next;
4545 xmlFreeProp(prop);
4546 return(0);
4547 }
4548 prev = prop;
4549 prop = prop->next;
4550 }
4551 return(-1);
4552}
4553
4554/**
Owen Taylor3473f882001-02-23 17:55:21 +00004555 * xmlSetNsProp:
4556 * @node: the node
4557 * @ns: the namespace definition
4558 * @name: the attribute name
4559 * @value: the attribute value
4560 *
4561 * Set (or reset) an attribute carried by a node.
4562 * The ns structure must be in scope, this is not checked.
4563 *
4564 * Returns the attribute pointer.
4565 */
4566xmlAttrPtr
4567xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4568 const xmlChar *value) {
4569 xmlAttrPtr prop;
4570
4571 if ((node == NULL) || (name == NULL))
4572 return(NULL);
4573
4574 if (ns == NULL)
4575 return(xmlSetProp(node, name, value));
4576 if (ns->href == NULL)
4577 return(NULL);
4578 prop = node->properties;
4579
4580 while (prop != NULL) {
4581 /*
4582 * One need to have
4583 * - same attribute names
4584 * - and the attribute carrying that namespace
4585 * or
4586 * no namespace on the attribute and the element carrying it
4587 */
4588 if ((xmlStrEqual(prop->name, name)) &&
4589 (((prop->ns == NULL) && (node->ns != NULL) &&
4590 (xmlStrEqual(node->ns->href, ns->href))) ||
4591 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4592 if (prop->children != NULL)
4593 xmlFreeNodeList(prop->children);
4594 prop->children = NULL;
4595 prop->last = NULL;
4596 prop->ns = ns;
4597 if (value != NULL) {
4598 xmlChar *buffer;
4599 xmlNodePtr tmp;
4600
4601 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4602 prop->children = xmlStringGetNodeList(node->doc, buffer);
4603 prop->last = NULL;
4604 tmp = prop->children;
4605 while (tmp != NULL) {
4606 tmp->parent = (xmlNodePtr) prop;
4607 if (tmp->next == NULL)
4608 prop->last = tmp;
4609 tmp = tmp->next;
4610 }
4611 xmlFree(buffer);
4612 }
4613 return(prop);
4614 }
4615 prop = prop->next;
4616 }
4617 prop = xmlNewNsProp(node, ns, name, value);
4618 return(prop);
4619}
4620
4621/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004622 * xmlUnsetNsProp:
4623 * @node: the node
4624 * @ns: the namespace definition
4625 * @name: the attribute name
4626 *
4627 * Remove an attribute carried by a node.
4628 * Returns 0 if successful, -1 if not found
4629 */
4630int
4631xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4632 xmlAttrPtr prop = node->properties, prev = NULL;;
4633
4634 if ((node == NULL) || (name == NULL))
4635 return(-1);
4636 if (ns == NULL)
4637 return(xmlUnsetProp(node, name));
4638 if (ns->href == NULL)
4639 return(-1);
4640 while (prop != NULL) {
4641 if ((xmlStrEqual(prop->name, name)) &&
4642 (((prop->ns == NULL) && (node->ns != NULL) &&
4643 (xmlStrEqual(node->ns->href, ns->href))) ||
4644 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4645 if (prev == NULL)
4646 node->properties = prop->next;
4647 else
4648 prev->next = prop->next;
4649 xmlFreeProp(prop);
4650 return(0);
4651 }
4652 prev = prop;
4653 prop = prop->next;
4654 }
4655 return(-1);
4656}
4657
4658/**
Owen Taylor3473f882001-02-23 17:55:21 +00004659 * xmlNodeIsText:
4660 * @node: the node
4661 *
4662 * Is this node a Text node ?
4663 * Returns 1 yes, 0 no
4664 */
4665int
4666xmlNodeIsText(xmlNodePtr node) {
4667 if (node == NULL) return(0);
4668
4669 if (node->type == XML_TEXT_NODE) return(1);
4670 return(0);
4671}
4672
4673/**
4674 * xmlIsBlankNode:
4675 * @node: the node
4676 *
4677 * Checks whether this node is an empty or whitespace only
4678 * (and possibly ignorable) text-node.
4679 *
4680 * Returns 1 yes, 0 no
4681 */
4682int
4683xmlIsBlankNode(xmlNodePtr node) {
4684 const xmlChar *cur;
4685 if (node == NULL) return(0);
4686
Daniel Veillard7db37732001-07-12 01:20:08 +00004687 if ((node->type != XML_TEXT_NODE) &&
4688 (node->type != XML_CDATA_SECTION_NODE))
4689 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004690 if (node->content == NULL) return(1);
4691#ifndef XML_USE_BUFFER_CONTENT
4692 cur = node->content;
4693#else
4694 cur = xmlBufferContent(node->content);
4695#endif
4696 while (*cur != 0) {
4697 if (!IS_BLANK(*cur)) return(0);
4698 cur++;
4699 }
4700
4701 return(1);
4702}
4703
4704/**
4705 * xmlTextConcat:
4706 * @node: the node
4707 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00004708 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00004709 *
4710 * Concat the given string at the end of the existing node content
4711 */
4712
4713void
4714xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4715 if (node == NULL) return;
4716
4717 if ((node->type != XML_TEXT_NODE) &&
4718 (node->type != XML_CDATA_SECTION_NODE)) {
4719#ifdef DEBUG_TREE
4720 xmlGenericError(xmlGenericErrorContext,
4721 "xmlTextConcat: node is not text nor cdata\n");
4722#endif
4723 return;
4724 }
4725#ifndef XML_USE_BUFFER_CONTENT
4726 node->content = xmlStrncat(node->content, content, len);
4727#else
4728 xmlBufferAdd(node->content, content, len);
4729#endif
4730}
4731
4732/************************************************************************
4733 * *
4734 * Output : to a FILE or in memory *
4735 * *
4736 ************************************************************************/
4737
Owen Taylor3473f882001-02-23 17:55:21 +00004738/**
4739 * xmlBufferCreate:
4740 *
4741 * routine to create an XML buffer.
4742 * returns the new structure.
4743 */
4744xmlBufferPtr
4745xmlBufferCreate(void) {
4746 xmlBufferPtr ret;
4747
4748 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4749 if (ret == NULL) {
4750 xmlGenericError(xmlGenericErrorContext,
4751 "xmlBufferCreate : out of memory!\n");
4752 return(NULL);
4753 }
4754 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004755 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004756 ret->alloc = xmlBufferAllocScheme;
4757 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4758 if (ret->content == NULL) {
4759 xmlGenericError(xmlGenericErrorContext,
4760 "xmlBufferCreate : out of memory!\n");
4761 xmlFree(ret);
4762 return(NULL);
4763 }
4764 ret->content[0] = 0;
4765 return(ret);
4766}
4767
4768/**
4769 * xmlBufferCreateSize:
4770 * @size: initial size of buffer
4771 *
4772 * routine to create an XML buffer.
4773 * returns the new structure.
4774 */
4775xmlBufferPtr
4776xmlBufferCreateSize(size_t size) {
4777 xmlBufferPtr ret;
4778
4779 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4780 if (ret == NULL) {
4781 xmlGenericError(xmlGenericErrorContext,
4782 "xmlBufferCreate : out of memory!\n");
4783 return(NULL);
4784 }
4785 ret->use = 0;
4786 ret->alloc = xmlBufferAllocScheme;
4787 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4788 if (ret->size){
4789 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4790 if (ret->content == NULL) {
4791 xmlGenericError(xmlGenericErrorContext,
4792 "xmlBufferCreate : out of memory!\n");
4793 xmlFree(ret);
4794 return(NULL);
4795 }
4796 ret->content[0] = 0;
4797 } else
4798 ret->content = NULL;
4799 return(ret);
4800}
4801
4802/**
4803 * xmlBufferSetAllocationScheme:
4804 * @buf: the buffer to free
4805 * @scheme: allocation scheme to use
4806 *
4807 * Sets the allocation scheme for this buffer
4808 */
4809void
4810xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4811 xmlBufferAllocationScheme scheme) {
4812 if (buf == NULL) {
4813#ifdef DEBUG_BUFFER
4814 xmlGenericError(xmlGenericErrorContext,
4815 "xmlBufferSetAllocationScheme: buf == NULL\n");
4816#endif
4817 return;
4818 }
4819
4820 buf->alloc = scheme;
4821}
4822
4823/**
4824 * xmlBufferFree:
4825 * @buf: the buffer to free
4826 *
4827 * Frees an XML buffer.
4828 */
4829void
4830xmlBufferFree(xmlBufferPtr buf) {
4831 if (buf == NULL) {
4832#ifdef DEBUG_BUFFER
4833 xmlGenericError(xmlGenericErrorContext,
4834 "xmlBufferFree: buf == NULL\n");
4835#endif
4836 return;
4837 }
4838 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004839 xmlFree(buf->content);
4840 }
Owen Taylor3473f882001-02-23 17:55:21 +00004841 xmlFree(buf);
4842}
4843
4844/**
4845 * xmlBufferEmpty:
4846 * @buf: the buffer
4847 *
4848 * empty a buffer.
4849 */
4850void
4851xmlBufferEmpty(xmlBufferPtr buf) {
4852 if (buf->content == NULL) return;
4853 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004854 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004855}
4856
4857/**
4858 * xmlBufferShrink:
4859 * @buf: the buffer to dump
4860 * @len: the number of xmlChar to remove
4861 *
4862 * Remove the beginning of an XML buffer.
4863 *
4864 * Returns the number of xmlChar removed, or -1 in case of failure.
4865 */
4866int
4867xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
4868 if (len == 0) return(0);
4869 if (len > buf->use) return(-1);
4870
4871 buf->use -= len;
4872 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
4873
4874 buf->content[buf->use] = 0;
4875 return(len);
4876}
4877
4878/**
4879 * xmlBufferGrow:
4880 * @buf: the buffer
4881 * @len: the minimum free size to allocate
4882 *
4883 * Grow the available space of an XML buffer.
4884 *
4885 * Returns the new available space or -1 in case of error
4886 */
4887int
4888xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
4889 int size;
4890 xmlChar *newbuf;
4891
4892 if (len + buf->use < buf->size) return(0);
4893
4894 size = buf->use + len + 100;
4895
4896 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
4897 if (newbuf == NULL) return(-1);
4898 buf->content = newbuf;
4899 buf->size = size;
4900 return(buf->size - buf->use);
4901}
4902
4903/**
4904 * xmlBufferDump:
4905 * @file: the file output
4906 * @buf: the buffer to dump
4907 *
4908 * Dumps an XML buffer to a FILE *.
4909 * Returns the number of xmlChar written
4910 */
4911int
4912xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4913 int ret;
4914
4915 if (buf == NULL) {
4916#ifdef DEBUG_BUFFER
4917 xmlGenericError(xmlGenericErrorContext,
4918 "xmlBufferDump: buf == NULL\n");
4919#endif
4920 return(0);
4921 }
4922 if (buf->content == NULL) {
4923#ifdef DEBUG_BUFFER
4924 xmlGenericError(xmlGenericErrorContext,
4925 "xmlBufferDump: buf->content == NULL\n");
4926#endif
4927 return(0);
4928 }
4929 if (file == NULL) file = stdout;
4930 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
4931 return(ret);
4932}
4933
4934/**
4935 * xmlBufferContent:
4936 * @buf: the buffer
4937 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004938 * Function to extract the content of a buffer
4939 *
Owen Taylor3473f882001-02-23 17:55:21 +00004940 * Returns the internal content
4941 */
4942
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004943const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00004944xmlBufferContent(const xmlBufferPtr buf)
4945{
4946 if(!buf)
4947 return NULL;
4948
4949 return buf->content;
4950}
4951
4952/**
4953 * xmlBufferLength:
4954 * @buf: the buffer
4955 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004956 * Function to get the length of a buffer
4957 *
Owen Taylor3473f882001-02-23 17:55:21 +00004958 * Returns the length of data in the internal content
4959 */
4960
4961int
4962xmlBufferLength(const xmlBufferPtr buf)
4963{
4964 if(!buf)
4965 return 0;
4966
4967 return buf->use;
4968}
4969
4970/**
4971 * xmlBufferResize:
4972 * @buf: the buffer to resize
4973 * @size: the desired size
4974 *
4975 * Resize a buffer to accomodate minimum size of @size.
4976 *
4977 * Returns 0 in case of problems, 1 otherwise
4978 */
4979int
4980xmlBufferResize(xmlBufferPtr buf, unsigned int size)
4981{
4982 unsigned int newSize;
4983 xmlChar* rebuf = NULL;
4984
4985 /*take care of empty case*/
4986 newSize = (buf->size ? buf->size*2 : size);
4987
4988 /* Don't resize if we don't have to */
4989 if (size < buf->size)
4990 return 1;
4991
4992 /* figure out new size */
4993 switch (buf->alloc){
4994 case XML_BUFFER_ALLOC_DOUBLEIT:
4995 while (size > newSize) newSize *= 2;
4996 break;
4997 case XML_BUFFER_ALLOC_EXACT:
4998 newSize = size+10;
4999 break;
5000 default:
5001 newSize = size+10;
5002 break;
5003 }
5004
5005 if (buf->content == NULL)
5006 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5007 else
5008 rebuf = (xmlChar *) xmlRealloc(buf->content,
5009 newSize * sizeof(xmlChar));
5010 if (rebuf == NULL) {
5011 xmlGenericError(xmlGenericErrorContext,
5012 "xmlBufferAdd : out of memory!\n");
5013 return 0;
5014 }
5015 buf->content = rebuf;
5016 buf->size = newSize;
5017
5018 return 1;
5019}
5020
5021/**
5022 * xmlBufferAdd:
5023 * @buf: the buffer to dump
5024 * @str: the xmlChar string
5025 * @len: the number of xmlChar to add
5026 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005027 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005028 * str is recomputed.
5029 */
5030void
5031xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5032 unsigned int needSize;
5033
5034 if (str == NULL) {
5035#ifdef DEBUG_BUFFER
5036 xmlGenericError(xmlGenericErrorContext,
5037 "xmlBufferAdd: str == NULL\n");
5038#endif
5039 return;
5040 }
5041 if (len < -1) {
5042#ifdef DEBUG_BUFFER
5043 xmlGenericError(xmlGenericErrorContext,
5044 "xmlBufferAdd: len < 0\n");
5045#endif
5046 return;
5047 }
5048 if (len == 0) return;
5049
5050 if (len < 0)
5051 len = xmlStrlen(str);
5052
5053 if (len <= 0) return;
5054
5055 needSize = buf->use + len + 2;
5056 if (needSize > buf->size){
5057 if (!xmlBufferResize(buf, needSize)){
5058 xmlGenericError(xmlGenericErrorContext,
5059 "xmlBufferAdd : out of memory!\n");
5060 return;
5061 }
5062 }
5063
5064 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5065 buf->use += len;
5066 buf->content[buf->use] = 0;
5067}
5068
5069/**
5070 * xmlBufferAddHead:
5071 * @buf: the buffer
5072 * @str: the xmlChar string
5073 * @len: the number of xmlChar to add
5074 *
5075 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005076 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005077 */
5078void
5079xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5080 unsigned int needSize;
5081
5082 if (str == NULL) {
5083#ifdef DEBUG_BUFFER
5084 xmlGenericError(xmlGenericErrorContext,
5085 "xmlBufferAdd: str == NULL\n");
5086#endif
5087 return;
5088 }
5089 if (len < -1) {
5090#ifdef DEBUG_BUFFER
5091 xmlGenericError(xmlGenericErrorContext,
5092 "xmlBufferAdd: len < 0\n");
5093#endif
5094 return;
5095 }
5096 if (len == 0) return;
5097
5098 if (len < 0)
5099 len = xmlStrlen(str);
5100
5101 if (len <= 0) return;
5102
5103 needSize = buf->use + len + 2;
5104 if (needSize > buf->size){
5105 if (!xmlBufferResize(buf, needSize)){
5106 xmlGenericError(xmlGenericErrorContext,
5107 "xmlBufferAddHead : out of memory!\n");
5108 return;
5109 }
5110 }
5111
5112 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5113 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5114 buf->use += len;
5115 buf->content[buf->use] = 0;
5116}
5117
5118/**
5119 * xmlBufferCat:
5120 * @buf: the buffer to dump
5121 * @str: the xmlChar string
5122 *
5123 * Append a zero terminated string to an XML buffer.
5124 */
5125void
5126xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5127 if (str != NULL)
5128 xmlBufferAdd(buf, str, -1);
5129}
5130
5131/**
5132 * xmlBufferCCat:
5133 * @buf: the buffer to dump
5134 * @str: the C char string
5135 *
5136 * Append a zero terminated C string to an XML buffer.
5137 */
5138void
5139xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5140 const char *cur;
5141
5142 if (str == NULL) {
5143#ifdef DEBUG_BUFFER
5144 xmlGenericError(xmlGenericErrorContext,
5145 "xmlBufferAdd: str == NULL\n");
5146#endif
5147 return;
5148 }
5149 for (cur = str;*cur != 0;cur++) {
5150 if (buf->use + 10 >= buf->size) {
5151 if (!xmlBufferResize(buf, buf->use+10)){
5152 xmlGenericError(xmlGenericErrorContext,
5153 "xmlBufferCCat : out of memory!\n");
5154 return;
5155 }
5156 }
5157 buf->content[buf->use++] = *cur;
5158 }
5159 buf->content[buf->use] = 0;
5160}
5161
5162/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005163 * xmlBufferWriteXmlCHAR:
5164 * @buf: the XML buffer
5165 * @string: the string to add
5166 *
5167 * For VMS only.
5168 * routine which manages and grows an output buffer. This one adds
5169 * xmlChars at the end of the buffer.
5170 */
5171/**
Owen Taylor3473f882001-02-23 17:55:21 +00005172 * xmlBufferWriteCHAR:
5173 * @buf: the XML buffer
5174 * @string: the string to add
5175 *
5176 * routine which manages and grows an output buffer. This one adds
5177 * xmlChars at the end of the buffer.
5178 */
5179void
5180#ifdef VMS
5181xmlBufferWriteXmlCHAR
5182#else
5183xmlBufferWriteCHAR
5184#endif
5185(xmlBufferPtr buf, const xmlChar *string) {
5186 xmlBufferCat(buf, string);
5187}
5188
5189/**
5190 * xmlBufferWriteChar:
5191 * @buf: the XML buffer output
5192 * @string: the string to add
5193 *
5194 * routine which manage and grows an output buffer. This one add
5195 * C chars at the end of the array.
5196 */
5197void
5198xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5199 xmlBufferCCat(buf, string);
5200}
5201
5202
5203/**
5204 * xmlBufferWriteQuotedString:
5205 * @buf: the XML buffer output
5206 * @string: the string to add
5207 *
5208 * routine which manage and grows an output buffer. This one writes
5209 * a quoted or double quoted xmlChar string, checking first if it holds
5210 * quote or double-quotes internally
5211 */
5212void
5213xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5214 if (xmlStrchr(string, '"')) {
5215 if (xmlStrchr(string, '\'')) {
5216#ifdef DEBUG_BUFFER
5217 xmlGenericError(xmlGenericErrorContext,
5218 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5219#endif
5220 }
5221 xmlBufferCCat(buf, "'");
5222 xmlBufferCat(buf, string);
5223 xmlBufferCCat(buf, "'");
5224 } else {
5225 xmlBufferCCat(buf, "\"");
5226 xmlBufferCat(buf, string);
5227 xmlBufferCCat(buf, "\"");
5228 }
5229}
5230
5231
5232/************************************************************************
5233 * *
5234 * Dumping XML tree content to a simple buffer *
5235 * *
5236 ************************************************************************/
5237
5238void
5239xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5240 int format);
5241static void
5242xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5243 int format);
5244void
5245htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5246
5247/**
5248 * xmlNsDump:
5249 * @buf: the XML buffer output
5250 * @cur: a namespace
5251 *
5252 * Dump a local Namespace definition.
5253 * Should be called in the context of attributes dumps.
5254 */
5255static void
5256xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5257 if (cur == NULL) {
5258#ifdef DEBUG_TREE
5259 xmlGenericError(xmlGenericErrorContext,
5260 "xmlNsDump : Ns == NULL\n");
5261#endif
5262 return;
5263 }
5264 if (cur->type == XML_LOCAL_NAMESPACE) {
5265 /* Within the context of an element attributes */
5266 if (cur->prefix != NULL) {
5267 xmlBufferWriteChar(buf, " xmlns:");
5268 xmlBufferWriteCHAR(buf, cur->prefix);
5269 } else
5270 xmlBufferWriteChar(buf, " xmlns");
5271 xmlBufferWriteChar(buf, "=");
5272 xmlBufferWriteQuotedString(buf, cur->href);
5273 }
5274}
5275
5276/**
5277 * xmlNsListDump:
5278 * @buf: the XML buffer output
5279 * @cur: the first namespace
5280 *
5281 * Dump a list of local Namespace definitions.
5282 * Should be called in the context of attributes dumps.
5283 */
5284static void
5285xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5286 while (cur != NULL) {
5287 xmlNsDump(buf, cur);
5288 cur = cur->next;
5289 }
5290}
5291
5292/**
5293 * xmlDtdDump:
5294 * @buf: the XML buffer output
5295 * @doc: the document
5296 *
5297 * Dump the XML document DTD, if any.
5298 */
5299static void
5300xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5301 if (dtd == NULL) {
5302#ifdef DEBUG_TREE
5303 xmlGenericError(xmlGenericErrorContext,
5304 "xmlDtdDump : no internal subset\n");
5305#endif
5306 return;
5307 }
5308 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5309 xmlBufferWriteCHAR(buf, dtd->name);
5310 if (dtd->ExternalID != NULL) {
5311 xmlBufferWriteChar(buf, " PUBLIC ");
5312 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5313 xmlBufferWriteChar(buf, " ");
5314 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5315 } else if (dtd->SystemID != NULL) {
5316 xmlBufferWriteChar(buf, " SYSTEM ");
5317 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5318 }
5319 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5320 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5321 xmlBufferWriteChar(buf, ">");
5322 return;
5323 }
5324 xmlBufferWriteChar(buf, " [\n");
5325 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5326#if 0
5327 if (dtd->entities != NULL)
5328 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5329 if (dtd->notations != NULL)
5330 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5331 if (dtd->elements != NULL)
5332 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5333 if (dtd->attributes != NULL)
5334 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5335#endif
5336 xmlBufferWriteChar(buf, "]>");
5337}
5338
5339/**
5340 * xmlAttrDump:
5341 * @buf: the XML buffer output
5342 * @doc: the document
5343 * @cur: the attribute pointer
5344 *
5345 * Dump an XML attribute
5346 */
5347static void
5348xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5349 xmlChar *value;
5350
5351 if (cur == NULL) {
5352#ifdef DEBUG_TREE
5353 xmlGenericError(xmlGenericErrorContext,
5354 "xmlAttrDump : property == NULL\n");
5355#endif
5356 return;
5357 }
5358 xmlBufferWriteChar(buf, " ");
5359 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5360 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5361 xmlBufferWriteChar(buf, ":");
5362 }
5363 xmlBufferWriteCHAR(buf, cur->name);
5364 value = xmlNodeListGetString(doc, cur->children, 0);
5365 if (value != NULL) {
5366 xmlBufferWriteChar(buf, "=");
5367 xmlBufferWriteQuotedString(buf, value);
5368 xmlFree(value);
5369 } else {
5370 xmlBufferWriteChar(buf, "=\"\"");
5371 }
5372}
5373
5374/**
5375 * xmlAttrListDump:
5376 * @buf: the XML buffer output
5377 * @doc: the document
5378 * @cur: the first attribute pointer
5379 *
5380 * Dump a list of XML attributes
5381 */
5382static void
5383xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5384 if (cur == NULL) {
5385#ifdef DEBUG_TREE
5386 xmlGenericError(xmlGenericErrorContext,
5387 "xmlAttrListDump : property == NULL\n");
5388#endif
5389 return;
5390 }
5391 while (cur != NULL) {
5392 xmlAttrDump(buf, doc, cur);
5393 cur = cur->next;
5394 }
5395}
5396
5397
5398
5399/**
5400 * xmlNodeListDump:
5401 * @buf: the XML buffer output
5402 * @doc: the document
5403 * @cur: the first node
5404 * @level: the imbrication level for indenting
5405 * @format: is formatting allowed
5406 *
5407 * Dump an XML node list, recursive behaviour,children are printed too.
5408 */
5409static void
5410xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5411 int format) {
5412 int i;
5413
5414 if (cur == NULL) {
5415#ifdef DEBUG_TREE
5416 xmlGenericError(xmlGenericErrorContext,
5417 "xmlNodeListDump : node == NULL\n");
5418#endif
5419 return;
5420 }
5421 while (cur != NULL) {
5422 if ((format) && (xmlIndentTreeOutput) &&
5423 (cur->type == XML_ELEMENT_NODE))
5424 for (i = 0;i < level;i++)
5425 xmlBufferWriteChar(buf, " ");
5426 xmlNodeDump(buf, doc, cur, level, format);
5427 if (format) {
5428 xmlBufferWriteChar(buf, "\n");
5429 }
5430 cur = cur->next;
5431 }
5432}
5433
5434/**
5435 * xmlNodeDump:
5436 * @buf: the XML buffer output
5437 * @doc: the document
5438 * @cur: the current node
5439 * @level: the imbrication level for indenting
5440 * @format: is formatting allowed
5441 *
5442 * Dump an XML node, recursive behaviour,children are printed too.
5443 */
5444void
5445xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5446 int format) {
5447 int i;
5448 xmlNodePtr tmp;
5449
5450 if (cur == NULL) {
5451#ifdef DEBUG_TREE
5452 xmlGenericError(xmlGenericErrorContext,
5453 "xmlNodeDump : node == NULL\n");
5454#endif
5455 return;
5456 }
5457 if (cur->type == XML_XINCLUDE_START)
5458 return;
5459 if (cur->type == XML_XINCLUDE_END)
5460 return;
5461 if (cur->type == XML_DTD_NODE) {
5462 xmlDtdDump(buf, (xmlDtdPtr) cur);
5463 return;
5464 }
5465 if (cur->type == XML_ELEMENT_DECL) {
5466 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5467 return;
5468 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005469 if (cur->type == XML_ATTRIBUTE_NODE){
5470 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5471 return;
5472 }
Owen Taylor3473f882001-02-23 17:55:21 +00005473 if (cur->type == XML_ATTRIBUTE_DECL) {
5474 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5475 return;
5476 }
5477 if (cur->type == XML_ENTITY_DECL) {
5478 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5479 return;
5480 }
5481 if (cur->type == XML_TEXT_NODE) {
5482 if (cur->content != NULL) {
5483 if ((cur->name == xmlStringText) ||
5484 (cur->name != xmlStringTextNoenc)) {
5485 xmlChar *buffer;
5486
5487#ifndef XML_USE_BUFFER_CONTENT
5488 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5489#else
5490 buffer = xmlEncodeEntitiesReentrant(doc,
5491 xmlBufferContent(cur->content));
5492#endif
5493 if (buffer != NULL) {
5494 xmlBufferWriteCHAR(buf, buffer);
5495 xmlFree(buffer);
5496 }
5497 } else {
5498 /*
5499 * Disable escaping, needed for XSLT
5500 */
5501#ifndef XML_USE_BUFFER_CONTENT
5502 xmlBufferWriteCHAR(buf, cur->content);
5503#else
5504 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5505#endif
5506 }
5507 }
5508 return;
5509 }
5510 if (cur->type == XML_PI_NODE) {
5511 if (cur->content != NULL) {
5512 xmlBufferWriteChar(buf, "<?");
5513 xmlBufferWriteCHAR(buf, cur->name);
5514 if (cur->content != NULL) {
5515 xmlBufferWriteChar(buf, " ");
5516#ifndef XML_USE_BUFFER_CONTENT
5517 xmlBufferWriteCHAR(buf, cur->content);
5518#else
5519 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5520#endif
5521 }
5522 xmlBufferWriteChar(buf, "?>");
5523 } else {
5524 xmlBufferWriteChar(buf, "<?");
5525 xmlBufferWriteCHAR(buf, cur->name);
5526 xmlBufferWriteChar(buf, "?>");
5527 }
5528 return;
5529 }
5530 if (cur->type == XML_COMMENT_NODE) {
5531 if (cur->content != NULL) {
5532 xmlBufferWriteChar(buf, "<!--");
5533#ifndef XML_USE_BUFFER_CONTENT
5534 xmlBufferWriteCHAR(buf, cur->content);
5535#else
5536 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5537#endif
5538 xmlBufferWriteChar(buf, "-->");
5539 }
5540 return;
5541 }
5542 if (cur->type == XML_ENTITY_REF_NODE) {
5543 xmlBufferWriteChar(buf, "&");
5544 xmlBufferWriteCHAR(buf, cur->name);
5545 xmlBufferWriteChar(buf, ";");
5546 return;
5547 }
5548 if (cur->type == XML_CDATA_SECTION_NODE) {
5549 xmlBufferWriteChar(buf, "<![CDATA[");
5550 if (cur->content != NULL)
5551#ifndef XML_USE_BUFFER_CONTENT
5552 xmlBufferWriteCHAR(buf, cur->content);
5553#else
5554 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5555#endif
5556 xmlBufferWriteChar(buf, "]]>");
5557 return;
5558 }
5559
5560 if (format == 1) {
5561 tmp = cur->children;
5562 while (tmp != NULL) {
5563 if ((tmp->type == XML_TEXT_NODE) ||
5564 (tmp->type == XML_ENTITY_REF_NODE)) {
5565 format = 0;
5566 break;
5567 }
5568 tmp = tmp->next;
5569 }
5570 }
5571 xmlBufferWriteChar(buf, "<");
5572 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5573 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5574 xmlBufferWriteChar(buf, ":");
5575 }
5576
5577 xmlBufferWriteCHAR(buf, cur->name);
5578 if (cur->nsDef)
5579 xmlNsListDump(buf, cur->nsDef);
5580 if (cur->properties != NULL)
5581 xmlAttrListDump(buf, doc, cur->properties);
5582
Daniel Veillard7db37732001-07-12 01:20:08 +00005583 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5584 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005585 (!xmlSaveNoEmptyTags)) {
5586 xmlBufferWriteChar(buf, "/>");
5587 return;
5588 }
5589 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005590 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005591 xmlChar *buffer;
5592
5593#ifndef XML_USE_BUFFER_CONTENT
5594 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5595#else
5596 buffer = xmlEncodeEntitiesReentrant(doc,
5597 xmlBufferContent(cur->content));
5598#endif
5599 if (buffer != NULL) {
5600 xmlBufferWriteCHAR(buf, buffer);
5601 xmlFree(buffer);
5602 }
5603 }
5604 if (cur->children != NULL) {
5605 if (format) xmlBufferWriteChar(buf, "\n");
5606 xmlNodeListDump(buf, doc, cur->children,
5607 (level >= 0?level+1:-1), format);
5608 if ((xmlIndentTreeOutput) && (format))
5609 for (i = 0;i < level;i++)
5610 xmlBufferWriteChar(buf, " ");
5611 }
5612 xmlBufferWriteChar(buf, "</");
5613 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5614 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5615 xmlBufferWriteChar(buf, ":");
5616 }
5617
5618 xmlBufferWriteCHAR(buf, cur->name);
5619 xmlBufferWriteChar(buf, ">");
5620}
5621
5622/**
5623 * xmlElemDump:
5624 * @f: the FILE * for the output
5625 * @doc: the document
5626 * @cur: the current node
5627 *
5628 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5629 */
5630void
5631xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5632 xmlBufferPtr buf;
5633
5634 if (cur == NULL) {
5635#ifdef DEBUG_TREE
5636 xmlGenericError(xmlGenericErrorContext,
5637 "xmlElemDump : cur == NULL\n");
5638#endif
5639 return;
5640 }
Owen Taylor3473f882001-02-23 17:55:21 +00005641#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005642 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005643 xmlGenericError(xmlGenericErrorContext,
5644 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005645 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005646#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005647
Owen Taylor3473f882001-02-23 17:55:21 +00005648 buf = xmlBufferCreate();
5649 if (buf == NULL) return;
5650 if ((doc != NULL) &&
5651 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5652#ifdef LIBXML_HTML_ENABLED
5653 htmlNodeDump(buf, doc, cur);
5654#else
5655 xmlGenericError(xmlGenericErrorContext,
5656 "HTML support not compiled in\n");
5657#endif /* LIBXML_HTML_ENABLED */
5658 } else
5659 xmlNodeDump(buf, doc, cur, 0, 1);
5660 xmlBufferDump(f, buf);
5661 xmlBufferFree(buf);
5662}
5663
5664/************************************************************************
5665 * *
5666 * Dumping XML tree content to an I/O output buffer *
5667 * *
5668 ************************************************************************/
5669
5670void
5671xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5672 int level, int format, const char *encoding);
5673static void
5674xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5675 int level, int format, const char *encoding);
5676/**
5677 * xmlNsDumpOutput:
5678 * @buf: the XML buffer output
5679 * @cur: a namespace
5680 *
5681 * Dump a local Namespace definition.
5682 * Should be called in the context of attributes dumps.
5683 */
5684static void
5685xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5686 if (cur == NULL) {
5687#ifdef DEBUG_TREE
5688 xmlGenericError(xmlGenericErrorContext,
5689 "xmlNsDump : Ns == NULL\n");
5690#endif
5691 return;
5692 }
5693 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5694 /* Within the context of an element attributes */
5695 if (cur->prefix != NULL) {
5696 xmlOutputBufferWriteString(buf, " xmlns:");
5697 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5698 } else
5699 xmlOutputBufferWriteString(buf, " xmlns");
5700 xmlOutputBufferWriteString(buf, "=");
5701 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5702 }
5703}
5704
5705/**
5706 * xmlNsListDumpOutput:
5707 * @buf: the XML buffer output
5708 * @cur: the first namespace
5709 *
5710 * Dump a list of local Namespace definitions.
5711 * Should be called in the context of attributes dumps.
5712 */
5713static void
5714xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5715 while (cur != NULL) {
5716 xmlNsDumpOutput(buf, cur);
5717 cur = cur->next;
5718 }
5719}
5720
5721/**
5722 * xmlDtdDumpOutput:
5723 * @buf: the XML buffer output
5724 * @doc: the document
5725 * @encoding: an optional encoding string
5726 *
5727 * Dump the XML document DTD, if any.
5728 */
5729static void
5730xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5731 if (dtd == NULL) {
5732#ifdef DEBUG_TREE
5733 xmlGenericError(xmlGenericErrorContext,
5734 "xmlDtdDump : no internal subset\n");
5735#endif
5736 return;
5737 }
5738 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5739 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5740 if (dtd->ExternalID != NULL) {
5741 xmlOutputBufferWriteString(buf, " PUBLIC ");
5742 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5743 xmlOutputBufferWriteString(buf, " ");
5744 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5745 } else if (dtd->SystemID != NULL) {
5746 xmlOutputBufferWriteString(buf, " SYSTEM ");
5747 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5748 }
5749 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5750 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5751 xmlOutputBufferWriteString(buf, ">");
5752 return;
5753 }
5754 xmlOutputBufferWriteString(buf, " [\n");
5755 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5756 xmlOutputBufferWriteString(buf, "]>");
5757}
5758
5759/**
5760 * xmlAttrDumpOutput:
5761 * @buf: the XML buffer output
5762 * @doc: the document
5763 * @cur: the attribute pointer
5764 * @encoding: an optional encoding string
5765 *
5766 * Dump an XML attribute
5767 */
5768static void
5769xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005770 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005771 xmlChar *value;
5772
5773 if (cur == NULL) {
5774#ifdef DEBUG_TREE
5775 xmlGenericError(xmlGenericErrorContext,
5776 "xmlAttrDump : property == NULL\n");
5777#endif
5778 return;
5779 }
5780 xmlOutputBufferWriteString(buf, " ");
5781 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5782 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5783 xmlOutputBufferWriteString(buf, ":");
5784 }
5785 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5786 value = xmlNodeListGetString(doc, cur->children, 0);
5787 if (value) {
5788 xmlOutputBufferWriteString(buf, "=");
5789 xmlBufferWriteQuotedString(buf->buffer, value);
5790 xmlFree(value);
5791 } else {
5792 xmlOutputBufferWriteString(buf, "=\"\"");
5793 }
5794}
5795
5796/**
5797 * xmlAttrListDumpOutput:
5798 * @buf: the XML buffer output
5799 * @doc: the document
5800 * @cur: the first attribute pointer
5801 * @encoding: an optional encoding string
5802 *
5803 * Dump a list of XML attributes
5804 */
5805static void
5806xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5807 xmlAttrPtr cur, const char *encoding) {
5808 if (cur == NULL) {
5809#ifdef DEBUG_TREE
5810 xmlGenericError(xmlGenericErrorContext,
5811 "xmlAttrListDump : property == NULL\n");
5812#endif
5813 return;
5814 }
5815 while (cur != NULL) {
5816 xmlAttrDumpOutput(buf, doc, cur, encoding);
5817 cur = cur->next;
5818 }
5819}
5820
5821
5822
5823/**
5824 * xmlNodeListDumpOutput:
5825 * @buf: the XML buffer output
5826 * @doc: the document
5827 * @cur: the first node
5828 * @level: the imbrication level for indenting
5829 * @format: is formatting allowed
5830 * @encoding: an optional encoding string
5831 *
5832 * Dump an XML node list, recursive behaviour,children are printed too.
5833 */
5834static void
5835xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5836 xmlNodePtr cur, int level, int format, const char *encoding) {
5837 int i;
5838
5839 if (cur == NULL) {
5840#ifdef DEBUG_TREE
5841 xmlGenericError(xmlGenericErrorContext,
5842 "xmlNodeListDump : node == NULL\n");
5843#endif
5844 return;
5845 }
5846 while (cur != NULL) {
5847 if ((format) && (xmlIndentTreeOutput) &&
5848 (cur->type == XML_ELEMENT_NODE))
5849 for (i = 0;i < level;i++)
5850 xmlOutputBufferWriteString(buf, " ");
5851 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5852 if (format) {
5853 xmlOutputBufferWriteString(buf, "\n");
5854 }
5855 cur = cur->next;
5856 }
5857}
5858
5859/**
5860 * xmlNodeDumpOutput:
5861 * @buf: the XML buffer output
5862 * @doc: the document
5863 * @cur: the current node
5864 * @level: the imbrication level for indenting
5865 * @format: is formatting allowed
5866 * @encoding: an optional encoding string
5867 *
5868 * Dump an XML node, recursive behaviour,children are printed too.
5869 */
5870void
5871xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5872 int level, int format, const char *encoding) {
5873 int i;
5874 xmlNodePtr tmp;
5875
5876 if (cur == NULL) {
5877#ifdef DEBUG_TREE
5878 xmlGenericError(xmlGenericErrorContext,
5879 "xmlNodeDump : node == NULL\n");
5880#endif
5881 return;
5882 }
5883 if (cur->type == XML_XINCLUDE_START)
5884 return;
5885 if (cur->type == XML_XINCLUDE_END)
5886 return;
5887 if (cur->type == XML_DTD_NODE) {
5888 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5889 return;
5890 }
5891 if (cur->type == XML_ELEMENT_DECL) {
5892 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5893 return;
5894 }
5895 if (cur->type == XML_ATTRIBUTE_DECL) {
5896 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5897 return;
5898 }
5899 if (cur->type == XML_ENTITY_DECL) {
5900 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5901 return;
5902 }
5903 if (cur->type == XML_TEXT_NODE) {
5904 if (cur->content != NULL) {
5905 if ((cur->name == xmlStringText) ||
5906 (cur->name != xmlStringTextNoenc)) {
5907 xmlChar *buffer;
5908
5909#ifndef XML_USE_BUFFER_CONTENT
5910 if (encoding == NULL)
5911 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5912 else
5913 buffer = xmlEncodeSpecialChars(doc, cur->content);
5914#else
5915 if (encoding == NULL)
5916 buffer = xmlEncodeEntitiesReentrant(doc,
5917 xmlBufferContent(cur->content));
5918 else
5919 buffer = xmlEncodeSpecialChars(doc,
5920 xmlBufferContent(cur->content));
5921#endif
5922 if (buffer != NULL) {
5923 xmlOutputBufferWriteString(buf, (const char *)buffer);
5924 xmlFree(buffer);
5925 }
5926 } else {
5927 /*
5928 * Disable escaping, needed for XSLT
5929 */
5930#ifndef XML_USE_BUFFER_CONTENT
5931 xmlOutputBufferWriteString(buf, (const char *) cur->content);
5932#else
5933 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5934#endif
5935 }
5936 }
5937
5938 return;
5939 }
5940 if (cur->type == XML_PI_NODE) {
5941 if (cur->content != NULL) {
5942 xmlOutputBufferWriteString(buf, "<?");
5943 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5944 if (cur->content != NULL) {
5945 xmlOutputBufferWriteString(buf, " ");
5946#ifndef XML_USE_BUFFER_CONTENT
5947 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5948#else
5949 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5950#endif
5951 }
5952 xmlOutputBufferWriteString(buf, "?>");
5953 } else {
5954 xmlOutputBufferWriteString(buf, "<?");
5955 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5956 xmlOutputBufferWriteString(buf, "?>");
5957 }
5958 return;
5959 }
5960 if (cur->type == XML_COMMENT_NODE) {
5961 if (cur->content != NULL) {
5962 xmlOutputBufferWriteString(buf, "<!--");
5963#ifndef XML_USE_BUFFER_CONTENT
5964 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5965#else
5966 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5967#endif
5968 xmlOutputBufferWriteString(buf, "-->");
5969 }
5970 return;
5971 }
5972 if (cur->type == XML_ENTITY_REF_NODE) {
5973 xmlOutputBufferWriteString(buf, "&");
5974 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5975 xmlOutputBufferWriteString(buf, ";");
5976 return;
5977 }
5978 if (cur->type == XML_CDATA_SECTION_NODE) {
5979 xmlOutputBufferWriteString(buf, "<![CDATA[");
5980 if (cur->content != NULL)
5981#ifndef XML_USE_BUFFER_CONTENT
5982 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5983#else
5984 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5985#endif
5986 xmlOutputBufferWriteString(buf, "]]>");
5987 return;
5988 }
5989
5990 if (format == 1) {
5991 tmp = cur->children;
5992 while (tmp != NULL) {
5993 if ((tmp->type == XML_TEXT_NODE) ||
5994 (tmp->type == XML_ENTITY_REF_NODE)) {
5995 format = 0;
5996 break;
5997 }
5998 tmp = tmp->next;
5999 }
6000 }
6001 xmlOutputBufferWriteString(buf, "<");
6002 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6003 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6004 xmlOutputBufferWriteString(buf, ":");
6005 }
6006
6007 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6008 if (cur->nsDef)
6009 xmlNsListDumpOutput(buf, cur->nsDef);
6010 if (cur->properties != NULL)
6011 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6012
Daniel Veillard7db37732001-07-12 01:20:08 +00006013 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6014 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006015 xmlOutputBufferWriteString(buf, "/>");
6016 return;
6017 }
6018 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006019 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006020 xmlChar *buffer;
6021
6022#ifndef XML_USE_BUFFER_CONTENT
6023 if (encoding == NULL)
6024 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6025 else
6026 buffer = xmlEncodeSpecialChars(doc, cur->content);
6027#else
6028 if (encoding == NULL)
6029 buffer = xmlEncodeEntitiesReentrant(doc,
6030 xmlBufferContent(cur->content));
6031 else
6032 buffer = xmlEncodeSpecialChars(doc,
6033 xmlBufferContent(cur->content));
6034#endif
6035 if (buffer != NULL) {
6036 xmlOutputBufferWriteString(buf, (const char *)buffer);
6037 xmlFree(buffer);
6038 }
6039 }
6040 if (cur->children != NULL) {
6041 if (format) xmlOutputBufferWriteString(buf, "\n");
6042 xmlNodeListDumpOutput(buf, doc, cur->children,
6043 (level >= 0?level+1:-1), format, encoding);
6044 if ((xmlIndentTreeOutput) && (format))
6045 for (i = 0;i < level;i++)
6046 xmlOutputBufferWriteString(buf, " ");
6047 }
6048 xmlOutputBufferWriteString(buf, "</");
6049 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6050 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6051 xmlOutputBufferWriteString(buf, ":");
6052 }
6053
6054 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6055 xmlOutputBufferWriteString(buf, ">");
6056}
6057
6058/**
6059 * xmlDocContentDumpOutput:
6060 * @buf: the XML buffer output
6061 * @cur: the document
6062 * @encoding: an optional encoding string
6063 * @format: should formatting spaces been added
6064 *
6065 * Dump an XML document.
6066 */
6067static void
6068xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6069 const char *encoding, int format) {
6070 xmlOutputBufferWriteString(buf, "<?xml version=");
6071 if (cur->version != NULL)
6072 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6073 else
6074 xmlOutputBufferWriteString(buf, "\"1.0\"");
6075 if (encoding == NULL) {
6076 if (cur->encoding != NULL)
6077 encoding = (const char *) cur->encoding;
6078 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6079 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6080 }
6081 if (encoding != NULL) {
6082 xmlOutputBufferWriteString(buf, " encoding=");
6083 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6084 }
6085 switch (cur->standalone) {
6086 case 0:
6087 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6088 break;
6089 case 1:
6090 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6091 break;
6092 }
6093 xmlOutputBufferWriteString(buf, "?>\n");
6094 if (cur->children != NULL) {
6095 xmlNodePtr child = cur->children;
6096
6097 while (child != NULL) {
6098 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6099 xmlOutputBufferWriteString(buf, "\n");
6100 child = child->next;
6101 }
6102 }
6103}
6104
6105/************************************************************************
6106 * *
6107 * Saving functions front-ends *
6108 * *
6109 ************************************************************************/
6110
6111/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006112 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006113 * @out_doc: Document to generate XML text from
6114 * @doc_txt_ptr: Memory pointer for allocated XML text
6115 * @doc_txt_len: Length of the generated XML text
6116 * @txt_encoding: Character encoding to use when generating XML text
6117 * @format: should formatting spaces been added
6118 *
6119 * Dump the current DOM tree into memory using the character encoding specified
6120 * by the caller. Note it is up to the caller of this function to free the
6121 * allocated memory.
6122 */
6123
6124void
6125xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006126 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006127 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006128 int dummy = 0;
6129
6130 xmlCharEncoding doc_charset;
6131 xmlOutputBufferPtr out_buff = NULL;
6132 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6133
6134 if (doc_txt_len == NULL) {
6135 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6136 }
6137
6138 if (doc_txt_ptr == NULL) {
6139 *doc_txt_len = 0;
6140 xmlGenericError(xmlGenericErrorContext,
6141 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6142 return;
6143 }
6144
6145 *doc_txt_ptr = NULL;
6146 *doc_txt_len = 0;
6147
6148 if (out_doc == NULL) {
6149 /* No document, no output */
6150 xmlGenericError(xmlGenericErrorContext,
6151 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6152 return;
6153 }
6154
6155 /*
6156 * Validate the encoding value, if provided.
6157 * This logic is copied from xmlSaveFileEnc.
6158 */
6159
6160 if (txt_encoding == NULL)
6161 txt_encoding = (const char *) out_doc->encoding;
6162 if (txt_encoding != NULL) {
6163 doc_charset = xmlParseCharEncoding(txt_encoding);
6164
6165 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6166 xmlGenericError(xmlGenericErrorContext,
6167 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6168 return;
6169
6170 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6171 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6172 if ( conv_hdlr == NULL ) {
6173 xmlGenericError(xmlGenericErrorContext,
6174 "%s: %s %s '%s'\n",
6175 "xmlDocDumpFormatMemoryEnc",
6176 "Failed to identify encoding handler for",
6177 "character set",
6178 txt_encoding);
6179 return;
6180 }
6181 }
6182 }
6183
6184 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6185 xmlGenericError(xmlGenericErrorContext,
6186 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6187 return;
6188 }
6189
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006190 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006191 xmlOutputBufferFlush(out_buff);
6192 if (out_buff->conv != NULL) {
6193 *doc_txt_len = out_buff->conv->use;
6194 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6195 } else {
6196 *doc_txt_len = out_buff->buffer->use;
6197 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6198 }
6199 (void)xmlOutputBufferClose(out_buff);
6200
6201 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6202 *doc_txt_len = 0;
6203 xmlGenericError(xmlGenericErrorContext,
6204 "xmlDocDumpFormatMemoryEnc: %s\n",
6205 "Failed to allocate memory for document text representation.");
6206 }
6207
6208 return;
6209}
6210
6211/**
6212 * xmlDocDumpMemory:
6213 * @cur: the document
6214 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006215 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006216 *
6217 * Dump an XML document in memory and return the xmlChar * and it's size.
6218 * It's up to the caller to free the memory.
6219 */
6220void
6221xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6222 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6223}
6224
6225/**
6226 * xmlDocDumpFormatMemory:
6227 * @cur: the document
6228 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006229 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006230 * @format: should formatting spaces been added
6231 *
6232 *
6233 * Dump an XML document in memory and return the xmlChar * and it's size.
6234 * It's up to the caller to free the memory.
6235 */
6236void
6237xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6238 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6239}
6240
6241/**
6242 * xmlDocDumpMemoryEnc:
6243 * @out_doc: Document to generate XML text from
6244 * @doc_txt_ptr: Memory pointer for allocated XML text
6245 * @doc_txt_len: Length of the generated XML text
6246 * @txt_encoding: Character encoding to use when generating XML text
6247 *
6248 * Dump the current DOM tree into memory using the character encoding specified
6249 * by the caller. Note it is up to the caller of this function to free the
6250 * allocated memory.
6251 */
6252
6253void
6254xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6255 int * doc_txt_len, const char * txt_encoding) {
6256 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006257 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006258}
6259
6260/**
6261 * xmlGetDocCompressMode:
6262 * @doc: the document
6263 *
6264 * get the compression ratio for a document, ZLIB based
6265 * Returns 0 (uncompressed) to 9 (max compression)
6266 */
6267int
6268xmlGetDocCompressMode (xmlDocPtr doc) {
6269 if (doc == NULL) return(-1);
6270 return(doc->compression);
6271}
6272
6273/**
6274 * xmlSetDocCompressMode:
6275 * @doc: the document
6276 * @mode: the compression ratio
6277 *
6278 * set the compression ratio for a document, ZLIB based
6279 * Correct values: 0 (uncompressed) to 9 (max compression)
6280 */
6281void
6282xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6283 if (doc == NULL) return;
6284 if (mode < 0) doc->compression = 0;
6285 else if (mode > 9) doc->compression = 9;
6286 else doc->compression = mode;
6287}
6288
6289/**
6290 * xmlGetCompressMode:
6291 *
6292 * get the default compression mode used, ZLIB based.
6293 * Returns 0 (uncompressed) to 9 (max compression)
6294 */
6295int
6296 xmlGetCompressMode(void) {
6297 return(xmlCompressMode);
6298}
6299
6300/**
6301 * xmlSetCompressMode:
6302 * @mode: the compression ratio
6303 *
6304 * set the default compression mode used, ZLIB based
6305 * Correct values: 0 (uncompressed) to 9 (max compression)
6306 */
6307void
6308xmlSetCompressMode(int mode) {
6309 if (mode < 0) xmlCompressMode = 0;
6310 else if (mode > 9) xmlCompressMode = 9;
6311 else xmlCompressMode = mode;
6312}
6313
6314/**
6315 * xmlDocDump:
6316 * @f: the FILE*
6317 * @cur: the document
6318 *
6319 * Dump an XML document to an open FILE.
6320 *
6321 * returns: the number of byte written or -1 in case of failure.
6322 */
6323int
6324xmlDocDump(FILE *f, xmlDocPtr cur) {
6325 xmlOutputBufferPtr buf;
6326 const char * encoding;
6327 xmlCharEncodingHandlerPtr handler = NULL;
6328 int ret;
6329
6330 if (cur == NULL) {
6331#ifdef DEBUG_TREE
6332 xmlGenericError(xmlGenericErrorContext,
6333 "xmlDocDump : document == NULL\n");
6334#endif
6335 return(-1);
6336 }
6337 encoding = (const char *) cur->encoding;
6338
6339 if (encoding != NULL) {
6340 xmlCharEncoding enc;
6341
6342 enc = xmlParseCharEncoding(encoding);
6343
6344 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6345 xmlGenericError(xmlGenericErrorContext,
6346 "xmlDocDump: document not in UTF8\n");
6347 return(-1);
6348 }
6349 if (enc != XML_CHAR_ENCODING_UTF8) {
6350 handler = xmlFindCharEncodingHandler(encoding);
6351 if (handler == NULL) {
6352 xmlFree((char *) cur->encoding);
6353 cur->encoding = NULL;
6354 }
6355 }
6356 }
6357 buf = xmlOutputBufferCreateFile(f, handler);
6358 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006359 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006360
6361 ret = xmlOutputBufferClose(buf);
6362 return(ret);
6363}
6364
6365/**
6366 * xmlSaveFileTo:
6367 * @buf: an output I/O buffer
6368 * @cur: the document
6369 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6370 *
6371 * Dump an XML document to an I/O buffer.
6372 *
6373 * returns: the number of byte written or -1 in case of failure.
6374 */
6375int
6376xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
6377 int ret;
6378
6379 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006380 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006381 ret = xmlOutputBufferClose(buf);
6382 return(ret);
6383}
6384
6385/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006386 * xmlSaveFormatFileTo:
6387 * @buf: an output I/O buffer
6388 * @cur: the document
6389 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6390 * @format: should formatting spaces been added
6391 *
6392 * Dump an XML document to an I/O buffer.
6393 *
6394 * returns: the number of byte written or -1 in case of failure.
6395 */
6396int
6397xmlSaveFormatFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding, int format) {
6398 int ret;
6399
6400 if (buf == NULL) return(0);
6401 xmlDocContentDumpOutput(buf, cur, encoding, format);
6402 ret = xmlOutputBufferClose(buf);
6403 return(ret);
6404}
6405
6406/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006407 * xmlSaveFormatFileEnc
6408 * @filename: the filename or URL to output
6409 * @cur: the document being saved
6410 * @encoding: the name of the encoding to use or NULL.
6411 * @format: should formatting spaces be added.
Owen Taylor3473f882001-02-23 17:55:21 +00006412 */
6413int
Daniel Veillardf012a642001-07-23 19:10:52 +00006414xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6415 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006416 xmlOutputBufferPtr buf;
6417 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006418 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006419 int ret;
6420
6421 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006422
6423 enc = xmlParseCharEncoding(encoding);
6424 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6425 xmlGenericError(xmlGenericErrorContext,
6426 "xmlSaveFileEnc: document not in UTF8\n");
6427 return(-1);
6428 }
6429 if (enc != XML_CHAR_ENCODING_UTF8) {
6430 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006431 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006432 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006433 }
6434 }
6435
Daniel Veillardf012a642001-07-23 19:10:52 +00006436#ifdef HAVE_ZLIB_H
6437 if (cur->compression < 0) cur->compression = xmlCompressMode;
6438#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006439 /*
6440 * save the content to a temp buffer.
6441 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006442 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006443 if (buf == NULL) return(-1);
6444
Daniel Veillardf012a642001-07-23 19:10:52 +00006445 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006446
6447 ret = xmlOutputBufferClose(buf);
6448 return(ret);
6449}
6450
Daniel Veillardf012a642001-07-23 19:10:52 +00006451
6452/**
6453 * xmlSaveFileEnc:
6454 * @filename: the filename (or URL)
6455 * @cur: the document
6456 * @encoding: the name of an encoding (or NULL)
6457 *
6458 * Dump an XML document, converting it to the given encoding
6459 *
6460 * returns: the number of byte written or -1 in case of failure.
6461 */
6462int
6463xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6464 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6465}
6466
Owen Taylor3473f882001-02-23 17:55:21 +00006467/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006468 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006469 * @filename: the filename (or URL)
6470 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006471 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006472 *
6473 * Dump an XML document to a file. Will use compression if
6474 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillard67fee942001-04-26 18:59:03 +00006475 * used. If format is set then the document will be indented on output.
6476 *
Owen Taylor3473f882001-02-23 17:55:21 +00006477 * returns: the number of byte written or -1 in case of failure.
6478 */
6479int
Daniel Veillard67fee942001-04-26 18:59:03 +00006480xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006481 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006482}
6483
Daniel Veillard67fee942001-04-26 18:59:03 +00006484/**
6485 * xmlSaveFile:
6486 * @filename: the filename (or URL)
6487 * @cur: the document
6488 *
6489 * Dump an XML document to a file. Will use compression if
6490 * compiled in and enabled. If @filename is "-" the stdout file is
6491 * used.
6492 * returns: the number of byte written or -1 in case of failure.
6493 */
6494int
6495xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006496 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006497}
6498