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