blob: c55f4ff83e0df583ba000478348d7579cc33be77 [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 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002825 ret->last = ret->children;
2826 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002827 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002828 UPDATE_LAST_CHILD_AND_PARENT(ret)
2829 }
Owen Taylor3473f882001-02-23 17:55:21 +00002830 return(ret);
2831}
2832
2833static xmlNodePtr
2834xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2835 xmlNodePtr ret = NULL;
2836 xmlNodePtr p = NULL,q;
2837
2838 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002839 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002840 if (doc == NULL) {
2841 node = node->next;
2842 continue;
2843 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002844 if (doc->intSubset == NULL) {
2845 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2846 q->doc = doc;
2847 q->parent = parent;
2848 doc->intSubset = (xmlDtdPtr) q;
2849 } else {
2850 q = (xmlNodePtr) doc->intSubset;
2851 }
2852 } else
2853 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002854 if (ret == NULL) {
2855 q->prev = NULL;
2856 ret = p = q;
2857 } else {
2858 p->next = q;
2859 q->prev = p;
2860 p = q;
2861 }
2862 node = node->next;
2863 }
2864 return(ret);
2865}
2866
2867/**
2868 * xmlCopyNode:
2869 * @node: the node
2870 * @recursive: if 1 do a recursive copy.
2871 *
2872 * Do a copy of the node.
2873 *
2874 * Returns: a new xmlNodePtr, or NULL in case of error.
2875 */
2876xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002877xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002878 xmlNodePtr ret;
2879
2880 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2881 return(ret);
2882}
2883
2884/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002885 * xmlDocCopyNode:
2886 * @node: the node
2887 * @recursive: if 1 do a recursive copy.
2888 *
2889 * Do a copy of the node to a given document.
2890 *
2891 * Returns: a new xmlNodePtr, or NULL in case of error.
2892 */
2893xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002894xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002895 xmlNodePtr ret;
2896
2897 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2898 return(ret);
2899}
2900
2901/**
Owen Taylor3473f882001-02-23 17:55:21 +00002902 * xmlCopyNodeList:
2903 * @node: the first node in the list.
2904 *
2905 * Do a recursive copy of the node list.
2906 *
2907 * Returns: a new xmlNodePtr, or NULL in case of error.
2908 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002909xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002910 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2911 return(ret);
2912}
2913
2914/**
Owen Taylor3473f882001-02-23 17:55:21 +00002915 * xmlCopyDtd:
2916 * @dtd: the dtd
2917 *
2918 * Do a copy of the dtd.
2919 *
2920 * Returns: a new xmlDtdPtr, or NULL in case of error.
2921 */
2922xmlDtdPtr
2923xmlCopyDtd(xmlDtdPtr dtd) {
2924 xmlDtdPtr ret;
2925
2926 if (dtd == NULL) return(NULL);
2927 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2928 if (ret == NULL) return(NULL);
2929 if (dtd->entities != NULL)
2930 ret->entities = (void *) xmlCopyEntitiesTable(
2931 (xmlEntitiesTablePtr) dtd->entities);
2932 if (dtd->notations != NULL)
2933 ret->notations = (void *) xmlCopyNotationTable(
2934 (xmlNotationTablePtr) dtd->notations);
2935 if (dtd->elements != NULL)
2936 ret->elements = (void *) xmlCopyElementTable(
2937 (xmlElementTablePtr) dtd->elements);
2938 if (dtd->attributes != NULL)
2939 ret->attributes = (void *) xmlCopyAttributeTable(
2940 (xmlAttributeTablePtr) dtd->attributes);
2941 return(ret);
2942}
2943
2944/**
2945 * xmlCopyDoc:
2946 * @doc: the document
2947 * @recursive: if 1 do a recursive copy.
2948 *
2949 * Do a copy of the document info. If recursive, the content tree will
2950 * be copied too as well as Dtd, namespaces and entities.
2951 *
2952 * Returns: a new xmlDocPtr, or NULL in case of error.
2953 */
2954xmlDocPtr
2955xmlCopyDoc(xmlDocPtr doc, int recursive) {
2956 xmlDocPtr ret;
2957
2958 if (doc == NULL) return(NULL);
2959 ret = xmlNewDoc(doc->version);
2960 if (ret == NULL) return(NULL);
2961 if (doc->name != NULL)
2962 ret->name = xmlMemStrdup(doc->name);
2963 if (doc->encoding != NULL)
2964 ret->encoding = xmlStrdup(doc->encoding);
2965 ret->charset = doc->charset;
2966 ret->compression = doc->compression;
2967 ret->standalone = doc->standalone;
2968 if (!recursive) return(ret);
2969
Daniel Veillardb33c2012001-04-25 12:59:04 +00002970 ret->last = NULL;
2971 ret->children = NULL;
2972 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002973 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002974 ret->intSubset->doc = ret;
2975 ret->intSubset->parent = ret;
2976 }
Owen Taylor3473f882001-02-23 17:55:21 +00002977 if (doc->oldNs != NULL)
2978 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2979 if (doc->children != NULL) {
2980 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002981
2982 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2983 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002984 ret->last = NULL;
2985 tmp = ret->children;
2986 while (tmp != NULL) {
2987 if (tmp->next == NULL)
2988 ret->last = tmp;
2989 tmp = tmp->next;
2990 }
2991 }
2992 return(ret);
2993}
2994
2995/************************************************************************
2996 * *
2997 * Content access functions *
2998 * *
2999 ************************************************************************/
3000
3001/**
3002 * xmlDocGetRootElement:
3003 * @doc: the document
3004 *
3005 * Get the root element of the document (doc->children is a list
3006 * containing possibly comments, PIs, etc ...).
3007 *
3008 * Returns the xmlNodePtr for the root or NULL
3009 */
3010xmlNodePtr
3011xmlDocGetRootElement(xmlDocPtr doc) {
3012 xmlNodePtr ret;
3013
3014 if (doc == NULL) return(NULL);
3015 ret = doc->children;
3016 while (ret != NULL) {
3017 if (ret->type == XML_ELEMENT_NODE)
3018 return(ret);
3019 ret = ret->next;
3020 }
3021 return(ret);
3022}
3023
3024/**
3025 * xmlDocSetRootElement:
3026 * @doc: the document
3027 * @root: the new document root element
3028 *
3029 * Set the root element of the document (doc->children is a list
3030 * containing possibly comments, PIs, etc ...).
3031 *
3032 * Returns the old root element if any was found
3033 */
3034xmlNodePtr
3035xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3036 xmlNodePtr old = NULL;
3037
3038 if (doc == NULL) return(NULL);
3039 old = doc->children;
3040 while (old != NULL) {
3041 if (old->type == XML_ELEMENT_NODE)
3042 break;
3043 old = old->next;
3044 }
3045 if (old == NULL) {
3046 if (doc->children == NULL) {
3047 doc->children = root;
3048 doc->last = root;
3049 } else {
3050 xmlAddSibling(doc->children, root);
3051 }
3052 } else {
3053 xmlReplaceNode(old, root);
3054 }
3055 return(old);
3056}
3057
3058/**
3059 * xmlNodeSetLang:
3060 * @cur: the node being changed
3061 * @lang: the langage description
3062 *
3063 * Set the language of a node, i.e. the values of the xml:lang
3064 * attribute.
3065 */
3066void
3067xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3068 if (cur == NULL) return;
3069 switch(cur->type) {
3070 case XML_TEXT_NODE:
3071 case XML_CDATA_SECTION_NODE:
3072 case XML_COMMENT_NODE:
3073 case XML_DOCUMENT_NODE:
3074 case XML_DOCUMENT_TYPE_NODE:
3075 case XML_DOCUMENT_FRAG_NODE:
3076 case XML_NOTATION_NODE:
3077 case XML_HTML_DOCUMENT_NODE:
3078 case XML_DTD_NODE:
3079 case XML_ELEMENT_DECL:
3080 case XML_ATTRIBUTE_DECL:
3081 case XML_ENTITY_DECL:
3082 case XML_PI_NODE:
3083 case XML_ENTITY_REF_NODE:
3084 case XML_ENTITY_NODE:
3085 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003086#ifdef LIBXML_DOCB_ENABLED
3087 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003088#endif
3089 case XML_XINCLUDE_START:
3090 case XML_XINCLUDE_END:
3091 return;
3092 case XML_ELEMENT_NODE:
3093 case XML_ATTRIBUTE_NODE:
3094 break;
3095 }
3096 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3097}
3098
3099/**
3100 * xmlNodeGetLang:
3101 * @cur: the node being checked
3102 *
3103 * Searches the language of a node, i.e. the values of the xml:lang
3104 * attribute or the one carried by the nearest ancestor.
3105 *
3106 * Returns a pointer to the lang value, or NULL if not found
3107 * It's up to the caller to free the memory.
3108 */
3109xmlChar *
3110xmlNodeGetLang(xmlNodePtr cur) {
3111 xmlChar *lang;
3112
3113 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003114 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003115 if (lang != NULL)
3116 return(lang);
3117 cur = cur->parent;
3118 }
3119 return(NULL);
3120}
3121
3122
3123/**
3124 * xmlNodeSetSpacePreserve:
3125 * @cur: the node being changed
3126 * @val: the xml:space value ("0": default, 1: "preserve")
3127 *
3128 * Set (or reset) the space preserving behaviour of a node, i.e. the
3129 * value of the xml:space attribute.
3130 */
3131void
3132xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3133 if (cur == NULL) return;
3134 switch(cur->type) {
3135 case XML_TEXT_NODE:
3136 case XML_CDATA_SECTION_NODE:
3137 case XML_COMMENT_NODE:
3138 case XML_DOCUMENT_NODE:
3139 case XML_DOCUMENT_TYPE_NODE:
3140 case XML_DOCUMENT_FRAG_NODE:
3141 case XML_NOTATION_NODE:
3142 case XML_HTML_DOCUMENT_NODE:
3143 case XML_DTD_NODE:
3144 case XML_ELEMENT_DECL:
3145 case XML_ATTRIBUTE_DECL:
3146 case XML_ENTITY_DECL:
3147 case XML_PI_NODE:
3148 case XML_ENTITY_REF_NODE:
3149 case XML_ENTITY_NODE:
3150 case XML_NAMESPACE_DECL:
3151 case XML_XINCLUDE_START:
3152 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003153#ifdef LIBXML_DOCB_ENABLED
3154 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003155#endif
3156 return;
3157 case XML_ELEMENT_NODE:
3158 case XML_ATTRIBUTE_NODE:
3159 break;
3160 }
3161 switch (val) {
3162 case 0:
3163 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3164 break;
3165 case 1:
3166 xmlSetProp(cur, BAD_CAST "xml:space",
3167 BAD_CAST "preserve");
3168 break;
3169 }
3170}
3171
3172/**
3173 * xmlNodeGetSpacePreserve:
3174 * @cur: the node being checked
3175 *
3176 * Searches the space preserving behaviour of a node, i.e. the values
3177 * of the xml:space attribute or the one carried by the nearest
3178 * ancestor.
3179 *
3180 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
3181 */
3182int
3183xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3184 xmlChar *space;
3185
3186 while (cur != NULL) {
3187 space = xmlGetProp(cur, BAD_CAST "xml:space");
3188 if (space != NULL) {
3189 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3190 xmlFree(space);
3191 return(1);
3192 }
3193 if (xmlStrEqual(space, BAD_CAST "default")) {
3194 xmlFree(space);
3195 return(0);
3196 }
3197 xmlFree(space);
3198 }
3199 cur = cur->parent;
3200 }
3201 return(-1);
3202}
3203
3204/**
3205 * xmlNodeSetName:
3206 * @cur: the node being changed
3207 * @name: the new tag name
3208 *
3209 * Set (or reset) the name of a node.
3210 */
3211void
3212xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3213 if (cur == NULL) return;
3214 if (name == NULL) return;
3215 switch(cur->type) {
3216 case XML_TEXT_NODE:
3217 case XML_CDATA_SECTION_NODE:
3218 case XML_COMMENT_NODE:
3219 case XML_DOCUMENT_TYPE_NODE:
3220 case XML_DOCUMENT_FRAG_NODE:
3221 case XML_NOTATION_NODE:
3222 case XML_HTML_DOCUMENT_NODE:
3223 case XML_NAMESPACE_DECL:
3224 case XML_XINCLUDE_START:
3225 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003226#ifdef LIBXML_DOCB_ENABLED
3227 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003228#endif
3229 return;
3230 case XML_ELEMENT_NODE:
3231 case XML_ATTRIBUTE_NODE:
3232 case XML_PI_NODE:
3233 case XML_ENTITY_REF_NODE:
3234 case XML_ENTITY_NODE:
3235 case XML_DTD_NODE:
3236 case XML_DOCUMENT_NODE:
3237 case XML_ELEMENT_DECL:
3238 case XML_ATTRIBUTE_DECL:
3239 case XML_ENTITY_DECL:
3240 break;
3241 }
3242 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3243 cur->name = xmlStrdup(name);
3244}
3245
3246/**
3247 * xmlNodeSetBase:
3248 * @cur: the node being changed
3249 * @uri: the new base URI
3250 *
3251 * Set (or reset) the base URI of a node, i.e. the value of the
3252 * xml:base attribute.
3253 */
3254void
3255xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3256 if (cur == NULL) return;
3257 switch(cur->type) {
3258 case XML_TEXT_NODE:
3259 case XML_CDATA_SECTION_NODE:
3260 case XML_COMMENT_NODE:
3261 case XML_DOCUMENT_NODE:
3262 case XML_DOCUMENT_TYPE_NODE:
3263 case XML_DOCUMENT_FRAG_NODE:
3264 case XML_NOTATION_NODE:
3265 case XML_HTML_DOCUMENT_NODE:
3266 case XML_DTD_NODE:
3267 case XML_ELEMENT_DECL:
3268 case XML_ATTRIBUTE_DECL:
3269 case XML_ENTITY_DECL:
3270 case XML_PI_NODE:
3271 case XML_ENTITY_REF_NODE:
3272 case XML_ENTITY_NODE:
3273 case XML_NAMESPACE_DECL:
3274 case XML_XINCLUDE_START:
3275 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003276#ifdef LIBXML_DOCB_ENABLED
3277 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003278#endif
3279 return;
3280 case XML_ELEMENT_NODE:
3281 case XML_ATTRIBUTE_NODE:
3282 break;
3283 }
3284 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3285}
3286
3287/**
Owen Taylor3473f882001-02-23 17:55:21 +00003288 * xmlNodeGetBase:
3289 * @doc: the document the node pertains to
3290 * @cur: the node being checked
3291 *
3292 * Searches for the BASE URL. The code should work on both XML
3293 * and HTML document even if base mechanisms are completely different.
3294 * It returns the base as defined in RFC 2396 sections
3295 * 5.1.1. Base URI within Document Content
3296 * and
3297 * 5.1.2. Base URI from the Encapsulating Entity
3298 * However it does not return the document base (5.1.3), use
3299 * xmlDocumentGetBase() for this
3300 *
3301 * Returns a pointer to the base URL, or NULL if not found
3302 * It's up to the caller to free the memory.
3303 */
3304xmlChar *
3305xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003306 xmlChar *oldbase = NULL;
3307 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003308
3309 if ((cur == NULL) && (doc == NULL))
3310 return(NULL);
3311 if (doc == NULL) doc = cur->doc;
3312 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3313 cur = doc->children;
3314 while ((cur != NULL) && (cur->name != NULL)) {
3315 if (cur->type != XML_ELEMENT_NODE) {
3316 cur = cur->next;
3317 continue;
3318 }
3319 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3320 cur = cur->children;
3321 continue;
3322 }
3323 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3324 cur = cur->children;
3325 continue;
3326 }
3327 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3328 return(xmlGetProp(cur, BAD_CAST "href"));
3329 }
3330 cur = cur->next;
3331 }
3332 return(NULL);
3333 }
3334 while (cur != NULL) {
3335 if (cur->type == XML_ENTITY_DECL) {
3336 xmlEntityPtr ent = (xmlEntityPtr) cur;
3337 return(xmlStrdup(ent->URI));
3338 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003339 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003340 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003341 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003342 if (oldbase != NULL) {
3343 newbase = xmlBuildURI(oldbase, base);
3344 if (newbase != NULL) {
3345 xmlFree(oldbase);
3346 xmlFree(base);
3347 oldbase = newbase;
3348 } else {
3349 xmlFree(oldbase);
3350 xmlFree(base);
3351 return(NULL);
3352 }
3353 } else {
3354 oldbase = base;
3355 }
3356 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3357 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3358 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3359 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003360 }
3361 }
Owen Taylor3473f882001-02-23 17:55:21 +00003362 cur = cur->parent;
3363 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003364 if ((doc != NULL) && (doc->URL != NULL)) {
3365 if (oldbase == NULL)
3366 return(xmlStrdup(doc->URL));
3367 newbase = xmlBuildURI(oldbase, doc->URL);
3368 xmlFree(oldbase);
3369 return(newbase);
3370 }
3371 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003372}
3373
3374/**
3375 * xmlNodeGetContent:
3376 * @cur: the node being read
3377 *
3378 * Read the value of a node, this can be either the text carried
3379 * directly by this node if it's a TEXT node or the aggregate string
3380 * of the values carried by this node child's (TEXT and ENTITY_REF).
3381 * Entity references are substitued.
3382 * Returns a new xmlChar * or NULL if no content is available.
3383 * It's up to the caller to free the memory.
3384 */
3385xmlChar *
3386xmlNodeGetContent(xmlNodePtr cur) {
3387 if (cur == NULL) return(NULL);
3388 switch (cur->type) {
3389 case XML_DOCUMENT_FRAG_NODE:
3390 case XML_ELEMENT_NODE: {
3391 xmlNodePtr tmp = cur;
3392 xmlBufferPtr buffer;
3393 xmlChar *ret;
3394
3395 buffer = xmlBufferCreate();
3396 if (buffer == NULL)
3397 return(NULL);
3398 while (tmp != NULL) {
3399 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003400 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003401 case XML_TEXT_NODE:
3402 if (tmp->content != NULL)
3403#ifndef XML_USE_BUFFER_CONTENT
3404 xmlBufferCat(buffer, tmp->content);
3405#else
3406 xmlBufferCat(buffer,
3407 xmlBufferContent(tmp->content));
3408#endif
3409 break;
3410 case XML_ENTITY_REF_NODE: {
3411 xmlEntityPtr ent;
3412
3413 ent = xmlGetDocEntity(cur->doc, tmp->name);
3414 if (ent != NULL)
3415 xmlBufferCat(buffer, ent->content);
3416 }
3417 default:
3418 break;
3419 }
3420 /*
3421 * Skip to next node
3422 */
3423 if (tmp->children != NULL) {
3424 if (tmp->children->type != XML_ENTITY_DECL) {
3425 tmp = tmp->children;
3426 continue;
3427 }
3428 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003429 if (tmp == cur)
3430 break;
3431
Owen Taylor3473f882001-02-23 17:55:21 +00003432 if (tmp->next != NULL) {
3433 tmp = tmp->next;
3434 continue;
3435 }
3436
3437 do {
3438 tmp = tmp->parent;
3439 if (tmp == NULL)
3440 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003441 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003442 tmp = NULL;
3443 break;
3444 }
3445 if (tmp->next != NULL) {
3446 tmp = tmp->next;
3447 break;
3448 }
3449 } while (tmp != NULL);
3450 }
3451 ret = buffer->content;
3452 buffer->content = NULL;
3453 xmlBufferFree(buffer);
3454 return(ret);
3455 }
3456 case XML_ATTRIBUTE_NODE: {
3457 xmlAttrPtr attr = (xmlAttrPtr) cur;
3458 if (attr->parent != NULL)
3459 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3460 else
3461 return(xmlNodeListGetString(NULL, attr->children, 1));
3462 break;
3463 }
3464 case XML_COMMENT_NODE:
3465 case XML_PI_NODE:
3466 if (cur->content != NULL)
3467#ifndef XML_USE_BUFFER_CONTENT
3468 return(xmlStrdup(cur->content));
3469#else
3470 return(xmlStrdup(xmlBufferContent(cur->content)));
3471#endif
3472 return(NULL);
3473 case XML_ENTITY_REF_NODE:
3474 /*
3475 * Locate the entity, and get it's content
3476 * @@@
3477 */
3478 return(NULL);
3479 case XML_ENTITY_NODE:
3480 case XML_DOCUMENT_NODE:
3481 case XML_HTML_DOCUMENT_NODE:
3482 case XML_DOCUMENT_TYPE_NODE:
3483 case XML_NOTATION_NODE:
3484 case XML_DTD_NODE:
3485 case XML_XINCLUDE_START:
3486 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003487#ifdef LIBXML_DOCB_ENABLED
3488 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003489#endif
3490 return(NULL);
3491 case XML_NAMESPACE_DECL:
3492 return(xmlStrdup(((xmlNsPtr)cur)->href));
3493 case XML_ELEMENT_DECL:
3494 /* TODO !!! */
3495 return(NULL);
3496 case XML_ATTRIBUTE_DECL:
3497 /* TODO !!! */
3498 return(NULL);
3499 case XML_ENTITY_DECL:
3500 /* TODO !!! */
3501 return(NULL);
3502 case XML_CDATA_SECTION_NODE:
3503 case XML_TEXT_NODE:
3504 if (cur->content != NULL)
3505#ifndef XML_USE_BUFFER_CONTENT
3506 return(xmlStrdup(cur->content));
3507#else
3508 return(xmlStrdup(xmlBufferContent(cur->content)));
3509#endif
3510 return(NULL);
3511 }
3512 return(NULL);
3513}
3514
3515/**
3516 * xmlNodeSetContent:
3517 * @cur: the node being modified
3518 * @content: the new value of the content
3519 *
3520 * Replace the content of a node.
3521 */
3522void
3523xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3524 if (cur == NULL) {
3525#ifdef DEBUG_TREE
3526 xmlGenericError(xmlGenericErrorContext,
3527 "xmlNodeSetContent : node == NULL\n");
3528#endif
3529 return;
3530 }
3531 switch (cur->type) {
3532 case XML_DOCUMENT_FRAG_NODE:
3533 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003534 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3535 cur->children = xmlStringGetNodeList(cur->doc, content);
3536 UPDATE_LAST_CHILD_AND_PARENT(cur)
3537 break;
3538 case XML_ATTRIBUTE_NODE:
3539 break;
3540 case XML_TEXT_NODE:
3541 case XML_CDATA_SECTION_NODE:
3542 case XML_ENTITY_REF_NODE:
3543 case XML_ENTITY_NODE:
3544 case XML_PI_NODE:
3545 case XML_COMMENT_NODE:
3546 if (cur->content != NULL) {
3547#ifndef XML_USE_BUFFER_CONTENT
3548 xmlFree(cur->content);
3549#else
3550 xmlBufferFree(cur->content);
3551#endif
3552 }
3553 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3554 cur->last = cur->children = NULL;
3555 if (content != NULL) {
3556#ifndef XML_USE_BUFFER_CONTENT
3557 cur->content = xmlStrdup(content);
3558#else
3559 cur->content = xmlBufferCreateSize(0);
3560 xmlBufferSetAllocationScheme(cur->content,
3561 xmlGetBufferAllocationScheme());
3562 xmlBufferAdd(cur->content, content, -1);
3563#endif
3564 } else
3565 cur->content = NULL;
3566 break;
3567 case XML_DOCUMENT_NODE:
3568 case XML_HTML_DOCUMENT_NODE:
3569 case XML_DOCUMENT_TYPE_NODE:
3570 case XML_XINCLUDE_START:
3571 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003572#ifdef LIBXML_DOCB_ENABLED
3573 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003574#endif
3575 break;
3576 case XML_NOTATION_NODE:
3577 break;
3578 case XML_DTD_NODE:
3579 break;
3580 case XML_NAMESPACE_DECL:
3581 break;
3582 case XML_ELEMENT_DECL:
3583 /* TODO !!! */
3584 break;
3585 case XML_ATTRIBUTE_DECL:
3586 /* TODO !!! */
3587 break;
3588 case XML_ENTITY_DECL:
3589 /* TODO !!! */
3590 break;
3591 }
3592}
3593
3594/**
3595 * xmlNodeSetContentLen:
3596 * @cur: the node being modified
3597 * @content: the new value of the content
3598 * @len: the size of @content
3599 *
3600 * Replace the content of a node.
3601 */
3602void
3603xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3604 if (cur == NULL) {
3605#ifdef DEBUG_TREE
3606 xmlGenericError(xmlGenericErrorContext,
3607 "xmlNodeSetContentLen : node == NULL\n");
3608#endif
3609 return;
3610 }
3611 switch (cur->type) {
3612 case XML_DOCUMENT_FRAG_NODE:
3613 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003614 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3615 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3616 UPDATE_LAST_CHILD_AND_PARENT(cur)
3617 break;
3618 case XML_ATTRIBUTE_NODE:
3619 break;
3620 case XML_TEXT_NODE:
3621 case XML_CDATA_SECTION_NODE:
3622 case XML_ENTITY_REF_NODE:
3623 case XML_ENTITY_NODE:
3624 case XML_PI_NODE:
3625 case XML_COMMENT_NODE:
3626 case XML_NOTATION_NODE:
3627 if (cur->content != NULL) {
3628#ifndef XML_USE_BUFFER_CONTENT
3629 xmlFree(cur->content);
3630#else
3631 xmlBufferFree(cur->content);
3632#endif
3633 }
3634 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3635 cur->children = cur->last = NULL;
3636 if (content != NULL) {
3637#ifndef XML_USE_BUFFER_CONTENT
3638 cur->content = xmlStrndup(content, len);
3639#else
3640 cur->content = xmlBufferCreateSize(len);
3641 xmlBufferSetAllocationScheme(cur->content,
3642 xmlGetBufferAllocationScheme());
3643 xmlBufferAdd(cur->content, content, len);
3644#endif
3645 } else
3646 cur->content = NULL;
3647 break;
3648 case XML_DOCUMENT_NODE:
3649 case XML_DTD_NODE:
3650 case XML_HTML_DOCUMENT_NODE:
3651 case XML_DOCUMENT_TYPE_NODE:
3652 case XML_NAMESPACE_DECL:
3653 case XML_XINCLUDE_START:
3654 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003655#ifdef LIBXML_DOCB_ENABLED
3656 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003657#endif
3658 break;
3659 case XML_ELEMENT_DECL:
3660 /* TODO !!! */
3661 break;
3662 case XML_ATTRIBUTE_DECL:
3663 /* TODO !!! */
3664 break;
3665 case XML_ENTITY_DECL:
3666 /* TODO !!! */
3667 break;
3668 }
3669}
3670
3671/**
3672 * xmlNodeAddContentLen:
3673 * @cur: the node being modified
3674 * @content: extra content
3675 * @len: the size of @content
3676 *
3677 * Append the extra substring to the node content.
3678 */
3679void
3680xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3681 if (cur == NULL) {
3682#ifdef DEBUG_TREE
3683 xmlGenericError(xmlGenericErrorContext,
3684 "xmlNodeAddContentLen : node == NULL\n");
3685#endif
3686 return;
3687 }
3688 if (len <= 0) return;
3689 switch (cur->type) {
3690 case XML_DOCUMENT_FRAG_NODE:
3691 case XML_ELEMENT_NODE: {
Daniel Veillard7db37732001-07-12 01:20:08 +00003692 xmlNodePtr last, newNode;
Owen Taylor3473f882001-02-23 17:55:21 +00003693
Daniel Veillard7db37732001-07-12 01:20:08 +00003694 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003695 newNode = xmlNewTextLen(content, len);
3696 if (newNode != NULL) {
3697 xmlAddChild(cur, newNode);
3698 if ((last != NULL) && (last->next == newNode)) {
3699 xmlTextMerge(last, newNode);
3700 }
3701 }
3702 break;
3703 }
3704 case XML_ATTRIBUTE_NODE:
3705 break;
3706 case XML_TEXT_NODE:
3707 case XML_CDATA_SECTION_NODE:
3708 case XML_ENTITY_REF_NODE:
3709 case XML_ENTITY_NODE:
3710 case XML_PI_NODE:
3711 case XML_COMMENT_NODE:
3712 case XML_NOTATION_NODE:
3713 if (content != NULL) {
3714#ifndef XML_USE_BUFFER_CONTENT
3715 cur->content = xmlStrncat(cur->content, content, len);
3716#else
3717 xmlBufferAdd(cur->content, content, len);
3718#endif
3719 }
3720 case XML_DOCUMENT_NODE:
3721 case XML_DTD_NODE:
3722 case XML_HTML_DOCUMENT_NODE:
3723 case XML_DOCUMENT_TYPE_NODE:
3724 case XML_NAMESPACE_DECL:
3725 case XML_XINCLUDE_START:
3726 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003727#ifdef LIBXML_DOCB_ENABLED
3728 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003729#endif
3730 break;
3731 case XML_ELEMENT_DECL:
3732 case XML_ATTRIBUTE_DECL:
3733 case XML_ENTITY_DECL:
3734 break;
3735 }
3736}
3737
3738/**
3739 * xmlNodeAddContent:
3740 * @cur: the node being modified
3741 * @content: extra content
3742 *
3743 * Append the extra substring to the node content.
3744 */
3745void
3746xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3747 int len;
3748
3749 if (cur == NULL) {
3750#ifdef DEBUG_TREE
3751 xmlGenericError(xmlGenericErrorContext,
3752 "xmlNodeAddContent : node == NULL\n");
3753#endif
3754 return;
3755 }
3756 if (content == NULL) return;
3757 len = xmlStrlen(content);
3758 xmlNodeAddContentLen(cur, content, len);
3759}
3760
3761/**
3762 * xmlTextMerge:
3763 * @first: the first text node
3764 * @second: the second text node being merged
3765 *
3766 * Merge two text nodes into one
3767 * Returns the first text node augmented
3768 */
3769xmlNodePtr
3770xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3771 if (first == NULL) return(second);
3772 if (second == NULL) return(first);
3773 if (first->type != XML_TEXT_NODE) return(first);
3774 if (second->type != XML_TEXT_NODE) return(first);
3775 if (second->name != first->name)
3776 return(first);
3777#ifndef XML_USE_BUFFER_CONTENT
3778 xmlNodeAddContent(first, second->content);
3779#else
3780 xmlNodeAddContent(first, xmlBufferContent(second->content));
3781#endif
3782 xmlUnlinkNode(second);
3783 xmlFreeNode(second);
3784 return(first);
3785}
3786
3787/**
3788 * xmlGetNsList:
3789 * @doc: the document
3790 * @node: the current node
3791 *
3792 * Search all the namespace applying to a given element.
3793 * Returns an NULL terminated array of all the xmlNsPtr found
3794 * that need to be freed by the caller or NULL if no
3795 * namespace if defined
3796 */
3797xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003798xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3799{
Owen Taylor3473f882001-02-23 17:55:21 +00003800 xmlNsPtr cur;
3801 xmlNsPtr *ret = NULL;
3802 int nbns = 0;
3803 int maxns = 10;
3804 int i;
3805
3806 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00003807 if (node->type == XML_ELEMENT_NODE) {
3808 cur = node->nsDef;
3809 while (cur != NULL) {
3810 if (ret == NULL) {
3811 ret =
3812 (xmlNsPtr *) xmlMalloc((maxns + 1) *
3813 sizeof(xmlNsPtr));
3814 if (ret == NULL) {
3815 xmlGenericError(xmlGenericErrorContext,
3816 "xmlGetNsList : out of memory!\n");
3817 return (NULL);
3818 }
3819 ret[nbns] = NULL;
3820 }
3821 for (i = 0; i < nbns; i++) {
3822 if ((cur->prefix == ret[i]->prefix) ||
3823 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
3824 break;
3825 }
3826 if (i >= nbns) {
3827 if (nbns >= maxns) {
3828 maxns *= 2;
3829 ret = (xmlNsPtr *) xmlRealloc(ret,
3830 (maxns +
3831 1) *
3832 sizeof(xmlNsPtr));
3833 if (ret == NULL) {
3834 xmlGenericError(xmlGenericErrorContext,
3835 "xmlGetNsList : realloc failed!\n");
3836 return (NULL);
3837 }
3838 }
3839 ret[nbns++] = cur;
3840 ret[nbns] = NULL;
3841 }
Owen Taylor3473f882001-02-23 17:55:21 +00003842
Daniel Veillard77044732001-06-29 21:31:07 +00003843 cur = cur->next;
3844 }
3845 }
3846 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003847 }
Daniel Veillard77044732001-06-29 21:31:07 +00003848 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003849}
3850
3851/**
3852 * xmlSearchNs:
3853 * @doc: the document
3854 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00003855 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00003856 *
3857 * Search a Ns registered under a given name space for a document.
3858 * recurse on the parents until it finds the defined namespace
3859 * or return NULL otherwise.
3860 * @nameSpace can be NULL, this is a search for the default namespace.
3861 * We don't allow to cross entities boundaries. If you don't declare
3862 * the namespace within those you will be in troubles !!! A warning
3863 * is generated to cover this case.
3864 *
3865 * Returns the namespace pointer or NULL.
3866 */
3867xmlNsPtr
3868xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
3869 xmlNsPtr cur;
3870
3871 if (node == NULL) return(NULL);
3872 if ((nameSpace != NULL) &&
3873 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
3874 if (doc->oldNs == NULL) {
3875 /*
3876 * Allocate a new Namespace and fill the fields.
3877 */
3878 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3879 if (doc->oldNs == NULL) {
3880 xmlGenericError(xmlGenericErrorContext,
3881 "xmlSearchNsByHref : malloc failed\n");
3882 return(NULL);
3883 }
3884 memset(doc->oldNs, 0, sizeof(xmlNs));
3885 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3886
3887 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3888 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3889 }
3890 return(doc->oldNs);
3891 }
3892 while (node != NULL) {
3893 if ((node->type == XML_ENTITY_REF_NODE) ||
3894 (node->type == XML_ENTITY_NODE) ||
3895 (node->type == XML_ENTITY_DECL))
3896 return(NULL);
3897 if (node->type == XML_ELEMENT_NODE) {
3898 cur = node->nsDef;
3899 while (cur != NULL) {
3900 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3901 (cur->href != NULL))
3902 return(cur);
3903 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
3904 (cur->href != NULL) &&
3905 (xmlStrEqual(cur->prefix, nameSpace)))
3906 return(cur);
3907 cur = cur->next;
3908 }
3909 }
3910 node = node->parent;
3911 }
3912 return(NULL);
3913}
3914
3915/**
3916 * xmlSearchNsByHref:
3917 * @doc: the document
3918 * @node: the current node
3919 * @href: the namespace value
3920 *
3921 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3922 * the defined namespace or return NULL otherwise.
3923 * Returns the namespace pointer or NULL.
3924 */
3925xmlNsPtr
3926xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
3927 xmlNsPtr cur;
3928 xmlNodePtr orig = node;
3929
3930 if ((node == NULL) || (href == NULL)) return(NULL);
3931 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
3932 if (doc->oldNs == NULL) {
3933 /*
3934 * Allocate a new Namespace and fill the fields.
3935 */
3936 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3937 if (doc->oldNs == NULL) {
3938 xmlGenericError(xmlGenericErrorContext,
3939 "xmlSearchNsByHref : malloc failed\n");
3940 return(NULL);
3941 }
3942 memset(doc->oldNs, 0, sizeof(xmlNs));
3943 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3944
3945 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3946 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3947 }
3948 return(doc->oldNs);
3949 }
3950 while (node != NULL) {
3951 cur = node->nsDef;
3952 while (cur != NULL) {
3953 if ((cur->href != NULL) && (href != NULL) &&
3954 (xmlStrEqual(cur->href, href))) {
3955 /*
3956 * Check that the prefix is not shadowed between orig and node
3957 */
3958 xmlNodePtr check = orig;
3959 xmlNsPtr tst;
3960
3961 while (check != node) {
3962 tst = check->nsDef;
3963 while (tst != NULL) {
3964 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3965 goto shadowed;
3966 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
3967 (xmlStrEqual(tst->prefix, cur->prefix)))
3968 goto shadowed;
3969 tst = tst->next;
3970 }
3971 check = check->parent;
3972 }
3973 return(cur);
3974 }
3975shadowed:
3976 cur = cur->next;
3977 }
3978 node = node->parent;
3979 }
3980 return(NULL);
3981}
3982
3983/**
3984 * xmlNewReconciliedNs
3985 * @doc: the document
3986 * @tree: a node expected to hold the new namespace
3987 * @ns: the original namespace
3988 *
3989 * This function tries to locate a namespace definition in a tree
3990 * ancestors, or create a new namespace definition node similar to
3991 * @ns trying to reuse the same prefix. However if the given prefix is
3992 * null (default namespace) or reused within the subtree defined by
3993 * @tree or on one of its ancestors then a new prefix is generated.
3994 * Returns the (new) namespace definition or NULL in case of error
3995 */
3996xmlNsPtr
3997xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3998 xmlNsPtr def;
3999 xmlChar prefix[50];
4000 int counter = 1;
4001
4002 if (tree == NULL) {
4003#ifdef DEBUG_TREE
4004 xmlGenericError(xmlGenericErrorContext,
4005 "xmlNewReconciliedNs : tree == NULL\n");
4006#endif
4007 return(NULL);
4008 }
4009 if (ns == NULL) {
4010#ifdef DEBUG_TREE
4011 xmlGenericError(xmlGenericErrorContext,
4012 "xmlNewReconciliedNs : ns == NULL\n");
4013#endif
4014 return(NULL);
4015 }
4016 /*
4017 * Search an existing namespace definition inherited.
4018 */
4019 def = xmlSearchNsByHref(doc, tree, ns->href);
4020 if (def != NULL)
4021 return(def);
4022
4023 /*
4024 * Find a close prefix which is not already in use.
4025 * Let's strip namespace prefixes longer than 20 chars !
4026 */
4027 sprintf((char *) prefix, "%.20s", ns->prefix);
4028 def = xmlSearchNs(doc, tree, prefix);
4029 while (def != NULL) {
4030 if (counter > 1000) return(NULL);
4031 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4032 def = xmlSearchNs(doc, tree, prefix);
4033 }
4034
4035 /*
4036 * Ok, now we are ready to create a new one.
4037 */
4038 def = xmlNewNs(tree, ns->href, prefix);
4039 return(def);
4040}
4041
4042/**
4043 * xmlReconciliateNs
4044 * @doc: the document
4045 * @tree: a node defining the subtree to reconciliate
4046 *
4047 * This function checks that all the namespaces declared within the given
4048 * tree are properly declared. This is needed for example after Copy or Cut
4049 * and then paste operations. The subtree may still hold pointers to
4050 * namespace declarations outside the subtree or invalid/masked. As much
4051 * as possible the function try tu reuse the existing namespaces found in
4052 * the new environment. If not possible the new namespaces are redeclared
4053 * on @tree at the top of the given subtree.
4054 * Returns the number of namespace declarations created or -1 in case of error.
4055 */
4056int
4057xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4058 xmlNsPtr *oldNs = NULL;
4059 xmlNsPtr *newNs = NULL;
4060 int sizeCache = 0;
4061 int nbCache = 0;
4062
4063 xmlNsPtr n;
4064 xmlNodePtr node = tree;
4065 xmlAttrPtr attr;
4066 int ret = 0, i;
4067
4068 while (node != NULL) {
4069 /*
4070 * Reconciliate the node namespace
4071 */
4072 if (node->ns != NULL) {
4073 /*
4074 * initialize the cache if needed
4075 */
4076 if (sizeCache == 0) {
4077 sizeCache = 10;
4078 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4079 sizeof(xmlNsPtr));
4080 if (oldNs == NULL) {
4081 xmlGenericError(xmlGenericErrorContext,
4082 "xmlReconciliateNs : memory pbm\n");
4083 return(-1);
4084 }
4085 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4086 sizeof(xmlNsPtr));
4087 if (newNs == NULL) {
4088 xmlGenericError(xmlGenericErrorContext,
4089 "xmlReconciliateNs : memory pbm\n");
4090 xmlFree(oldNs);
4091 return(-1);
4092 }
4093 }
4094 for (i = 0;i < nbCache;i++) {
4095 if (oldNs[i] == node->ns) {
4096 node->ns = newNs[i];
4097 break;
4098 }
4099 }
4100 if (i == nbCache) {
4101 /*
4102 * Ok we need to recreate a new namespace definition
4103 */
4104 n = xmlNewReconciliedNs(doc, tree, node->ns);
4105 if (n != NULL) { /* :-( what if else ??? */
4106 /*
4107 * check if we need to grow the cache buffers.
4108 */
4109 if (sizeCache <= nbCache) {
4110 sizeCache *= 2;
4111 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4112 sizeof(xmlNsPtr));
4113 if (oldNs == NULL) {
4114 xmlGenericError(xmlGenericErrorContext,
4115 "xmlReconciliateNs : memory pbm\n");
4116 xmlFree(newNs);
4117 return(-1);
4118 }
4119 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4120 sizeof(xmlNsPtr));
4121 if (newNs == NULL) {
4122 xmlGenericError(xmlGenericErrorContext,
4123 "xmlReconciliateNs : memory pbm\n");
4124 xmlFree(oldNs);
4125 return(-1);
4126 }
4127 }
4128 newNs[nbCache] = n;
4129 oldNs[nbCache++] = node->ns;
4130 node->ns = n;
4131 }
4132 }
4133 }
4134 /*
4135 * now check for namespace hold by attributes on the node.
4136 */
4137 attr = node->properties;
4138 while (attr != NULL) {
4139 if (attr->ns != NULL) {
4140 /*
4141 * initialize the cache if needed
4142 */
4143 if (sizeCache == 0) {
4144 sizeCache = 10;
4145 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4146 sizeof(xmlNsPtr));
4147 if (oldNs == NULL) {
4148 xmlGenericError(xmlGenericErrorContext,
4149 "xmlReconciliateNs : memory pbm\n");
4150 return(-1);
4151 }
4152 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4153 sizeof(xmlNsPtr));
4154 if (newNs == NULL) {
4155 xmlGenericError(xmlGenericErrorContext,
4156 "xmlReconciliateNs : memory pbm\n");
4157 xmlFree(oldNs);
4158 return(-1);
4159 }
4160 }
4161 for (i = 0;i < nbCache;i++) {
4162 if (oldNs[i] == attr->ns) {
4163 node->ns = newNs[i];
4164 break;
4165 }
4166 }
4167 if (i == nbCache) {
4168 /*
4169 * Ok we need to recreate a new namespace definition
4170 */
4171 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4172 if (n != NULL) { /* :-( what if else ??? */
4173 /*
4174 * check if we need to grow the cache buffers.
4175 */
4176 if (sizeCache <= nbCache) {
4177 sizeCache *= 2;
4178 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4179 sizeof(xmlNsPtr));
4180 if (oldNs == NULL) {
4181 xmlGenericError(xmlGenericErrorContext,
4182 "xmlReconciliateNs : memory pbm\n");
4183 xmlFree(newNs);
4184 return(-1);
4185 }
4186 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4187 sizeof(xmlNsPtr));
4188 if (newNs == NULL) {
4189 xmlGenericError(xmlGenericErrorContext,
4190 "xmlReconciliateNs : memory pbm\n");
4191 xmlFree(oldNs);
4192 return(-1);
4193 }
4194 }
4195 newNs[nbCache] = n;
4196 oldNs[nbCache++] = attr->ns;
4197 attr->ns = n;
4198 }
4199 }
4200 }
4201 attr = attr->next;
4202 }
4203
4204 /*
4205 * Browse the full subtree, deep first
4206 */
4207 if (node->children != NULL) {
4208 /* deep first */
4209 node = node->children;
4210 } else if ((node != tree) && (node->next != NULL)) {
4211 /* then siblings */
4212 node = node->next;
4213 } else if (node != tree) {
4214 /* go up to parents->next if needed */
4215 while (node != tree) {
4216 if (node->parent != NULL)
4217 node = node->parent;
4218 if ((node != tree) && (node->next != NULL)) {
4219 node = node->next;
4220 break;
4221 }
4222 if (node->parent == NULL) {
4223 node = NULL;
4224 break;
4225 }
4226 }
4227 /* exit condition */
4228 if (node == tree)
4229 node = NULL;
4230 }
4231 }
4232 return(ret);
4233}
4234
4235/**
4236 * xmlHasProp:
4237 * @node: the node
4238 * @name: the attribute name
4239 *
4240 * Search an attribute associated to a node
4241 * This function also looks in DTD attribute declaration for #FIXED or
4242 * default declaration values unless DTD use has been turned off.
4243 *
4244 * Returns the attribute or the attribute declaration or NULL if
4245 * neither was found.
4246 */
4247xmlAttrPtr
4248xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4249 xmlAttrPtr prop;
4250 xmlDocPtr doc;
4251
4252 if ((node == NULL) || (name == NULL)) return(NULL);
4253 /*
4254 * Check on the properties attached to the node
4255 */
4256 prop = node->properties;
4257 while (prop != NULL) {
4258 if (xmlStrEqual(prop->name, name)) {
4259 return(prop);
4260 }
4261 prop = prop->next;
4262 }
4263 if (!xmlCheckDTD) return(NULL);
4264
4265 /*
4266 * Check if there is a default declaration in the internal
4267 * or external subsets
4268 */
4269 doc = node->doc;
4270 if (doc != NULL) {
4271 xmlAttributePtr attrDecl;
4272 if (doc->intSubset != NULL) {
4273 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4274 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4275 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4276 if (attrDecl != NULL)
4277 return((xmlAttrPtr) attrDecl);
4278 }
4279 }
4280 return(NULL);
4281}
4282
4283/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004284 * xmlHasNsProp:
4285 * @node: the node
4286 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004287 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004288 *
4289 * Search for an attribute associated to a node
4290 * This attribute has to be anchored in the namespace specified.
4291 * This does the entity substitution.
4292 * This function looks in DTD attribute declaration for #FIXED or
4293 * default declaration values unless DTD use has been turned off.
4294 *
4295 * Returns the attribute or the attribute declaration or NULL
4296 * if neither was found.
4297 */
4298xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004299xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004300 xmlAttrPtr prop;
4301 xmlDocPtr doc;
4302 xmlNsPtr ns;
4303
4304 if (node == NULL)
4305 return(NULL);
4306
4307 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004308 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004309 return(xmlHasProp(node, name));
4310 while (prop != NULL) {
4311 /*
4312 * One need to have
4313 * - same attribute names
4314 * - and the attribute carrying that namespace
4315 * or
4316 * no namespace on the attribute and the element carrying it
4317 */
4318 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004319 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4320 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004321 }
4322 prop = prop->next;
4323 }
4324 if (!xmlCheckDTD) return(NULL);
4325
4326 /*
4327 * Check if there is a default declaration in the internal
4328 * or external subsets
4329 */
4330 doc = node->doc;
4331 if (doc != NULL) {
4332 if (doc->intSubset != NULL) {
4333 xmlAttributePtr attrDecl;
4334
4335 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4336 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4337 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4338
4339 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4340 /*
4341 * The DTD declaration only allows a prefix search
4342 */
4343 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004344 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004345 return((xmlAttrPtr) attrDecl);
4346 }
4347 }
4348 }
4349 return(NULL);
4350}
4351
4352/**
Owen Taylor3473f882001-02-23 17:55:21 +00004353 * xmlGetProp:
4354 * @node: the node
4355 * @name: the attribute name
4356 *
4357 * Search and get the value of an attribute associated to a node
4358 * This does the entity substitution.
4359 * This function looks in DTD attribute declaration for #FIXED or
4360 * default declaration values unless DTD use has been turned off.
4361 *
4362 * Returns the attribute value or NULL if not found.
4363 * It's up to the caller to free the memory.
4364 */
4365xmlChar *
4366xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4367 xmlAttrPtr prop;
4368 xmlDocPtr doc;
4369
4370 if ((node == NULL) || (name == NULL)) return(NULL);
4371 /*
4372 * Check on the properties attached to the node
4373 */
4374 prop = node->properties;
4375 while (prop != NULL) {
4376 if (xmlStrEqual(prop->name, name)) {
4377 xmlChar *ret;
4378
4379 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4380 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4381 return(ret);
4382 }
4383 prop = prop->next;
4384 }
4385 if (!xmlCheckDTD) return(NULL);
4386
4387 /*
4388 * Check if there is a default declaration in the internal
4389 * or external subsets
4390 */
4391 doc = node->doc;
4392 if (doc != NULL) {
4393 xmlAttributePtr attrDecl;
4394 if (doc->intSubset != NULL) {
4395 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4396 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4397 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4398 if (attrDecl != NULL)
4399 return(xmlStrdup(attrDecl->defaultValue));
4400 }
4401 }
4402 return(NULL);
4403}
4404
4405/**
4406 * xmlGetNsProp:
4407 * @node: the node
4408 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004409 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004410 *
4411 * Search and get the value of an attribute associated to a node
4412 * This attribute has to be anchored in the namespace specified.
4413 * This does the entity substitution.
4414 * This function looks in DTD attribute declaration for #FIXED or
4415 * default declaration values unless DTD use has been turned off.
4416 *
4417 * Returns the attribute value or NULL if not found.
4418 * It's up to the caller to free the memory.
4419 */
4420xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004421xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004422 xmlAttrPtr prop;
4423 xmlDocPtr doc;
4424 xmlNsPtr ns;
4425
4426 if (node == NULL)
4427 return(NULL);
4428
4429 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004430 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004431 return(xmlGetProp(node, name));
4432 while (prop != NULL) {
4433 /*
4434 * One need to have
4435 * - same attribute names
4436 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004437 */
4438 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004439 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004440 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004441 xmlChar *ret;
4442
4443 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4444 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4445 return(ret);
4446 }
4447 prop = prop->next;
4448 }
4449 if (!xmlCheckDTD) return(NULL);
4450
4451 /*
4452 * Check if there is a default declaration in the internal
4453 * or external subsets
4454 */
4455 doc = node->doc;
4456 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004457 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004458 xmlAttributePtr attrDecl;
4459
Owen Taylor3473f882001-02-23 17:55:21 +00004460 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4461 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4462 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4463
4464 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4465 /*
4466 * The DTD declaration only allows a prefix search
4467 */
4468 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004469 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004470 return(xmlStrdup(attrDecl->defaultValue));
4471 }
4472 }
4473 }
4474 return(NULL);
4475}
4476
4477/**
4478 * xmlSetProp:
4479 * @node: the node
4480 * @name: the attribute name
4481 * @value: the attribute value
4482 *
4483 * Set (or reset) an attribute carried by a node.
4484 * Returns the attribute pointer.
4485 */
4486xmlAttrPtr
4487xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
4488 xmlAttrPtr prop = node->properties;
4489 xmlDocPtr doc = NULL;
4490
4491 if ((node == NULL) || (name == NULL))
4492 return(NULL);
4493 doc = node->doc;
4494 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004495 if ((xmlStrEqual(prop->name, name)) &&
4496 (prop->ns == NULL)){
Owen Taylor3473f882001-02-23 17:55:21 +00004497 if (prop->children != NULL)
4498 xmlFreeNodeList(prop->children);
4499 prop->children = NULL;
4500 prop->last = NULL;
4501 if (value != NULL) {
4502 xmlChar *buffer;
4503 xmlNodePtr tmp;
4504
4505 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4506 prop->children = xmlStringGetNodeList(node->doc, buffer);
4507 prop->last = NULL;
4508 prop->doc = doc;
4509 tmp = prop->children;
4510 while (tmp != NULL) {
4511 tmp->parent = (xmlNodePtr) prop;
4512 tmp->doc = doc;
4513 if (tmp->next == NULL)
4514 prop->last = tmp;
4515 tmp = tmp->next;
4516 }
4517 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004518 }
Owen Taylor3473f882001-02-23 17:55:21 +00004519 return(prop);
4520 }
4521 prop = prop->next;
4522 }
4523 prop = xmlNewProp(node, name, value);
4524 return(prop);
4525}
4526
4527/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004528 * xmlUnsetProp:
4529 * @node: the node
4530 * @name: the attribute name
4531 *
4532 * Remove an attribute carried by a node.
4533 * Returns 0 if successful, -1 if not found
4534 */
4535int
4536xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4537 xmlAttrPtr prop = node->properties, prev = NULL;;
4538
4539 if ((node == NULL) || (name == NULL))
4540 return(-1);
4541 while (prop != NULL) {
4542 if ((xmlStrEqual(prop->name, name)) &&
4543 (prop->ns == NULL)) {
4544 if (prev == NULL)
4545 node->properties = prop->next;
4546 else
4547 prev->next = prop->next;
4548 xmlFreeProp(prop);
4549 return(0);
4550 }
4551 prev = prop;
4552 prop = prop->next;
4553 }
4554 return(-1);
4555}
4556
4557/**
Owen Taylor3473f882001-02-23 17:55:21 +00004558 * xmlSetNsProp:
4559 * @node: the node
4560 * @ns: the namespace definition
4561 * @name: the attribute name
4562 * @value: the attribute value
4563 *
4564 * Set (or reset) an attribute carried by a node.
4565 * The ns structure must be in scope, this is not checked.
4566 *
4567 * Returns the attribute pointer.
4568 */
4569xmlAttrPtr
4570xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4571 const xmlChar *value) {
4572 xmlAttrPtr prop;
4573
4574 if ((node == NULL) || (name == NULL))
4575 return(NULL);
4576
4577 if (ns == NULL)
4578 return(xmlSetProp(node, name, value));
4579 if (ns->href == NULL)
4580 return(NULL);
4581 prop = node->properties;
4582
4583 while (prop != NULL) {
4584 /*
4585 * One need to have
4586 * - same attribute names
4587 * - and the attribute carrying that namespace
4588 * or
4589 * no namespace on the attribute and the element carrying it
4590 */
4591 if ((xmlStrEqual(prop->name, name)) &&
4592 (((prop->ns == NULL) && (node->ns != NULL) &&
4593 (xmlStrEqual(node->ns->href, ns->href))) ||
4594 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4595 if (prop->children != NULL)
4596 xmlFreeNodeList(prop->children);
4597 prop->children = NULL;
4598 prop->last = NULL;
4599 prop->ns = ns;
4600 if (value != NULL) {
4601 xmlChar *buffer;
4602 xmlNodePtr tmp;
4603
4604 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4605 prop->children = xmlStringGetNodeList(node->doc, buffer);
4606 prop->last = NULL;
4607 tmp = prop->children;
4608 while (tmp != NULL) {
4609 tmp->parent = (xmlNodePtr) prop;
4610 if (tmp->next == NULL)
4611 prop->last = tmp;
4612 tmp = tmp->next;
4613 }
4614 xmlFree(buffer);
4615 }
4616 return(prop);
4617 }
4618 prop = prop->next;
4619 }
4620 prop = xmlNewNsProp(node, ns, name, value);
4621 return(prop);
4622}
4623
4624/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004625 * xmlUnsetNsProp:
4626 * @node: the node
4627 * @ns: the namespace definition
4628 * @name: the attribute name
4629 *
4630 * Remove an attribute carried by a node.
4631 * Returns 0 if successful, -1 if not found
4632 */
4633int
4634xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4635 xmlAttrPtr prop = node->properties, prev = NULL;;
4636
4637 if ((node == NULL) || (name == NULL))
4638 return(-1);
4639 if (ns == NULL)
4640 return(xmlUnsetProp(node, name));
4641 if (ns->href == NULL)
4642 return(-1);
4643 while (prop != NULL) {
4644 if ((xmlStrEqual(prop->name, name)) &&
4645 (((prop->ns == NULL) && (node->ns != NULL) &&
4646 (xmlStrEqual(node->ns->href, ns->href))) ||
4647 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4648 if (prev == NULL)
4649 node->properties = prop->next;
4650 else
4651 prev->next = prop->next;
4652 xmlFreeProp(prop);
4653 return(0);
4654 }
4655 prev = prop;
4656 prop = prop->next;
4657 }
4658 return(-1);
4659}
4660
4661/**
Owen Taylor3473f882001-02-23 17:55:21 +00004662 * xmlNodeIsText:
4663 * @node: the node
4664 *
4665 * Is this node a Text node ?
4666 * Returns 1 yes, 0 no
4667 */
4668int
4669xmlNodeIsText(xmlNodePtr node) {
4670 if (node == NULL) return(0);
4671
4672 if (node->type == XML_TEXT_NODE) return(1);
4673 return(0);
4674}
4675
4676/**
4677 * xmlIsBlankNode:
4678 * @node: the node
4679 *
4680 * Checks whether this node is an empty or whitespace only
4681 * (and possibly ignorable) text-node.
4682 *
4683 * Returns 1 yes, 0 no
4684 */
4685int
4686xmlIsBlankNode(xmlNodePtr node) {
4687 const xmlChar *cur;
4688 if (node == NULL) return(0);
4689
Daniel Veillard7db37732001-07-12 01:20:08 +00004690 if ((node->type != XML_TEXT_NODE) &&
4691 (node->type != XML_CDATA_SECTION_NODE))
4692 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004693 if (node->content == NULL) return(1);
4694#ifndef XML_USE_BUFFER_CONTENT
4695 cur = node->content;
4696#else
4697 cur = xmlBufferContent(node->content);
4698#endif
4699 while (*cur != 0) {
4700 if (!IS_BLANK(*cur)) return(0);
4701 cur++;
4702 }
4703
4704 return(1);
4705}
4706
4707/**
4708 * xmlTextConcat:
4709 * @node: the node
4710 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00004711 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00004712 *
4713 * Concat the given string at the end of the existing node content
4714 */
4715
4716void
4717xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4718 if (node == NULL) return;
4719
4720 if ((node->type != XML_TEXT_NODE) &&
4721 (node->type != XML_CDATA_SECTION_NODE)) {
4722#ifdef DEBUG_TREE
4723 xmlGenericError(xmlGenericErrorContext,
4724 "xmlTextConcat: node is not text nor cdata\n");
4725#endif
4726 return;
4727 }
4728#ifndef XML_USE_BUFFER_CONTENT
4729 node->content = xmlStrncat(node->content, content, len);
4730#else
4731 xmlBufferAdd(node->content, content, len);
4732#endif
4733}
4734
4735/************************************************************************
4736 * *
4737 * Output : to a FILE or in memory *
4738 * *
4739 ************************************************************************/
4740
Owen Taylor3473f882001-02-23 17:55:21 +00004741/**
4742 * xmlBufferCreate:
4743 *
4744 * routine to create an XML buffer.
4745 * returns the new structure.
4746 */
4747xmlBufferPtr
4748xmlBufferCreate(void) {
4749 xmlBufferPtr ret;
4750
4751 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4752 if (ret == NULL) {
4753 xmlGenericError(xmlGenericErrorContext,
4754 "xmlBufferCreate : out of memory!\n");
4755 return(NULL);
4756 }
4757 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004758 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004759 ret->alloc = xmlBufferAllocScheme;
4760 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4761 if (ret->content == NULL) {
4762 xmlGenericError(xmlGenericErrorContext,
4763 "xmlBufferCreate : out of memory!\n");
4764 xmlFree(ret);
4765 return(NULL);
4766 }
4767 ret->content[0] = 0;
4768 return(ret);
4769}
4770
4771/**
4772 * xmlBufferCreateSize:
4773 * @size: initial size of buffer
4774 *
4775 * routine to create an XML buffer.
4776 * returns the new structure.
4777 */
4778xmlBufferPtr
4779xmlBufferCreateSize(size_t size) {
4780 xmlBufferPtr ret;
4781
4782 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4783 if (ret == NULL) {
4784 xmlGenericError(xmlGenericErrorContext,
4785 "xmlBufferCreate : out of memory!\n");
4786 return(NULL);
4787 }
4788 ret->use = 0;
4789 ret->alloc = xmlBufferAllocScheme;
4790 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4791 if (ret->size){
4792 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4793 if (ret->content == NULL) {
4794 xmlGenericError(xmlGenericErrorContext,
4795 "xmlBufferCreate : out of memory!\n");
4796 xmlFree(ret);
4797 return(NULL);
4798 }
4799 ret->content[0] = 0;
4800 } else
4801 ret->content = NULL;
4802 return(ret);
4803}
4804
4805/**
4806 * xmlBufferSetAllocationScheme:
4807 * @buf: the buffer to free
4808 * @scheme: allocation scheme to use
4809 *
4810 * Sets the allocation scheme for this buffer
4811 */
4812void
4813xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4814 xmlBufferAllocationScheme scheme) {
4815 if (buf == NULL) {
4816#ifdef DEBUG_BUFFER
4817 xmlGenericError(xmlGenericErrorContext,
4818 "xmlBufferSetAllocationScheme: buf == NULL\n");
4819#endif
4820 return;
4821 }
4822
4823 buf->alloc = scheme;
4824}
4825
4826/**
4827 * xmlBufferFree:
4828 * @buf: the buffer to free
4829 *
4830 * Frees an XML buffer.
4831 */
4832void
4833xmlBufferFree(xmlBufferPtr buf) {
4834 if (buf == NULL) {
4835#ifdef DEBUG_BUFFER
4836 xmlGenericError(xmlGenericErrorContext,
4837 "xmlBufferFree: buf == NULL\n");
4838#endif
4839 return;
4840 }
4841 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004842 xmlFree(buf->content);
4843 }
Owen Taylor3473f882001-02-23 17:55:21 +00004844 xmlFree(buf);
4845}
4846
4847/**
4848 * xmlBufferEmpty:
4849 * @buf: the buffer
4850 *
4851 * empty a buffer.
4852 */
4853void
4854xmlBufferEmpty(xmlBufferPtr buf) {
4855 if (buf->content == NULL) return;
4856 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004857 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004858}
4859
4860/**
4861 * xmlBufferShrink:
4862 * @buf: the buffer to dump
4863 * @len: the number of xmlChar to remove
4864 *
4865 * Remove the beginning of an XML buffer.
4866 *
4867 * Returns the number of xmlChar removed, or -1 in case of failure.
4868 */
4869int
4870xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
4871 if (len == 0) return(0);
4872 if (len > buf->use) return(-1);
4873
4874 buf->use -= len;
4875 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
4876
4877 buf->content[buf->use] = 0;
4878 return(len);
4879}
4880
4881/**
4882 * xmlBufferGrow:
4883 * @buf: the buffer
4884 * @len: the minimum free size to allocate
4885 *
4886 * Grow the available space of an XML buffer.
4887 *
4888 * Returns the new available space or -1 in case of error
4889 */
4890int
4891xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
4892 int size;
4893 xmlChar *newbuf;
4894
4895 if (len + buf->use < buf->size) return(0);
4896
4897 size = buf->use + len + 100;
4898
4899 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
4900 if (newbuf == NULL) return(-1);
4901 buf->content = newbuf;
4902 buf->size = size;
4903 return(buf->size - buf->use);
4904}
4905
4906/**
4907 * xmlBufferDump:
4908 * @file: the file output
4909 * @buf: the buffer to dump
4910 *
4911 * Dumps an XML buffer to a FILE *.
4912 * Returns the number of xmlChar written
4913 */
4914int
4915xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4916 int ret;
4917
4918 if (buf == NULL) {
4919#ifdef DEBUG_BUFFER
4920 xmlGenericError(xmlGenericErrorContext,
4921 "xmlBufferDump: buf == NULL\n");
4922#endif
4923 return(0);
4924 }
4925 if (buf->content == NULL) {
4926#ifdef DEBUG_BUFFER
4927 xmlGenericError(xmlGenericErrorContext,
4928 "xmlBufferDump: buf->content == NULL\n");
4929#endif
4930 return(0);
4931 }
4932 if (file == NULL) file = stdout;
4933 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
4934 return(ret);
4935}
4936
4937/**
4938 * xmlBufferContent:
4939 * @buf: the buffer
4940 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004941 * Function to extract the content of a buffer
4942 *
Owen Taylor3473f882001-02-23 17:55:21 +00004943 * Returns the internal content
4944 */
4945
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004946const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00004947xmlBufferContent(const xmlBufferPtr buf)
4948{
4949 if(!buf)
4950 return NULL;
4951
4952 return buf->content;
4953}
4954
4955/**
4956 * xmlBufferLength:
4957 * @buf: the buffer
4958 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004959 * Function to get the length of a buffer
4960 *
Owen Taylor3473f882001-02-23 17:55:21 +00004961 * Returns the length of data in the internal content
4962 */
4963
4964int
4965xmlBufferLength(const xmlBufferPtr buf)
4966{
4967 if(!buf)
4968 return 0;
4969
4970 return buf->use;
4971}
4972
4973/**
4974 * xmlBufferResize:
4975 * @buf: the buffer to resize
4976 * @size: the desired size
4977 *
4978 * Resize a buffer to accomodate minimum size of @size.
4979 *
4980 * Returns 0 in case of problems, 1 otherwise
4981 */
4982int
4983xmlBufferResize(xmlBufferPtr buf, unsigned int size)
4984{
4985 unsigned int newSize;
4986 xmlChar* rebuf = NULL;
4987
4988 /*take care of empty case*/
4989 newSize = (buf->size ? buf->size*2 : size);
4990
4991 /* Don't resize if we don't have to */
4992 if (size < buf->size)
4993 return 1;
4994
4995 /* figure out new size */
4996 switch (buf->alloc){
4997 case XML_BUFFER_ALLOC_DOUBLEIT:
4998 while (size > newSize) newSize *= 2;
4999 break;
5000 case XML_BUFFER_ALLOC_EXACT:
5001 newSize = size+10;
5002 break;
5003 default:
5004 newSize = size+10;
5005 break;
5006 }
5007
5008 if (buf->content == NULL)
5009 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5010 else
5011 rebuf = (xmlChar *) xmlRealloc(buf->content,
5012 newSize * sizeof(xmlChar));
5013 if (rebuf == NULL) {
5014 xmlGenericError(xmlGenericErrorContext,
5015 "xmlBufferAdd : out of memory!\n");
5016 return 0;
5017 }
5018 buf->content = rebuf;
5019 buf->size = newSize;
5020
5021 return 1;
5022}
5023
5024/**
5025 * xmlBufferAdd:
5026 * @buf: the buffer to dump
5027 * @str: the xmlChar string
5028 * @len: the number of xmlChar to add
5029 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005030 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005031 * str is recomputed.
5032 */
5033void
5034xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5035 unsigned int needSize;
5036
5037 if (str == NULL) {
5038#ifdef DEBUG_BUFFER
5039 xmlGenericError(xmlGenericErrorContext,
5040 "xmlBufferAdd: str == NULL\n");
5041#endif
5042 return;
5043 }
5044 if (len < -1) {
5045#ifdef DEBUG_BUFFER
5046 xmlGenericError(xmlGenericErrorContext,
5047 "xmlBufferAdd: len < 0\n");
5048#endif
5049 return;
5050 }
5051 if (len == 0) return;
5052
5053 if (len < 0)
5054 len = xmlStrlen(str);
5055
5056 if (len <= 0) return;
5057
5058 needSize = buf->use + len + 2;
5059 if (needSize > buf->size){
5060 if (!xmlBufferResize(buf, needSize)){
5061 xmlGenericError(xmlGenericErrorContext,
5062 "xmlBufferAdd : out of memory!\n");
5063 return;
5064 }
5065 }
5066
5067 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5068 buf->use += len;
5069 buf->content[buf->use] = 0;
5070}
5071
5072/**
5073 * xmlBufferAddHead:
5074 * @buf: the buffer
5075 * @str: the xmlChar string
5076 * @len: the number of xmlChar to add
5077 *
5078 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005079 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005080 */
5081void
5082xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5083 unsigned int needSize;
5084
5085 if (str == NULL) {
5086#ifdef DEBUG_BUFFER
5087 xmlGenericError(xmlGenericErrorContext,
5088 "xmlBufferAdd: str == NULL\n");
5089#endif
5090 return;
5091 }
5092 if (len < -1) {
5093#ifdef DEBUG_BUFFER
5094 xmlGenericError(xmlGenericErrorContext,
5095 "xmlBufferAdd: len < 0\n");
5096#endif
5097 return;
5098 }
5099 if (len == 0) return;
5100
5101 if (len < 0)
5102 len = xmlStrlen(str);
5103
5104 if (len <= 0) return;
5105
5106 needSize = buf->use + len + 2;
5107 if (needSize > buf->size){
5108 if (!xmlBufferResize(buf, needSize)){
5109 xmlGenericError(xmlGenericErrorContext,
5110 "xmlBufferAddHead : out of memory!\n");
5111 return;
5112 }
5113 }
5114
5115 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5116 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5117 buf->use += len;
5118 buf->content[buf->use] = 0;
5119}
5120
5121/**
5122 * xmlBufferCat:
5123 * @buf: the buffer to dump
5124 * @str: the xmlChar string
5125 *
5126 * Append a zero terminated string to an XML buffer.
5127 */
5128void
5129xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5130 if (str != NULL)
5131 xmlBufferAdd(buf, str, -1);
5132}
5133
5134/**
5135 * xmlBufferCCat:
5136 * @buf: the buffer to dump
5137 * @str: the C char string
5138 *
5139 * Append a zero terminated C string to an XML buffer.
5140 */
5141void
5142xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5143 const char *cur;
5144
5145 if (str == NULL) {
5146#ifdef DEBUG_BUFFER
5147 xmlGenericError(xmlGenericErrorContext,
5148 "xmlBufferAdd: str == NULL\n");
5149#endif
5150 return;
5151 }
5152 for (cur = str;*cur != 0;cur++) {
5153 if (buf->use + 10 >= buf->size) {
5154 if (!xmlBufferResize(buf, buf->use+10)){
5155 xmlGenericError(xmlGenericErrorContext,
5156 "xmlBufferCCat : out of memory!\n");
5157 return;
5158 }
5159 }
5160 buf->content[buf->use++] = *cur;
5161 }
5162 buf->content[buf->use] = 0;
5163}
5164
5165/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005166 * xmlBufferWriteXmlCHAR:
5167 * @buf: the XML buffer
5168 * @string: the string to add
5169 *
5170 * For VMS only.
5171 * routine which manages and grows an output buffer. This one adds
5172 * xmlChars at the end of the buffer.
5173 */
5174/**
Owen Taylor3473f882001-02-23 17:55:21 +00005175 * xmlBufferWriteCHAR:
5176 * @buf: the XML buffer
5177 * @string: the string to add
5178 *
5179 * routine which manages and grows an output buffer. This one adds
5180 * xmlChars at the end of the buffer.
5181 */
5182void
5183#ifdef VMS
5184xmlBufferWriteXmlCHAR
5185#else
5186xmlBufferWriteCHAR
5187#endif
5188(xmlBufferPtr buf, const xmlChar *string) {
5189 xmlBufferCat(buf, string);
5190}
5191
5192/**
5193 * xmlBufferWriteChar:
5194 * @buf: the XML buffer output
5195 * @string: the string to add
5196 *
5197 * routine which manage and grows an output buffer. This one add
5198 * C chars at the end of the array.
5199 */
5200void
5201xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5202 xmlBufferCCat(buf, string);
5203}
5204
5205
5206/**
5207 * xmlBufferWriteQuotedString:
5208 * @buf: the XML buffer output
5209 * @string: the string to add
5210 *
5211 * routine which manage and grows an output buffer. This one writes
5212 * a quoted or double quoted xmlChar string, checking first if it holds
5213 * quote or double-quotes internally
5214 */
5215void
5216xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5217 if (xmlStrchr(string, '"')) {
5218 if (xmlStrchr(string, '\'')) {
5219#ifdef DEBUG_BUFFER
5220 xmlGenericError(xmlGenericErrorContext,
5221 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5222#endif
5223 }
5224 xmlBufferCCat(buf, "'");
5225 xmlBufferCat(buf, string);
5226 xmlBufferCCat(buf, "'");
5227 } else {
5228 xmlBufferCCat(buf, "\"");
5229 xmlBufferCat(buf, string);
5230 xmlBufferCCat(buf, "\"");
5231 }
5232}
5233
5234
5235/************************************************************************
5236 * *
5237 * Dumping XML tree content to a simple buffer *
5238 * *
5239 ************************************************************************/
5240
5241void
5242xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5243 int format);
5244static void
5245xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5246 int format);
5247void
5248htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5249
5250/**
5251 * xmlNsDump:
5252 * @buf: the XML buffer output
5253 * @cur: a namespace
5254 *
5255 * Dump a local Namespace definition.
5256 * Should be called in the context of attributes dumps.
5257 */
5258static void
5259xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5260 if (cur == NULL) {
5261#ifdef DEBUG_TREE
5262 xmlGenericError(xmlGenericErrorContext,
5263 "xmlNsDump : Ns == NULL\n");
5264#endif
5265 return;
5266 }
5267 if (cur->type == XML_LOCAL_NAMESPACE) {
5268 /* Within the context of an element attributes */
5269 if (cur->prefix != NULL) {
5270 xmlBufferWriteChar(buf, " xmlns:");
5271 xmlBufferWriteCHAR(buf, cur->prefix);
5272 } else
5273 xmlBufferWriteChar(buf, " xmlns");
5274 xmlBufferWriteChar(buf, "=");
5275 xmlBufferWriteQuotedString(buf, cur->href);
5276 }
5277}
5278
5279/**
5280 * xmlNsListDump:
5281 * @buf: the XML buffer output
5282 * @cur: the first namespace
5283 *
5284 * Dump a list of local Namespace definitions.
5285 * Should be called in the context of attributes dumps.
5286 */
5287static void
5288xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5289 while (cur != NULL) {
5290 xmlNsDump(buf, cur);
5291 cur = cur->next;
5292 }
5293}
5294
5295/**
5296 * xmlDtdDump:
5297 * @buf: the XML buffer output
5298 * @doc: the document
5299 *
5300 * Dump the XML document DTD, if any.
5301 */
5302static void
5303xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5304 if (dtd == NULL) {
5305#ifdef DEBUG_TREE
5306 xmlGenericError(xmlGenericErrorContext,
5307 "xmlDtdDump : no internal subset\n");
5308#endif
5309 return;
5310 }
5311 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5312 xmlBufferWriteCHAR(buf, dtd->name);
5313 if (dtd->ExternalID != NULL) {
5314 xmlBufferWriteChar(buf, " PUBLIC ");
5315 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5316 xmlBufferWriteChar(buf, " ");
5317 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5318 } else if (dtd->SystemID != NULL) {
5319 xmlBufferWriteChar(buf, " SYSTEM ");
5320 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5321 }
5322 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5323 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5324 xmlBufferWriteChar(buf, ">");
5325 return;
5326 }
5327 xmlBufferWriteChar(buf, " [\n");
5328 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5329#if 0
5330 if (dtd->entities != NULL)
5331 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5332 if (dtd->notations != NULL)
5333 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5334 if (dtd->elements != NULL)
5335 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5336 if (dtd->attributes != NULL)
5337 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5338#endif
5339 xmlBufferWriteChar(buf, "]>");
5340}
5341
5342/**
5343 * xmlAttrDump:
5344 * @buf: the XML buffer output
5345 * @doc: the document
5346 * @cur: the attribute pointer
5347 *
5348 * Dump an XML attribute
5349 */
5350static void
5351xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5352 xmlChar *value;
5353
5354 if (cur == NULL) {
5355#ifdef DEBUG_TREE
5356 xmlGenericError(xmlGenericErrorContext,
5357 "xmlAttrDump : property == NULL\n");
5358#endif
5359 return;
5360 }
5361 xmlBufferWriteChar(buf, " ");
5362 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5363 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5364 xmlBufferWriteChar(buf, ":");
5365 }
5366 xmlBufferWriteCHAR(buf, cur->name);
5367 value = xmlNodeListGetString(doc, cur->children, 0);
5368 if (value != NULL) {
5369 xmlBufferWriteChar(buf, "=");
5370 xmlBufferWriteQuotedString(buf, value);
5371 xmlFree(value);
5372 } else {
5373 xmlBufferWriteChar(buf, "=\"\"");
5374 }
5375}
5376
5377/**
5378 * xmlAttrListDump:
5379 * @buf: the XML buffer output
5380 * @doc: the document
5381 * @cur: the first attribute pointer
5382 *
5383 * Dump a list of XML attributes
5384 */
5385static void
5386xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5387 if (cur == NULL) {
5388#ifdef DEBUG_TREE
5389 xmlGenericError(xmlGenericErrorContext,
5390 "xmlAttrListDump : property == NULL\n");
5391#endif
5392 return;
5393 }
5394 while (cur != NULL) {
5395 xmlAttrDump(buf, doc, cur);
5396 cur = cur->next;
5397 }
5398}
5399
5400
5401
5402/**
5403 * xmlNodeListDump:
5404 * @buf: the XML buffer output
5405 * @doc: the document
5406 * @cur: the first node
5407 * @level: the imbrication level for indenting
5408 * @format: is formatting allowed
5409 *
5410 * Dump an XML node list, recursive behaviour,children are printed too.
5411 */
5412static void
5413xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5414 int format) {
5415 int i;
5416
5417 if (cur == NULL) {
5418#ifdef DEBUG_TREE
5419 xmlGenericError(xmlGenericErrorContext,
5420 "xmlNodeListDump : node == NULL\n");
5421#endif
5422 return;
5423 }
5424 while (cur != NULL) {
5425 if ((format) && (xmlIndentTreeOutput) &&
5426 (cur->type == XML_ELEMENT_NODE))
5427 for (i = 0;i < level;i++)
5428 xmlBufferWriteChar(buf, " ");
5429 xmlNodeDump(buf, doc, cur, level, format);
5430 if (format) {
5431 xmlBufferWriteChar(buf, "\n");
5432 }
5433 cur = cur->next;
5434 }
5435}
5436
5437/**
5438 * xmlNodeDump:
5439 * @buf: the XML buffer output
5440 * @doc: the document
5441 * @cur: the current node
5442 * @level: the imbrication level for indenting
5443 * @format: is formatting allowed
5444 *
5445 * Dump an XML node, recursive behaviour,children are printed too.
5446 */
5447void
5448xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5449 int format) {
5450 int i;
5451 xmlNodePtr tmp;
5452
5453 if (cur == NULL) {
5454#ifdef DEBUG_TREE
5455 xmlGenericError(xmlGenericErrorContext,
5456 "xmlNodeDump : node == NULL\n");
5457#endif
5458 return;
5459 }
5460 if (cur->type == XML_XINCLUDE_START)
5461 return;
5462 if (cur->type == XML_XINCLUDE_END)
5463 return;
5464 if (cur->type == XML_DTD_NODE) {
5465 xmlDtdDump(buf, (xmlDtdPtr) cur);
5466 return;
5467 }
5468 if (cur->type == XML_ELEMENT_DECL) {
5469 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5470 return;
5471 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005472 if (cur->type == XML_ATTRIBUTE_NODE){
5473 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5474 return;
5475 }
Owen Taylor3473f882001-02-23 17:55:21 +00005476 if (cur->type == XML_ATTRIBUTE_DECL) {
5477 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5478 return;
5479 }
5480 if (cur->type == XML_ENTITY_DECL) {
5481 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5482 return;
5483 }
5484 if (cur->type == XML_TEXT_NODE) {
5485 if (cur->content != NULL) {
5486 if ((cur->name == xmlStringText) ||
5487 (cur->name != xmlStringTextNoenc)) {
5488 xmlChar *buffer;
5489
5490#ifndef XML_USE_BUFFER_CONTENT
5491 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5492#else
5493 buffer = xmlEncodeEntitiesReentrant(doc,
5494 xmlBufferContent(cur->content));
5495#endif
5496 if (buffer != NULL) {
5497 xmlBufferWriteCHAR(buf, buffer);
5498 xmlFree(buffer);
5499 }
5500 } else {
5501 /*
5502 * Disable escaping, needed for XSLT
5503 */
5504#ifndef XML_USE_BUFFER_CONTENT
5505 xmlBufferWriteCHAR(buf, cur->content);
5506#else
5507 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5508#endif
5509 }
5510 }
5511 return;
5512 }
5513 if (cur->type == XML_PI_NODE) {
5514 if (cur->content != NULL) {
5515 xmlBufferWriteChar(buf, "<?");
5516 xmlBufferWriteCHAR(buf, cur->name);
5517 if (cur->content != NULL) {
5518 xmlBufferWriteChar(buf, " ");
5519#ifndef XML_USE_BUFFER_CONTENT
5520 xmlBufferWriteCHAR(buf, cur->content);
5521#else
5522 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5523#endif
5524 }
5525 xmlBufferWriteChar(buf, "?>");
5526 } else {
5527 xmlBufferWriteChar(buf, "<?");
5528 xmlBufferWriteCHAR(buf, cur->name);
5529 xmlBufferWriteChar(buf, "?>");
5530 }
5531 return;
5532 }
5533 if (cur->type == XML_COMMENT_NODE) {
5534 if (cur->content != NULL) {
5535 xmlBufferWriteChar(buf, "<!--");
5536#ifndef XML_USE_BUFFER_CONTENT
5537 xmlBufferWriteCHAR(buf, cur->content);
5538#else
5539 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5540#endif
5541 xmlBufferWriteChar(buf, "-->");
5542 }
5543 return;
5544 }
5545 if (cur->type == XML_ENTITY_REF_NODE) {
5546 xmlBufferWriteChar(buf, "&");
5547 xmlBufferWriteCHAR(buf, cur->name);
5548 xmlBufferWriteChar(buf, ";");
5549 return;
5550 }
5551 if (cur->type == XML_CDATA_SECTION_NODE) {
5552 xmlBufferWriteChar(buf, "<![CDATA[");
5553 if (cur->content != NULL)
5554#ifndef XML_USE_BUFFER_CONTENT
5555 xmlBufferWriteCHAR(buf, cur->content);
5556#else
5557 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5558#endif
5559 xmlBufferWriteChar(buf, "]]>");
5560 return;
5561 }
5562
5563 if (format == 1) {
5564 tmp = cur->children;
5565 while (tmp != NULL) {
5566 if ((tmp->type == XML_TEXT_NODE) ||
5567 (tmp->type == XML_ENTITY_REF_NODE)) {
5568 format = 0;
5569 break;
5570 }
5571 tmp = tmp->next;
5572 }
5573 }
5574 xmlBufferWriteChar(buf, "<");
5575 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5576 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5577 xmlBufferWriteChar(buf, ":");
5578 }
5579
5580 xmlBufferWriteCHAR(buf, cur->name);
5581 if (cur->nsDef)
5582 xmlNsListDump(buf, cur->nsDef);
5583 if (cur->properties != NULL)
5584 xmlAttrListDump(buf, doc, cur->properties);
5585
Daniel Veillard7db37732001-07-12 01:20:08 +00005586 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5587 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005588 (!xmlSaveNoEmptyTags)) {
5589 xmlBufferWriteChar(buf, "/>");
5590 return;
5591 }
5592 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005593 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005594 xmlChar *buffer;
5595
5596#ifndef XML_USE_BUFFER_CONTENT
5597 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5598#else
5599 buffer = xmlEncodeEntitiesReentrant(doc,
5600 xmlBufferContent(cur->content));
5601#endif
5602 if (buffer != NULL) {
5603 xmlBufferWriteCHAR(buf, buffer);
5604 xmlFree(buffer);
5605 }
5606 }
5607 if (cur->children != NULL) {
5608 if (format) xmlBufferWriteChar(buf, "\n");
5609 xmlNodeListDump(buf, doc, cur->children,
5610 (level >= 0?level+1:-1), format);
5611 if ((xmlIndentTreeOutput) && (format))
5612 for (i = 0;i < level;i++)
5613 xmlBufferWriteChar(buf, " ");
5614 }
5615 xmlBufferWriteChar(buf, "</");
5616 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5617 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5618 xmlBufferWriteChar(buf, ":");
5619 }
5620
5621 xmlBufferWriteCHAR(buf, cur->name);
5622 xmlBufferWriteChar(buf, ">");
5623}
5624
5625/**
5626 * xmlElemDump:
5627 * @f: the FILE * for the output
5628 * @doc: the document
5629 * @cur: the current node
5630 *
5631 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5632 */
5633void
5634xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5635 xmlBufferPtr buf;
5636
5637 if (cur == NULL) {
5638#ifdef DEBUG_TREE
5639 xmlGenericError(xmlGenericErrorContext,
5640 "xmlElemDump : cur == NULL\n");
5641#endif
5642 return;
5643 }
Owen Taylor3473f882001-02-23 17:55:21 +00005644#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005645 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005646 xmlGenericError(xmlGenericErrorContext,
5647 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005648 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005649#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005650
Owen Taylor3473f882001-02-23 17:55:21 +00005651 buf = xmlBufferCreate();
5652 if (buf == NULL) return;
5653 if ((doc != NULL) &&
5654 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5655#ifdef LIBXML_HTML_ENABLED
5656 htmlNodeDump(buf, doc, cur);
5657#else
5658 xmlGenericError(xmlGenericErrorContext,
5659 "HTML support not compiled in\n");
5660#endif /* LIBXML_HTML_ENABLED */
5661 } else
5662 xmlNodeDump(buf, doc, cur, 0, 1);
5663 xmlBufferDump(f, buf);
5664 xmlBufferFree(buf);
5665}
5666
5667/************************************************************************
5668 * *
5669 * Dumping XML tree content to an I/O output buffer *
5670 * *
5671 ************************************************************************/
5672
5673void
5674xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5675 int level, int format, const char *encoding);
5676static void
5677xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5678 int level, int format, const char *encoding);
5679/**
5680 * xmlNsDumpOutput:
5681 * @buf: the XML buffer output
5682 * @cur: a namespace
5683 *
5684 * Dump a local Namespace definition.
5685 * Should be called in the context of attributes dumps.
5686 */
5687static void
5688xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5689 if (cur == NULL) {
5690#ifdef DEBUG_TREE
5691 xmlGenericError(xmlGenericErrorContext,
5692 "xmlNsDump : Ns == NULL\n");
5693#endif
5694 return;
5695 }
5696 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5697 /* Within the context of an element attributes */
5698 if (cur->prefix != NULL) {
5699 xmlOutputBufferWriteString(buf, " xmlns:");
5700 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5701 } else
5702 xmlOutputBufferWriteString(buf, " xmlns");
5703 xmlOutputBufferWriteString(buf, "=");
5704 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5705 }
5706}
5707
5708/**
5709 * xmlNsListDumpOutput:
5710 * @buf: the XML buffer output
5711 * @cur: the first namespace
5712 *
5713 * Dump a list of local Namespace definitions.
5714 * Should be called in the context of attributes dumps.
5715 */
5716static void
5717xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5718 while (cur != NULL) {
5719 xmlNsDumpOutput(buf, cur);
5720 cur = cur->next;
5721 }
5722}
5723
5724/**
5725 * xmlDtdDumpOutput:
5726 * @buf: the XML buffer output
5727 * @doc: the document
5728 * @encoding: an optional encoding string
5729 *
5730 * Dump the XML document DTD, if any.
5731 */
5732static void
5733xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5734 if (dtd == NULL) {
5735#ifdef DEBUG_TREE
5736 xmlGenericError(xmlGenericErrorContext,
5737 "xmlDtdDump : no internal subset\n");
5738#endif
5739 return;
5740 }
5741 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5742 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5743 if (dtd->ExternalID != NULL) {
5744 xmlOutputBufferWriteString(buf, " PUBLIC ");
5745 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5746 xmlOutputBufferWriteString(buf, " ");
5747 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5748 } else if (dtd->SystemID != NULL) {
5749 xmlOutputBufferWriteString(buf, " SYSTEM ");
5750 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5751 }
5752 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5753 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5754 xmlOutputBufferWriteString(buf, ">");
5755 return;
5756 }
5757 xmlOutputBufferWriteString(buf, " [\n");
5758 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5759 xmlOutputBufferWriteString(buf, "]>");
5760}
5761
5762/**
5763 * xmlAttrDumpOutput:
5764 * @buf: the XML buffer output
5765 * @doc: the document
5766 * @cur: the attribute pointer
5767 * @encoding: an optional encoding string
5768 *
5769 * Dump an XML attribute
5770 */
5771static void
5772xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005773 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005774 xmlChar *value;
5775
5776 if (cur == NULL) {
5777#ifdef DEBUG_TREE
5778 xmlGenericError(xmlGenericErrorContext,
5779 "xmlAttrDump : property == NULL\n");
5780#endif
5781 return;
5782 }
5783 xmlOutputBufferWriteString(buf, " ");
5784 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5785 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5786 xmlOutputBufferWriteString(buf, ":");
5787 }
5788 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5789 value = xmlNodeListGetString(doc, cur->children, 0);
5790 if (value) {
5791 xmlOutputBufferWriteString(buf, "=");
5792 xmlBufferWriteQuotedString(buf->buffer, value);
5793 xmlFree(value);
5794 } else {
5795 xmlOutputBufferWriteString(buf, "=\"\"");
5796 }
5797}
5798
5799/**
5800 * xmlAttrListDumpOutput:
5801 * @buf: the XML buffer output
5802 * @doc: the document
5803 * @cur: the first attribute pointer
5804 * @encoding: an optional encoding string
5805 *
5806 * Dump a list of XML attributes
5807 */
5808static void
5809xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5810 xmlAttrPtr cur, const char *encoding) {
5811 if (cur == NULL) {
5812#ifdef DEBUG_TREE
5813 xmlGenericError(xmlGenericErrorContext,
5814 "xmlAttrListDump : property == NULL\n");
5815#endif
5816 return;
5817 }
5818 while (cur != NULL) {
5819 xmlAttrDumpOutput(buf, doc, cur, encoding);
5820 cur = cur->next;
5821 }
5822}
5823
5824
5825
5826/**
5827 * xmlNodeListDumpOutput:
5828 * @buf: the XML buffer output
5829 * @doc: the document
5830 * @cur: the first node
5831 * @level: the imbrication level for indenting
5832 * @format: is formatting allowed
5833 * @encoding: an optional encoding string
5834 *
5835 * Dump an XML node list, recursive behaviour,children are printed too.
5836 */
5837static void
5838xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5839 xmlNodePtr cur, int level, int format, const char *encoding) {
5840 int i;
5841
5842 if (cur == NULL) {
5843#ifdef DEBUG_TREE
5844 xmlGenericError(xmlGenericErrorContext,
5845 "xmlNodeListDump : node == NULL\n");
5846#endif
5847 return;
5848 }
5849 while (cur != NULL) {
5850 if ((format) && (xmlIndentTreeOutput) &&
5851 (cur->type == XML_ELEMENT_NODE))
5852 for (i = 0;i < level;i++)
5853 xmlOutputBufferWriteString(buf, " ");
5854 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5855 if (format) {
5856 xmlOutputBufferWriteString(buf, "\n");
5857 }
5858 cur = cur->next;
5859 }
5860}
5861
5862/**
5863 * xmlNodeDumpOutput:
5864 * @buf: the XML buffer output
5865 * @doc: the document
5866 * @cur: the current node
5867 * @level: the imbrication level for indenting
5868 * @format: is formatting allowed
5869 * @encoding: an optional encoding string
5870 *
5871 * Dump an XML node, recursive behaviour,children are printed too.
5872 */
5873void
5874xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5875 int level, int format, const char *encoding) {
5876 int i;
5877 xmlNodePtr tmp;
5878
5879 if (cur == NULL) {
5880#ifdef DEBUG_TREE
5881 xmlGenericError(xmlGenericErrorContext,
5882 "xmlNodeDump : node == NULL\n");
5883#endif
5884 return;
5885 }
5886 if (cur->type == XML_XINCLUDE_START)
5887 return;
5888 if (cur->type == XML_XINCLUDE_END)
5889 return;
5890 if (cur->type == XML_DTD_NODE) {
5891 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5892 return;
5893 }
5894 if (cur->type == XML_ELEMENT_DECL) {
5895 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5896 return;
5897 }
5898 if (cur->type == XML_ATTRIBUTE_DECL) {
5899 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5900 return;
5901 }
5902 if (cur->type == XML_ENTITY_DECL) {
5903 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5904 return;
5905 }
5906 if (cur->type == XML_TEXT_NODE) {
5907 if (cur->content != NULL) {
5908 if ((cur->name == xmlStringText) ||
5909 (cur->name != xmlStringTextNoenc)) {
5910 xmlChar *buffer;
5911
5912#ifndef XML_USE_BUFFER_CONTENT
5913 if (encoding == NULL)
5914 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5915 else
5916 buffer = xmlEncodeSpecialChars(doc, cur->content);
5917#else
5918 if (encoding == NULL)
5919 buffer = xmlEncodeEntitiesReentrant(doc,
5920 xmlBufferContent(cur->content));
5921 else
5922 buffer = xmlEncodeSpecialChars(doc,
5923 xmlBufferContent(cur->content));
5924#endif
5925 if (buffer != NULL) {
5926 xmlOutputBufferWriteString(buf, (const char *)buffer);
5927 xmlFree(buffer);
5928 }
5929 } else {
5930 /*
5931 * Disable escaping, needed for XSLT
5932 */
5933#ifndef XML_USE_BUFFER_CONTENT
5934 xmlOutputBufferWriteString(buf, (const char *) cur->content);
5935#else
5936 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5937#endif
5938 }
5939 }
5940
5941 return;
5942 }
5943 if (cur->type == XML_PI_NODE) {
5944 if (cur->content != NULL) {
5945 xmlOutputBufferWriteString(buf, "<?");
5946 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5947 if (cur->content != NULL) {
5948 xmlOutputBufferWriteString(buf, " ");
5949#ifndef XML_USE_BUFFER_CONTENT
5950 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5951#else
5952 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5953#endif
5954 }
5955 xmlOutputBufferWriteString(buf, "?>");
5956 } else {
5957 xmlOutputBufferWriteString(buf, "<?");
5958 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5959 xmlOutputBufferWriteString(buf, "?>");
5960 }
5961 return;
5962 }
5963 if (cur->type == XML_COMMENT_NODE) {
5964 if (cur->content != NULL) {
5965 xmlOutputBufferWriteString(buf, "<!--");
5966#ifndef XML_USE_BUFFER_CONTENT
5967 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5968#else
5969 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5970#endif
5971 xmlOutputBufferWriteString(buf, "-->");
5972 }
5973 return;
5974 }
5975 if (cur->type == XML_ENTITY_REF_NODE) {
5976 xmlOutputBufferWriteString(buf, "&");
5977 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5978 xmlOutputBufferWriteString(buf, ";");
5979 return;
5980 }
5981 if (cur->type == XML_CDATA_SECTION_NODE) {
5982 xmlOutputBufferWriteString(buf, "<![CDATA[");
5983 if (cur->content != NULL)
5984#ifndef XML_USE_BUFFER_CONTENT
5985 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5986#else
5987 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5988#endif
5989 xmlOutputBufferWriteString(buf, "]]>");
5990 return;
5991 }
5992
5993 if (format == 1) {
5994 tmp = cur->children;
5995 while (tmp != NULL) {
5996 if ((tmp->type == XML_TEXT_NODE) ||
5997 (tmp->type == XML_ENTITY_REF_NODE)) {
5998 format = 0;
5999 break;
6000 }
6001 tmp = tmp->next;
6002 }
6003 }
6004 xmlOutputBufferWriteString(buf, "<");
6005 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6006 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6007 xmlOutputBufferWriteString(buf, ":");
6008 }
6009
6010 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6011 if (cur->nsDef)
6012 xmlNsListDumpOutput(buf, cur->nsDef);
6013 if (cur->properties != NULL)
6014 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6015
Daniel Veillard7db37732001-07-12 01:20:08 +00006016 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6017 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006018 xmlOutputBufferWriteString(buf, "/>");
6019 return;
6020 }
6021 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006022 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006023 xmlChar *buffer;
6024
6025#ifndef XML_USE_BUFFER_CONTENT
6026 if (encoding == NULL)
6027 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6028 else
6029 buffer = xmlEncodeSpecialChars(doc, cur->content);
6030#else
6031 if (encoding == NULL)
6032 buffer = xmlEncodeEntitiesReentrant(doc,
6033 xmlBufferContent(cur->content));
6034 else
6035 buffer = xmlEncodeSpecialChars(doc,
6036 xmlBufferContent(cur->content));
6037#endif
6038 if (buffer != NULL) {
6039 xmlOutputBufferWriteString(buf, (const char *)buffer);
6040 xmlFree(buffer);
6041 }
6042 }
6043 if (cur->children != NULL) {
6044 if (format) xmlOutputBufferWriteString(buf, "\n");
6045 xmlNodeListDumpOutput(buf, doc, cur->children,
6046 (level >= 0?level+1:-1), format, encoding);
6047 if ((xmlIndentTreeOutput) && (format))
6048 for (i = 0;i < level;i++)
6049 xmlOutputBufferWriteString(buf, " ");
6050 }
6051 xmlOutputBufferWriteString(buf, "</");
6052 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6053 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6054 xmlOutputBufferWriteString(buf, ":");
6055 }
6056
6057 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6058 xmlOutputBufferWriteString(buf, ">");
6059}
6060
6061/**
6062 * xmlDocContentDumpOutput:
6063 * @buf: the XML buffer output
6064 * @cur: the document
6065 * @encoding: an optional encoding string
6066 * @format: should formatting spaces been added
6067 *
6068 * Dump an XML document.
6069 */
6070static void
6071xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6072 const char *encoding, int format) {
6073 xmlOutputBufferWriteString(buf, "<?xml version=");
6074 if (cur->version != NULL)
6075 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6076 else
6077 xmlOutputBufferWriteString(buf, "\"1.0\"");
6078 if (encoding == NULL) {
6079 if (cur->encoding != NULL)
6080 encoding = (const char *) cur->encoding;
6081 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6082 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6083 }
6084 if (encoding != NULL) {
6085 xmlOutputBufferWriteString(buf, " encoding=");
6086 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6087 }
6088 switch (cur->standalone) {
6089 case 0:
6090 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6091 break;
6092 case 1:
6093 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6094 break;
6095 }
6096 xmlOutputBufferWriteString(buf, "?>\n");
6097 if (cur->children != NULL) {
6098 xmlNodePtr child = cur->children;
6099
6100 while (child != NULL) {
6101 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6102 xmlOutputBufferWriteString(buf, "\n");
6103 child = child->next;
6104 }
6105 }
6106}
6107
6108/************************************************************************
6109 * *
6110 * Saving functions front-ends *
6111 * *
6112 ************************************************************************/
6113
6114/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006115 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006116 * @out_doc: Document to generate XML text from
6117 * @doc_txt_ptr: Memory pointer for allocated XML text
6118 * @doc_txt_len: Length of the generated XML text
6119 * @txt_encoding: Character encoding to use when generating XML text
6120 * @format: should formatting spaces been added
6121 *
6122 * Dump the current DOM tree into memory using the character encoding specified
6123 * by the caller. Note it is up to the caller of this function to free the
6124 * allocated memory.
6125 */
6126
6127void
6128xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006129 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006130 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006131 int dummy = 0;
6132
6133 xmlCharEncoding doc_charset;
6134 xmlOutputBufferPtr out_buff = NULL;
6135 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6136
6137 if (doc_txt_len == NULL) {
6138 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6139 }
6140
6141 if (doc_txt_ptr == NULL) {
6142 *doc_txt_len = 0;
6143 xmlGenericError(xmlGenericErrorContext,
6144 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6145 return;
6146 }
6147
6148 *doc_txt_ptr = NULL;
6149 *doc_txt_len = 0;
6150
6151 if (out_doc == NULL) {
6152 /* No document, no output */
6153 xmlGenericError(xmlGenericErrorContext,
6154 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6155 return;
6156 }
6157
6158 /*
6159 * Validate the encoding value, if provided.
6160 * This logic is copied from xmlSaveFileEnc.
6161 */
6162
6163 if (txt_encoding == NULL)
6164 txt_encoding = (const char *) out_doc->encoding;
6165 if (txt_encoding != NULL) {
6166 doc_charset = xmlParseCharEncoding(txt_encoding);
6167
6168 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6169 xmlGenericError(xmlGenericErrorContext,
6170 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6171 return;
6172
6173 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6174 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6175 if ( conv_hdlr == NULL ) {
6176 xmlGenericError(xmlGenericErrorContext,
6177 "%s: %s %s '%s'\n",
6178 "xmlDocDumpFormatMemoryEnc",
6179 "Failed to identify encoding handler for",
6180 "character set",
6181 txt_encoding);
6182 return;
6183 }
6184 }
6185 }
6186
6187 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6188 xmlGenericError(xmlGenericErrorContext,
6189 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6190 return;
6191 }
6192
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006193 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006194 xmlOutputBufferFlush(out_buff);
6195 if (out_buff->conv != NULL) {
6196 *doc_txt_len = out_buff->conv->use;
6197 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6198 } else {
6199 *doc_txt_len = out_buff->buffer->use;
6200 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6201 }
6202 (void)xmlOutputBufferClose(out_buff);
6203
6204 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6205 *doc_txt_len = 0;
6206 xmlGenericError(xmlGenericErrorContext,
6207 "xmlDocDumpFormatMemoryEnc: %s\n",
6208 "Failed to allocate memory for document text representation.");
6209 }
6210
6211 return;
6212}
6213
6214/**
6215 * xmlDocDumpMemory:
6216 * @cur: the document
6217 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006218 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006219 *
6220 * Dump an XML document in memory and return the xmlChar * and it's size.
6221 * It's up to the caller to free the memory.
6222 */
6223void
6224xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6225 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6226}
6227
6228/**
6229 * xmlDocDumpFormatMemory:
6230 * @cur: the document
6231 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006232 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006233 * @format: should formatting spaces been added
6234 *
6235 *
6236 * Dump an XML document in memory and return the xmlChar * and it's size.
6237 * It's up to the caller to free the memory.
6238 */
6239void
6240xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6241 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6242}
6243
6244/**
6245 * xmlDocDumpMemoryEnc:
6246 * @out_doc: Document to generate XML text from
6247 * @doc_txt_ptr: Memory pointer for allocated XML text
6248 * @doc_txt_len: Length of the generated XML text
6249 * @txt_encoding: Character encoding to use when generating XML text
6250 *
6251 * Dump the current DOM tree into memory using the character encoding specified
6252 * by the caller. Note it is up to the caller of this function to free the
6253 * allocated memory.
6254 */
6255
6256void
6257xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6258 int * doc_txt_len, const char * txt_encoding) {
6259 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006260 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006261}
6262
6263/**
6264 * xmlGetDocCompressMode:
6265 * @doc: the document
6266 *
6267 * get the compression ratio for a document, ZLIB based
6268 * Returns 0 (uncompressed) to 9 (max compression)
6269 */
6270int
6271xmlGetDocCompressMode (xmlDocPtr doc) {
6272 if (doc == NULL) return(-1);
6273 return(doc->compression);
6274}
6275
6276/**
6277 * xmlSetDocCompressMode:
6278 * @doc: the document
6279 * @mode: the compression ratio
6280 *
6281 * set the compression ratio for a document, ZLIB based
6282 * Correct values: 0 (uncompressed) to 9 (max compression)
6283 */
6284void
6285xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6286 if (doc == NULL) return;
6287 if (mode < 0) doc->compression = 0;
6288 else if (mode > 9) doc->compression = 9;
6289 else doc->compression = mode;
6290}
6291
6292/**
6293 * xmlGetCompressMode:
6294 *
6295 * get the default compression mode used, ZLIB based.
6296 * Returns 0 (uncompressed) to 9 (max compression)
6297 */
6298int
6299 xmlGetCompressMode(void) {
6300 return(xmlCompressMode);
6301}
6302
6303/**
6304 * xmlSetCompressMode:
6305 * @mode: the compression ratio
6306 *
6307 * set the default compression mode used, ZLIB based
6308 * Correct values: 0 (uncompressed) to 9 (max compression)
6309 */
6310void
6311xmlSetCompressMode(int mode) {
6312 if (mode < 0) xmlCompressMode = 0;
6313 else if (mode > 9) xmlCompressMode = 9;
6314 else xmlCompressMode = mode;
6315}
6316
6317/**
6318 * xmlDocDump:
6319 * @f: the FILE*
6320 * @cur: the document
6321 *
6322 * Dump an XML document to an open FILE.
6323 *
6324 * returns: the number of byte written or -1 in case of failure.
6325 */
6326int
6327xmlDocDump(FILE *f, xmlDocPtr cur) {
6328 xmlOutputBufferPtr buf;
6329 const char * encoding;
6330 xmlCharEncodingHandlerPtr handler = NULL;
6331 int ret;
6332
6333 if (cur == NULL) {
6334#ifdef DEBUG_TREE
6335 xmlGenericError(xmlGenericErrorContext,
6336 "xmlDocDump : document == NULL\n");
6337#endif
6338 return(-1);
6339 }
6340 encoding = (const char *) cur->encoding;
6341
6342 if (encoding != NULL) {
6343 xmlCharEncoding enc;
6344
6345 enc = xmlParseCharEncoding(encoding);
6346
6347 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6348 xmlGenericError(xmlGenericErrorContext,
6349 "xmlDocDump: document not in UTF8\n");
6350 return(-1);
6351 }
6352 if (enc != XML_CHAR_ENCODING_UTF8) {
6353 handler = xmlFindCharEncodingHandler(encoding);
6354 if (handler == NULL) {
6355 xmlFree((char *) cur->encoding);
6356 cur->encoding = NULL;
6357 }
6358 }
6359 }
6360 buf = xmlOutputBufferCreateFile(f, handler);
6361 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006362 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006363
6364 ret = xmlOutputBufferClose(buf);
6365 return(ret);
6366}
6367
6368/**
6369 * xmlSaveFileTo:
6370 * @buf: an output I/O buffer
6371 * @cur: the document
6372 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6373 *
6374 * Dump an XML document to an I/O buffer.
6375 *
6376 * returns: the number of byte written or -1 in case of failure.
6377 */
6378int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006379xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006380 int ret;
6381
6382 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006383 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006384 ret = xmlOutputBufferClose(buf);
6385 return(ret);
6386}
6387
6388/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006389 * xmlSaveFormatFileTo:
6390 * @buf: an output I/O buffer
6391 * @cur: the document
6392 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6393 * @format: should formatting spaces been added
6394 *
6395 * Dump an XML document to an I/O buffer.
6396 *
6397 * returns: the number of byte written or -1 in case of failure.
6398 */
6399int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006400xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006401 int ret;
6402
6403 if (buf == NULL) return(0);
6404 xmlDocContentDumpOutput(buf, cur, encoding, format);
6405 ret = xmlOutputBufferClose(buf);
6406 return(ret);
6407}
6408
6409/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006410 * xmlSaveFormatFileEnc
6411 * @filename: the filename or URL to output
6412 * @cur: the document being saved
6413 * @encoding: the name of the encoding to use or NULL.
6414 * @format: should formatting spaces be added.
Owen Taylor3473f882001-02-23 17:55:21 +00006415 */
6416int
Daniel Veillardf012a642001-07-23 19:10:52 +00006417xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6418 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006419 xmlOutputBufferPtr buf;
6420 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006421 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006422 int ret;
6423
6424 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006425
6426 enc = xmlParseCharEncoding(encoding);
6427 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6428 xmlGenericError(xmlGenericErrorContext,
6429 "xmlSaveFileEnc: document not in UTF8\n");
6430 return(-1);
6431 }
6432 if (enc != XML_CHAR_ENCODING_UTF8) {
6433 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006434 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006435 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006436 }
6437 }
6438
Daniel Veillardf012a642001-07-23 19:10:52 +00006439#ifdef HAVE_ZLIB_H
6440 if (cur->compression < 0) cur->compression = xmlCompressMode;
6441#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006442 /*
6443 * save the content to a temp buffer.
6444 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006445 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006446 if (buf == NULL) return(-1);
6447
Daniel Veillardf012a642001-07-23 19:10:52 +00006448 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006449
6450 ret = xmlOutputBufferClose(buf);
6451 return(ret);
6452}
6453
Daniel Veillardf012a642001-07-23 19:10:52 +00006454
6455/**
6456 * xmlSaveFileEnc:
6457 * @filename: the filename (or URL)
6458 * @cur: the document
6459 * @encoding: the name of an encoding (or NULL)
6460 *
6461 * Dump an XML document, converting it to the given encoding
6462 *
6463 * returns: the number of byte written or -1 in case of failure.
6464 */
6465int
6466xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6467 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6468}
6469
Owen Taylor3473f882001-02-23 17:55:21 +00006470/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006471 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006472 * @filename: the filename (or URL)
6473 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006474 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006475 *
6476 * Dump an XML document to a file. Will use compression if
6477 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillard67fee942001-04-26 18:59:03 +00006478 * used. If format is set then the document will be indented on output.
6479 *
Owen Taylor3473f882001-02-23 17:55:21 +00006480 * returns: the number of byte written or -1 in case of failure.
6481 */
6482int
Daniel Veillard67fee942001-04-26 18:59:03 +00006483xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006484 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006485}
6486
Daniel Veillard67fee942001-04-26 18:59:03 +00006487/**
6488 * xmlSaveFile:
6489 * @filename: the filename (or URL)
6490 * @cur: the document
6491 *
6492 * Dump an XML document to a file. Will use compression if
6493 * compiled in and enabled. If @filename is "-" the stdout file is
6494 * used.
6495 * returns: the number of byte written or -1 in case of failure.
6496 */
6497int
6498xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006499 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006500}
6501