blob: 241bd08ac3beb7208e7a9cbb408b81d4af81870a [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
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.
Daniel Veillardd1640922001-12-17 15:30:10 +0000118 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000119 */
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,
Daniel Veillardd1640922001-12-17 15:30:10 +0000344 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000345 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 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000416 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000417 * 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
Owen Taylor3473f882001-02-23 17:55:21 +0000485 *
486 * Free up all the structures used by a document, tree included.
487 */
488void
489xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000490 xmlDtdPtr extSubset, intSubset;
491
Owen Taylor3473f882001-02-23 17:55:21 +0000492 if (cur == NULL) {
493#ifdef DEBUG_TREE
494 xmlGenericError(xmlGenericErrorContext,
495 "xmlFreeDoc : document == NULL\n");
496#endif
497 return;
498 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000499 /*
500 * Do this before freeing the children list to avoid ID lookups
501 */
502 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
503 cur->ids = NULL;
504 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
505 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000506 extSubset = cur->extSubset;
507 intSubset = cur->intSubset;
508 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000509 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000510 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000511 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000512 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000513 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000514 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000515 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000516 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000517 }
518
519 if (cur->children != NULL) xmlFreeNodeList(cur->children);
520
Owen Taylor3473f882001-02-23 17:55:21 +0000521 if (cur->version != NULL) xmlFree((char *) cur->version);
522 if (cur->name != NULL) xmlFree((char *) cur->name);
523 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000524 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000525 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000526 xmlFree(cur);
527}
528
529/**
530 * xmlStringLenGetNodeList:
531 * @doc: the document
532 * @value: the value of the text
533 * @len: the length of the string value
534 *
535 * Parse the value string and build the node list associated. Should
536 * produce a flat tree with only TEXTs and ENTITY_REFs.
537 * Returns a pointer to the first child
538 */
539xmlNodePtr
540xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
541 xmlNodePtr ret = NULL, last = NULL;
542 xmlNodePtr node;
543 xmlChar *val;
544 const xmlChar *cur = value;
545 const xmlChar *q;
546 xmlEntityPtr ent;
547
548 if (value == NULL) return(NULL);
549
550 q = cur;
551 while ((*cur != 0) && (cur - value < len)) {
552 if (*cur == '&') {
553 /*
554 * Save the current text.
555 */
556 if (cur != q) {
557 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
558 xmlNodeAddContentLen(last, q, cur - q);
559 } else {
560 node = xmlNewDocTextLen(doc, q, cur - q);
561 if (node == NULL) return(ret);
562 if (last == NULL)
563 last = ret = node;
564 else {
565 last->next = node;
566 node->prev = last;
567 last = node;
568 }
569 }
570 }
571 /*
572 * Read the entity string
573 */
574 cur++;
575 q = cur;
576 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
577 if ((*cur == 0) || (cur - value >= len)) {
578#ifdef DEBUG_TREE
579 xmlGenericError(xmlGenericErrorContext,
580 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
581#endif
582 return(ret);
583 }
584 if (cur != q) {
585 /*
586 * Predefined entities don't generate nodes
587 */
588 val = xmlStrndup(q, cur - q);
589 ent = xmlGetDocEntity(doc, val);
590 if ((ent != NULL) &&
591 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
592 if (last == NULL) {
593 node = xmlNewDocText(doc, ent->content);
594 last = ret = node;
595 } else
596 xmlNodeAddContent(last, ent->content);
597
598 } else {
599 /*
600 * Create a new REFERENCE_REF node
601 */
602 node = xmlNewReference(doc, val);
603 if (node == NULL) {
604 if (val != NULL) xmlFree(val);
605 return(ret);
606 }
607 if (last == NULL)
608 last = ret = node;
609 else {
610 last->next = node;
611 node->prev = last;
612 last = node;
613 }
614 }
615 xmlFree(val);
616 }
617 cur++;
618 q = cur;
619 } else
620 cur++;
621 }
622 if (cur != q) {
623 /*
624 * Handle the last piece of text.
625 */
626 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
627 xmlNodeAddContentLen(last, q, cur - q);
628 } else {
629 node = xmlNewDocTextLen(doc, q, cur - q);
630 if (node == NULL) return(ret);
631 if (last == NULL)
632 last = ret = node;
633 else {
634 last->next = node;
635 node->prev = last;
636 last = node;
637 }
638 }
639 }
640 return(ret);
641}
642
643/**
644 * xmlStringGetNodeList:
645 * @doc: the document
646 * @value: the value of the attribute
647 *
648 * Parse the value string and build the node list associated. Should
649 * produce a flat tree with only TEXTs and ENTITY_REFs.
650 * Returns a pointer to the first child
651 */
652xmlNodePtr
653xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
654 xmlNodePtr ret = NULL, last = NULL;
655 xmlNodePtr node;
656 xmlChar *val;
657 const xmlChar *cur = value;
658 const xmlChar *q;
659 xmlEntityPtr ent;
660
661 if (value == NULL) return(NULL);
662
663 q = cur;
664 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000665 if (cur[0] == '&') {
666 int charval = 0;
667 xmlChar tmp;
668
Owen Taylor3473f882001-02-23 17:55:21 +0000669 /*
670 * Save the current text.
671 */
672 if (cur != q) {
673 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
674 xmlNodeAddContentLen(last, q, cur - q);
675 } else {
676 node = xmlNewDocTextLen(doc, q, cur - q);
677 if (node == NULL) return(ret);
678 if (last == NULL)
679 last = ret = node;
680 else {
681 last->next = node;
682 node->prev = last;
683 last = node;
684 }
685 }
686 }
Owen Taylor3473f882001-02-23 17:55:21 +0000687 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000688 if ((cur[1] == '#') && (cur[2] == 'x')) {
689 cur += 3;
690 tmp = *cur;
691 while (tmp != ';') { /* Non input consuming loop */
692 if ((tmp >= '0') && (tmp <= '9'))
693 charval = charval * 16 + (tmp - '0');
694 else if ((tmp >= 'a') && (tmp <= 'f'))
695 charval = charval * 16 + (tmp - 'a') + 10;
696 else if ((tmp >= 'A') && (tmp <= 'F'))
697 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000698 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000699 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000700 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000701 charval = 0;
702 break;
703 }
704 cur++;
705 tmp = *cur;
706 }
707 if (tmp == ';')
708 cur++;
709 q = cur;
710 } else if (cur[1] == '#') {
711 cur += 2;
712 tmp = *cur;
713 while (tmp != ';') { /* Non input consuming loops */
714 if ((tmp >= '0') && (tmp <= '9'))
715 charval = charval * 10 + (tmp - '0');
716 else {
717 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000718 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000719 charval = 0;
720 break;
721 }
722 cur++;
723 tmp = *cur;
724 }
725 if (tmp == ';')
726 cur++;
727 q = cur;
728 } else {
729 /*
730 * Read the entity string
731 */
732 cur++;
733 q = cur;
734 while ((*cur != 0) && (*cur != ';')) cur++;
735 if (*cur == 0) {
736#ifdef DEBUG_TREE
737 xmlGenericError(xmlGenericErrorContext,
738 "xmlStringGetNodeList: unterminated entity %30s\n", q);
739#endif
740 return(ret);
741 }
742 if (cur != q) {
743 /*
744 * Predefined entities don't generate nodes
745 */
746 val = xmlStrndup(q, cur - q);
747 ent = xmlGetDocEntity(doc, val);
748 if ((ent != NULL) &&
749 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
750 if (last == NULL) {
751 node = xmlNewDocText(doc, ent->content);
752 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000753 } else if (last->type != XML_TEXT_NODE) {
754 node = xmlNewDocText(doc, ent->content);
755 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000756 } else
757 xmlNodeAddContent(last, ent->content);
758
759 } else {
760 /*
761 * Create a new REFERENCE_REF node
762 */
763 node = xmlNewReference(doc, val);
764 if (node == NULL) {
765 if (val != NULL) xmlFree(val);
766 return(ret);
767 }
768 if (last == NULL) {
769 last = ret = node;
770 } else {
771 last = xmlAddNextSibling(last, node);
772 }
773 }
774 xmlFree(val);
775 }
776 cur++;
777 q = cur;
778 }
779 if (charval != 0) {
780 xmlChar buf[10];
781 int len;
782
783 len = xmlCopyCharMultiByte(buf, charval);
784 buf[len] = 0;
785 node = xmlNewDocText(doc, buf);
786 if (node != NULL) {
787 if (last == NULL) {
788 last = ret = node;
789 } else {
790 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000791 }
792 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000793
794 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000795 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000796 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000797 cur++;
798 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000799 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000800 /*
801 * Handle the last piece of text.
802 */
803 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
804 xmlNodeAddContentLen(last, q, cur - q);
805 } else {
806 node = xmlNewDocTextLen(doc, q, cur - q);
807 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000808 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000809 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000810 } else {
811 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000812 }
813 }
814 }
815 return(ret);
816}
817
818/**
819 * xmlNodeListGetString:
820 * @doc: the document
821 * @list: a Node list
822 * @inLine: should we replace entity contents or show their external form
823 *
824 * Returns the string equivalent to the text contained in the Node list
825 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000826 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000827 */
828xmlChar *
829xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
830 xmlNodePtr node = list;
831 xmlChar *ret = NULL;
832 xmlEntityPtr ent;
833
834 if (list == NULL) return(NULL);
835
836 while (node != NULL) {
837 if ((node->type == XML_TEXT_NODE) ||
838 (node->type == XML_CDATA_SECTION_NODE)) {
839 if (inLine) {
840#ifndef XML_USE_BUFFER_CONTENT
841 ret = xmlStrcat(ret, node->content);
842#else
843 ret = xmlStrcat(ret, xmlBufferContent(node->content));
844#endif
845 } else {
846 xmlChar *buffer;
847
848#ifndef XML_USE_BUFFER_CONTENT
849 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
850#else
851 buffer = xmlEncodeEntitiesReentrant(doc,
852 xmlBufferContent(node->content));
853#endif
854 if (buffer != NULL) {
855 ret = xmlStrcat(ret, buffer);
856 xmlFree(buffer);
857 }
858 }
859 } else if (node->type == XML_ENTITY_REF_NODE) {
860 if (inLine) {
861 ent = xmlGetDocEntity(doc, node->name);
862 if (ent != NULL)
863 ret = xmlStrcat(ret, ent->content);
864 else {
865#ifndef XML_USE_BUFFER_CONTENT
866 ret = xmlStrcat(ret, node->content);
867#else
868 ret = xmlStrcat(ret, xmlBufferContent(node->content));
869#endif
870 }
871 } else {
872 xmlChar buf[2];
873 buf[0] = '&'; buf[1] = 0;
874 ret = xmlStrncat(ret, buf, 1);
875 ret = xmlStrcat(ret, node->name);
876 buf[0] = ';'; buf[1] = 0;
877 ret = xmlStrncat(ret, buf, 1);
878 }
879 }
880#if 0
881 else {
882 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000883 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000884 node->type);
885 }
886#endif
887 node = node->next;
888 }
889 return(ret);
890}
891
892/**
893 * xmlNodeListGetRawString:
894 * @doc: the document
895 * @list: a Node list
896 * @inLine: should we replace entity contents or show their external form
897 *
898 * Returns the string equivalent to the text contained in the Node list
899 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
900 * this function doesn't do any character encoding handling.
901 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000902 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000903 */
904xmlChar *
905xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
906 xmlNodePtr node = list;
907 xmlChar *ret = NULL;
908 xmlEntityPtr ent;
909
910 if (list == NULL) return(NULL);
911
912 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000913 if ((node->type == XML_TEXT_NODE) ||
914 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000915 if (inLine) {
916#ifndef XML_USE_BUFFER_CONTENT
917 ret = xmlStrcat(ret, node->content);
918#else
919 ret = xmlStrcat(ret, xmlBufferContent(node->content));
920#endif
921 } else {
922 xmlChar *buffer;
923
924#ifndef XML_USE_BUFFER_CONTENT
925 buffer = xmlEncodeSpecialChars(doc, node->content);
926#else
927 buffer = xmlEncodeSpecialChars(doc,
928 xmlBufferContent(node->content));
929#endif
930 if (buffer != NULL) {
931 ret = xmlStrcat(ret, buffer);
932 xmlFree(buffer);
933 }
934 }
935 } else if (node->type == XML_ENTITY_REF_NODE) {
936 if (inLine) {
937 ent = xmlGetDocEntity(doc, node->name);
938 if (ent != NULL)
939 ret = xmlStrcat(ret, ent->content);
940 else {
941#ifndef XML_USE_BUFFER_CONTENT
942 ret = xmlStrcat(ret, node->content);
943#else
944 ret = xmlStrcat(ret, xmlBufferContent(node->content));
945#endif
946 }
947 } else {
948 xmlChar buf[2];
949 buf[0] = '&'; buf[1] = 0;
950 ret = xmlStrncat(ret, buf, 1);
951 ret = xmlStrcat(ret, node->name);
952 buf[0] = ';'; buf[1] = 0;
953 ret = xmlStrncat(ret, buf, 1);
954 }
955 }
956#if 0
957 else {
958 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000959 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000960 node->type);
961 }
962#endif
963 node = node->next;
964 }
965 return(ret);
966}
967
968/**
969 * xmlNewProp:
970 * @node: the holding node
971 * @name: the name of the attribute
972 * @value: the value of the attribute
973 *
974 * Create a new property carried by a node.
975 * Returns a pointer to the attribute
976 */
977xmlAttrPtr
978xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
979 xmlAttrPtr cur;
980 xmlDocPtr doc = NULL;
981
982 if (name == NULL) {
983#ifdef DEBUG_TREE
984 xmlGenericError(xmlGenericErrorContext,
985 "xmlNewProp : name == NULL\n");
986#endif
987 return(NULL);
988 }
989
990 /*
991 * Allocate a new property and fill the fields.
992 */
993 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
994 if (cur == NULL) {
995 xmlGenericError(xmlGenericErrorContext,
996 "xmlNewProp : malloc failed\n");
997 return(NULL);
998 }
999 memset(cur, 0, sizeof(xmlAttr));
1000 cur->type = XML_ATTRIBUTE_NODE;
1001
1002 cur->parent = node;
1003 if (node != NULL) {
1004 doc = node->doc;
1005 cur->doc = doc;
1006 }
1007 cur->name = xmlStrdup(name);
1008 if (value != NULL) {
1009 xmlChar *buffer;
1010 xmlNodePtr tmp;
1011
1012 buffer = xmlEncodeEntitiesReentrant(doc, value);
1013 cur->children = xmlStringGetNodeList(doc, buffer);
1014 cur->last = NULL;
1015 tmp = cur->children;
1016 while (tmp != NULL) {
1017 tmp->parent = (xmlNodePtr) cur;
1018 tmp->doc = doc;
1019 if (tmp->next == NULL)
1020 cur->last = tmp;
1021 tmp = tmp->next;
1022 }
1023 xmlFree(buffer);
1024 }
1025
1026 /*
1027 * Add it at the end to preserve parsing order ...
1028 */
1029 if (node != NULL) {
1030 if (node->properties == NULL) {
1031 node->properties = cur;
1032 } else {
1033 xmlAttrPtr prev = node->properties;
1034
1035 while (prev->next != NULL) prev = prev->next;
1036 prev->next = cur;
1037 cur->prev = prev;
1038 }
1039 }
1040 return(cur);
1041}
1042
1043/**
1044 * xmlNewNsProp:
1045 * @node: the holding node
1046 * @ns: the namespace
1047 * @name: the name of the attribute
1048 * @value: the value of the attribute
1049 *
1050 * Create a new property tagged with a namespace and carried by a node.
1051 * Returns a pointer to the attribute
1052 */
1053xmlAttrPtr
1054xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1055 const xmlChar *value) {
1056 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001057 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001058
1059 if (name == NULL) {
1060#ifdef DEBUG_TREE
1061 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001062 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001063#endif
1064 return(NULL);
1065 }
1066
1067 /*
1068 * Allocate a new property and fill the fields.
1069 */
1070 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1071 if (cur == NULL) {
1072 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001073 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001074 return(NULL);
1075 }
1076 memset(cur, 0, sizeof(xmlAttr));
1077 cur->type = XML_ATTRIBUTE_NODE;
1078
1079 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001080 if (node != NULL) {
1081 doc = node->doc;
1082 cur->doc = doc;
1083 }
Owen Taylor3473f882001-02-23 17:55:21 +00001084 cur->ns = ns;
1085 cur->name = xmlStrdup(name);
1086 if (value != NULL) {
1087 xmlChar *buffer;
1088 xmlNodePtr tmp;
1089
Daniel Veillarda682b212001-06-07 19:59:42 +00001090 buffer = xmlEncodeEntitiesReentrant(doc, value);
1091 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001092 cur->last = NULL;
1093 tmp = cur->children;
1094 while (tmp != NULL) {
1095 tmp->parent = (xmlNodePtr) cur;
1096 if (tmp->next == NULL)
1097 cur->last = tmp;
1098 tmp = tmp->next;
1099 }
1100 xmlFree(buffer);
1101 }
1102
1103 /*
1104 * Add it at the end to preserve parsing order ...
1105 */
1106 if (node != NULL) {
1107 if (node->properties == NULL) {
1108 node->properties = cur;
1109 } else {
1110 xmlAttrPtr prev = node->properties;
1111
1112 while (prev->next != NULL) prev = prev->next;
1113 prev->next = cur;
1114 cur->prev = prev;
1115 }
1116 }
1117 return(cur);
1118}
1119
1120/**
1121 * xmlNewDocProp:
1122 * @doc: the document
1123 * @name: the name of the attribute
1124 * @value: the value of the attribute
1125 *
1126 * Create a new property carried by a document.
1127 * Returns a pointer to the attribute
1128 */
1129xmlAttrPtr
1130xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1131 xmlAttrPtr cur;
1132
1133 if (name == NULL) {
1134#ifdef DEBUG_TREE
1135 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001136 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001137#endif
1138 return(NULL);
1139 }
1140
1141 /*
1142 * Allocate a new property and fill the fields.
1143 */
1144 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1145 if (cur == NULL) {
1146 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001147 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001148 return(NULL);
1149 }
1150 memset(cur, 0, sizeof(xmlAttr));
1151 cur->type = XML_ATTRIBUTE_NODE;
1152
1153 cur->name = xmlStrdup(name);
1154 cur->doc = doc;
1155 if (value != NULL) {
1156 xmlNodePtr tmp;
1157
1158 cur->children = xmlStringGetNodeList(doc, value);
1159 cur->last = NULL;
1160
1161 tmp = cur->children;
1162 while (tmp != NULL) {
1163 tmp->parent = (xmlNodePtr) cur;
1164 if (tmp->next == NULL)
1165 cur->last = tmp;
1166 tmp = tmp->next;
1167 }
1168 }
1169 return(cur);
1170}
1171
1172/**
1173 * xmlFreePropList:
1174 * @cur: the first property in the list
1175 *
1176 * Free a property and all its siblings, all the children are freed too.
1177 */
1178void
1179xmlFreePropList(xmlAttrPtr cur) {
1180 xmlAttrPtr next;
1181 if (cur == NULL) {
1182#ifdef DEBUG_TREE
1183 xmlGenericError(xmlGenericErrorContext,
1184 "xmlFreePropList : property == NULL\n");
1185#endif
1186 return;
1187 }
1188 while (cur != NULL) {
1189 next = cur->next;
1190 xmlFreeProp(cur);
1191 cur = next;
1192 }
1193}
1194
1195/**
1196 * xmlFreeProp:
1197 * @cur: an attribute
1198 *
1199 * Free one attribute, all the content is freed too
1200 */
1201void
1202xmlFreeProp(xmlAttrPtr cur) {
1203 if (cur == NULL) {
1204#ifdef DEBUG_TREE
1205 xmlGenericError(xmlGenericErrorContext,
1206 "xmlFreeProp : property == NULL\n");
1207#endif
1208 return;
1209 }
1210 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001211 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1212 ((cur->parent->doc->intSubset != NULL) ||
1213 (cur->parent->doc->extSubset != NULL))) {
1214 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1215 xmlRemoveID(cur->parent->doc, cur);
1216 }
Owen Taylor3473f882001-02-23 17:55:21 +00001217 if (cur->name != NULL) xmlFree((char *) cur->name);
1218 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001219 xmlFree(cur);
1220}
1221
1222/**
1223 * xmlRemoveProp:
1224 * @cur: an attribute
1225 *
1226 * Unlink and free one attribute, all the content is freed too
1227 * Note this doesn't work for namespace definition attributes
1228 *
1229 * Returns 0 if success and -1 in case of error.
1230 */
1231int
1232xmlRemoveProp(xmlAttrPtr cur) {
1233 xmlAttrPtr tmp;
1234 if (cur == NULL) {
1235#ifdef DEBUG_TREE
1236 xmlGenericError(xmlGenericErrorContext,
1237 "xmlRemoveProp : cur == NULL\n");
1238#endif
1239 return(-1);
1240 }
1241 if (cur->parent == NULL) {
1242#ifdef DEBUG_TREE
1243 xmlGenericError(xmlGenericErrorContext,
1244 "xmlRemoveProp : cur->parent == NULL\n");
1245#endif
1246 return(-1);
1247 }
1248 tmp = cur->parent->properties;
1249 if (tmp == cur) {
1250 cur->parent->properties = cur->next;
1251 xmlFreeProp(cur);
1252 return(0);
1253 }
1254 while (tmp != NULL) {
1255 if (tmp->next == cur) {
1256 tmp->next = cur->next;
1257 if (tmp->next != NULL)
1258 tmp->next->prev = tmp;
1259 xmlFreeProp(cur);
1260 return(0);
1261 }
1262 tmp = tmp->next;
1263 }
1264#ifdef DEBUG_TREE
1265 xmlGenericError(xmlGenericErrorContext,
1266 "xmlRemoveProp : attribute not owned by its node\n");
1267#endif
1268 return(-1);
1269}
1270
1271/**
1272 * xmlNewPI:
1273 * @name: the processing instruction name
1274 * @content: the PI content
1275 *
1276 * Creation of a processing instruction element.
1277 * Returns a pointer to the new node object.
1278 */
1279xmlNodePtr
1280xmlNewPI(const xmlChar *name, const xmlChar *content) {
1281 xmlNodePtr cur;
1282
1283 if (name == NULL) {
1284#ifdef DEBUG_TREE
1285 xmlGenericError(xmlGenericErrorContext,
1286 "xmlNewPI : name == NULL\n");
1287#endif
1288 return(NULL);
1289 }
1290
1291 /*
1292 * Allocate a new node and fill the fields.
1293 */
1294 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1295 if (cur == NULL) {
1296 xmlGenericError(xmlGenericErrorContext,
1297 "xmlNewPI : malloc failed\n");
1298 return(NULL);
1299 }
1300 memset(cur, 0, sizeof(xmlNode));
1301 cur->type = XML_PI_NODE;
1302
1303 cur->name = xmlStrdup(name);
1304 if (content != NULL) {
1305#ifndef XML_USE_BUFFER_CONTENT
1306 cur->content = xmlStrdup(content);
1307#else
1308 cur->content = xmlBufferCreateSize(0);
1309 xmlBufferSetAllocationScheme(cur->content,
1310 xmlGetBufferAllocationScheme());
1311 xmlBufferAdd(cur->content, content, -1);
1312#endif
1313 }
1314 return(cur);
1315}
1316
1317/**
1318 * xmlNewNode:
1319 * @ns: namespace if any
1320 * @name: the node name
1321 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001322 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001323 *
1324 * Returns a pointer to the new node object.
1325 */
1326xmlNodePtr
1327xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1328 xmlNodePtr cur;
1329
1330 if (name == NULL) {
1331#ifdef DEBUG_TREE
1332 xmlGenericError(xmlGenericErrorContext,
1333 "xmlNewNode : name == NULL\n");
1334#endif
1335 return(NULL);
1336 }
1337
1338 /*
1339 * Allocate a new node and fill the fields.
1340 */
1341 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1342 if (cur == NULL) {
1343 xmlGenericError(xmlGenericErrorContext,
1344 "xmlNewNode : malloc failed\n");
1345 return(NULL);
1346 }
1347 memset(cur, 0, sizeof(xmlNode));
1348 cur->type = XML_ELEMENT_NODE;
1349
1350 cur->name = xmlStrdup(name);
1351 cur->ns = ns;
1352 return(cur);
1353}
1354
1355/**
1356 * xmlNewDocNode:
1357 * @doc: the document
1358 * @ns: namespace if any
1359 * @name: the node name
1360 * @content: the XML text content if any
1361 *
1362 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001363 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001364 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1365 * references, but XML special chars need to be escaped first by using
1366 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1367 * need entities support.
1368 *
1369 * Returns a pointer to the new node object.
1370 */
1371xmlNodePtr
1372xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1373 const xmlChar *name, const xmlChar *content) {
1374 xmlNodePtr cur;
1375
1376 cur = xmlNewNode(ns, name);
1377 if (cur != NULL) {
1378 cur->doc = doc;
1379 if (content != NULL) {
1380 cur->children = xmlStringGetNodeList(doc, content);
1381 UPDATE_LAST_CHILD_AND_PARENT(cur)
1382 }
1383 }
1384 return(cur);
1385}
1386
1387
1388/**
1389 * xmlNewDocRawNode:
1390 * @doc: the document
1391 * @ns: namespace if any
1392 * @name: the node name
1393 * @content: the text content if any
1394 *
1395 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001396 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001397 *
1398 * Returns a pointer to the new node object.
1399 */
1400xmlNodePtr
1401xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1402 const xmlChar *name, const xmlChar *content) {
1403 xmlNodePtr cur;
1404
1405 cur = xmlNewNode(ns, name);
1406 if (cur != NULL) {
1407 cur->doc = doc;
1408 if (content != NULL) {
1409 cur->children = xmlNewDocText(doc, content);
1410 UPDATE_LAST_CHILD_AND_PARENT(cur)
1411 }
1412 }
1413 return(cur);
1414}
1415
1416/**
1417 * xmlNewDocFragment:
1418 * @doc: the document owning the fragment
1419 *
1420 * Creation of a new Fragment node.
1421 * Returns a pointer to the new node object.
1422 */
1423xmlNodePtr
1424xmlNewDocFragment(xmlDocPtr doc) {
1425 xmlNodePtr cur;
1426
1427 /*
1428 * Allocate a new DocumentFragment node and fill the fields.
1429 */
1430 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1431 if (cur == NULL) {
1432 xmlGenericError(xmlGenericErrorContext,
1433 "xmlNewDocFragment : malloc failed\n");
1434 return(NULL);
1435 }
1436 memset(cur, 0, sizeof(xmlNode));
1437 cur->type = XML_DOCUMENT_FRAG_NODE;
1438
1439 cur->doc = doc;
1440 return(cur);
1441}
1442
1443/**
1444 * xmlNewText:
1445 * @content: the text content
1446 *
1447 * Creation of a new text node.
1448 * Returns a pointer to the new node object.
1449 */
1450xmlNodePtr
1451xmlNewText(const xmlChar *content) {
1452 xmlNodePtr cur;
1453
1454 /*
1455 * Allocate a new node and fill the fields.
1456 */
1457 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1458 if (cur == NULL) {
1459 xmlGenericError(xmlGenericErrorContext,
1460 "xmlNewText : malloc failed\n");
1461 return(NULL);
1462 }
1463 memset(cur, 0, sizeof(xmlNode));
1464 cur->type = XML_TEXT_NODE;
1465
1466 cur->name = xmlStringText;
1467 if (content != NULL) {
1468#ifndef XML_USE_BUFFER_CONTENT
1469 cur->content = xmlStrdup(content);
1470#else
1471 cur->content = xmlBufferCreateSize(0);
1472 xmlBufferSetAllocationScheme(cur->content,
1473 xmlGetBufferAllocationScheme());
1474 xmlBufferAdd(cur->content, content, -1);
1475#endif
1476 }
1477 return(cur);
1478}
1479
1480/**
1481 * xmlNewTextChild:
1482 * @parent: the parent node
1483 * @ns: a namespace if any
1484 * @name: the name of the child
1485 * @content: the text content of the child if any.
1486 *
1487 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001488 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001489 * a child TEXT node will be created containing the string content.
1490 *
1491 * Returns a pointer to the new node object.
1492 */
1493xmlNodePtr
1494xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1495 const xmlChar *name, const xmlChar *content) {
1496 xmlNodePtr cur, prev;
1497
1498 if (parent == NULL) {
1499#ifdef DEBUG_TREE
1500 xmlGenericError(xmlGenericErrorContext,
1501 "xmlNewTextChild : parent == NULL\n");
1502#endif
1503 return(NULL);
1504 }
1505
1506 if (name == NULL) {
1507#ifdef DEBUG_TREE
1508 xmlGenericError(xmlGenericErrorContext,
1509 "xmlNewTextChild : name == NULL\n");
1510#endif
1511 return(NULL);
1512 }
1513
1514 /*
1515 * Allocate a new node
1516 */
1517 if (ns == NULL)
1518 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1519 else
1520 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1521 if (cur == NULL) return(NULL);
1522
1523 /*
1524 * add the new element at the end of the children list.
1525 */
1526 cur->type = XML_ELEMENT_NODE;
1527 cur->parent = parent;
1528 cur->doc = parent->doc;
1529 if (parent->children == NULL) {
1530 parent->children = cur;
1531 parent->last = cur;
1532 } else {
1533 prev = parent->last;
1534 prev->next = cur;
1535 cur->prev = prev;
1536 parent->last = cur;
1537 }
1538
1539 return(cur);
1540}
1541
1542/**
1543 * xmlNewCharRef:
1544 * @doc: the document
1545 * @name: the char ref string, starting with # or "&# ... ;"
1546 *
1547 * Creation of a new character reference node.
1548 * Returns a pointer to the new node object.
1549 */
1550xmlNodePtr
1551xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1552 xmlNodePtr cur;
1553
1554 /*
1555 * Allocate a new node and fill the fields.
1556 */
1557 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1558 if (cur == NULL) {
1559 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001560 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001561 return(NULL);
1562 }
1563 memset(cur, 0, sizeof(xmlNode));
1564 cur->type = XML_ENTITY_REF_NODE;
1565
1566 cur->doc = doc;
1567 if (name[0] == '&') {
1568 int len;
1569 name++;
1570 len = xmlStrlen(name);
1571 if (name[len - 1] == ';')
1572 cur->name = xmlStrndup(name, len - 1);
1573 else
1574 cur->name = xmlStrndup(name, len);
1575 } else
1576 cur->name = xmlStrdup(name);
1577 return(cur);
1578}
1579
1580/**
1581 * xmlNewReference:
1582 * @doc: the document
1583 * @name: the reference name, or the reference string with & and ;
1584 *
1585 * Creation of a new reference node.
1586 * Returns a pointer to the new node object.
1587 */
1588xmlNodePtr
1589xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1590 xmlNodePtr cur;
1591 xmlEntityPtr ent;
1592
1593 /*
1594 * Allocate a new node and fill the fields.
1595 */
1596 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1597 if (cur == NULL) {
1598 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001599 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001600 return(NULL);
1601 }
1602 memset(cur, 0, sizeof(xmlNode));
1603 cur->type = XML_ENTITY_REF_NODE;
1604
1605 cur->doc = doc;
1606 if (name[0] == '&') {
1607 int len;
1608 name++;
1609 len = xmlStrlen(name);
1610 if (name[len - 1] == ';')
1611 cur->name = xmlStrndup(name, len - 1);
1612 else
1613 cur->name = xmlStrndup(name, len);
1614 } else
1615 cur->name = xmlStrdup(name);
1616
1617 ent = xmlGetDocEntity(doc, cur->name);
1618 if (ent != NULL) {
1619#ifndef XML_USE_BUFFER_CONTENT
1620 cur->content = ent->content;
1621#else
1622 /*
1623 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1624 * a copy of this pointer. Let's hope we don't manipulate it
1625 * later
1626 */
1627 cur->content = xmlBufferCreateSize(0);
1628 xmlBufferSetAllocationScheme(cur->content,
1629 xmlGetBufferAllocationScheme());
1630 if (ent->content != NULL)
1631 xmlBufferAdd(cur->content, ent->content, -1);
1632#endif
1633 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001634 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001635 * updated. Not sure if this is 100% correct.
1636 * -George
1637 */
1638 cur->children = (xmlNodePtr) ent;
1639 cur->last = (xmlNodePtr) ent;
1640 }
1641 return(cur);
1642}
1643
1644/**
1645 * xmlNewDocText:
1646 * @doc: the document
1647 * @content: the text content
1648 *
1649 * Creation of a new text node within a document.
1650 * Returns a pointer to the new node object.
1651 */
1652xmlNodePtr
1653xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1654 xmlNodePtr cur;
1655
1656 cur = xmlNewText(content);
1657 if (cur != NULL) cur->doc = doc;
1658 return(cur);
1659}
1660
1661/**
1662 * xmlNewTextLen:
1663 * @content: the text content
1664 * @len: the text len.
1665 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001666 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001667 * Returns a pointer to the new node object.
1668 */
1669xmlNodePtr
1670xmlNewTextLen(const xmlChar *content, int len) {
1671 xmlNodePtr cur;
1672
1673 /*
1674 * Allocate a new node and fill the fields.
1675 */
1676 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1677 if (cur == NULL) {
1678 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001679 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001680 return(NULL);
1681 }
1682 memset(cur, 0, sizeof(xmlNode));
1683 cur->type = XML_TEXT_NODE;
1684
1685 cur->name = xmlStringText;
1686 if (content != NULL) {
1687#ifndef XML_USE_BUFFER_CONTENT
1688 cur->content = xmlStrndup(content, len);
1689#else
1690 cur->content = xmlBufferCreateSize(len);
1691 xmlBufferSetAllocationScheme(cur->content,
1692 xmlGetBufferAllocationScheme());
1693 xmlBufferAdd(cur->content, content, len);
1694#endif
1695 }
1696 return(cur);
1697}
1698
1699/**
1700 * xmlNewDocTextLen:
1701 * @doc: the document
1702 * @content: the text content
1703 * @len: the text len.
1704 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001705 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001706 * text node pertain to a given document.
1707 * Returns a pointer to the new node object.
1708 */
1709xmlNodePtr
1710xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1711 xmlNodePtr cur;
1712
1713 cur = xmlNewTextLen(content, len);
1714 if (cur != NULL) cur->doc = doc;
1715 return(cur);
1716}
1717
1718/**
1719 * xmlNewComment:
1720 * @content: the comment content
1721 *
1722 * Creation of a new node containing a comment.
1723 * Returns a pointer to the new node object.
1724 */
1725xmlNodePtr
1726xmlNewComment(const xmlChar *content) {
1727 xmlNodePtr cur;
1728
1729 /*
1730 * Allocate a new node and fill the fields.
1731 */
1732 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1733 if (cur == NULL) {
1734 xmlGenericError(xmlGenericErrorContext,
1735 "xmlNewComment : malloc failed\n");
1736 return(NULL);
1737 }
1738 memset(cur, 0, sizeof(xmlNode));
1739 cur->type = XML_COMMENT_NODE;
1740
1741 cur->name = xmlStringComment;
1742 if (content != NULL) {
1743#ifndef XML_USE_BUFFER_CONTENT
1744 cur->content = xmlStrdup(content);
1745#else
1746 cur->content = xmlBufferCreateSize(0);
1747 xmlBufferSetAllocationScheme(cur->content,
1748 xmlGetBufferAllocationScheme());
1749 xmlBufferAdd(cur->content, content, -1);
1750#endif
1751 }
1752 return(cur);
1753}
1754
1755/**
1756 * xmlNewCDataBlock:
1757 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001758 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001759 * @len: the length of the block
1760 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001761 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001762 * Returns a pointer to the new node object.
1763 */
1764xmlNodePtr
1765xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1766 xmlNodePtr cur;
1767
1768 /*
1769 * Allocate a new node and fill the fields.
1770 */
1771 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1772 if (cur == NULL) {
1773 xmlGenericError(xmlGenericErrorContext,
1774 "xmlNewCDataBlock : malloc failed\n");
1775 return(NULL);
1776 }
1777 memset(cur, 0, sizeof(xmlNode));
1778 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001779 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001780
1781 if (content != NULL) {
1782#ifndef XML_USE_BUFFER_CONTENT
1783 cur->content = xmlStrndup(content, len);
1784#else
1785 cur->content = xmlBufferCreateSize(len);
1786 xmlBufferSetAllocationScheme(cur->content,
1787 xmlGetBufferAllocationScheme());
1788 xmlBufferAdd(cur->content, content, len);
1789#endif
1790 }
1791 return(cur);
1792}
1793
1794/**
1795 * xmlNewDocComment:
1796 * @doc: the document
1797 * @content: the comment content
1798 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001799 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001800 * Returns a pointer to the new node object.
1801 */
1802xmlNodePtr
1803xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1804 xmlNodePtr cur;
1805
1806 cur = xmlNewComment(content);
1807 if (cur != NULL) cur->doc = doc;
1808 return(cur);
1809}
1810
1811/**
1812 * xmlSetTreeDoc:
1813 * @tree: the top element
1814 * @doc: the document
1815 *
1816 * update all nodes under the tree to point to the right document
1817 */
1818void
1819xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001820 xmlAttrPtr prop;
1821
Owen Taylor3473f882001-02-23 17:55:21 +00001822 if (tree == NULL)
1823 return;
1824 if (tree->type == XML_ENTITY_DECL)
1825 return;
1826 if (tree->doc != doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001827 prop = tree->properties;
1828 while (prop != NULL) {
1829 prop->doc = doc;
1830 xmlSetListDoc(prop->children, doc);
1831 prop = prop->next;
1832 }
Owen Taylor3473f882001-02-23 17:55:21 +00001833 if (tree->children != NULL)
1834 xmlSetListDoc(tree->children, doc);
1835 tree->doc = doc;
1836 }
1837}
1838
1839/**
1840 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001841 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001842 * @doc: the document
1843 *
1844 * update all nodes in the list to point to the right document
1845 */
1846void
1847xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1848 xmlNodePtr cur;
1849
1850 if (list == NULL)
1851 return;
1852 cur = list;
1853 while (cur != NULL) {
1854 if (cur->doc != doc)
1855 xmlSetTreeDoc(cur, doc);
1856 cur = cur->next;
1857 }
1858}
1859
1860
1861/**
1862 * xmlNewChild:
1863 * @parent: the parent node
1864 * @ns: a namespace if any
1865 * @name: the name of the child
1866 * @content: the XML content of the child if any.
1867 *
1868 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001869 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001870 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1871 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1872 * references, but XML special chars need to be escaped first by using
1873 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1874 * support is not needed.
1875 *
1876 * Returns a pointer to the new node object.
1877 */
1878xmlNodePtr
1879xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1880 const xmlChar *name, const xmlChar *content) {
1881 xmlNodePtr cur, prev;
1882
1883 if (parent == NULL) {
1884#ifdef DEBUG_TREE
1885 xmlGenericError(xmlGenericErrorContext,
1886 "xmlNewChild : parent == NULL\n");
1887#endif
1888 return(NULL);
1889 }
1890
1891 if (name == NULL) {
1892#ifdef DEBUG_TREE
1893 xmlGenericError(xmlGenericErrorContext,
1894 "xmlNewChild : name == NULL\n");
1895#endif
1896 return(NULL);
1897 }
1898
1899 /*
1900 * Allocate a new node
1901 */
1902 if (ns == NULL)
1903 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1904 else
1905 cur = xmlNewDocNode(parent->doc, ns, name, content);
1906 if (cur == NULL) return(NULL);
1907
1908 /*
1909 * add the new element at the end of the children list.
1910 */
1911 cur->type = XML_ELEMENT_NODE;
1912 cur->parent = parent;
1913 cur->doc = parent->doc;
1914 if (parent->children == NULL) {
1915 parent->children = cur;
1916 parent->last = cur;
1917 } else {
1918 prev = parent->last;
1919 prev->next = cur;
1920 cur->prev = prev;
1921 parent->last = cur;
1922 }
1923
1924 return(cur);
1925}
1926
1927/**
1928 * xmlAddNextSibling:
1929 * @cur: the child node
1930 * @elem: the new node
1931 *
1932 * Add a new element @elem as the next siblings of @cur
1933 * If the new element was already inserted in a document it is
1934 * first unlinked from its existing context.
1935 * As a result of text merging @elem may be freed.
1936 *
1937 * Returns the new element or NULL in case of error.
1938 */
1939xmlNodePtr
1940xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1941 if (cur == NULL) {
1942#ifdef DEBUG_TREE
1943 xmlGenericError(xmlGenericErrorContext,
1944 "xmlAddNextSibling : cur == NULL\n");
1945#endif
1946 return(NULL);
1947 }
1948 if (elem == NULL) {
1949#ifdef DEBUG_TREE
1950 xmlGenericError(xmlGenericErrorContext,
1951 "xmlAddNextSibling : elem == NULL\n");
1952#endif
1953 return(NULL);
1954 }
1955
1956 xmlUnlinkNode(elem);
1957
1958 if (elem->type == XML_TEXT_NODE) {
1959 if (cur->type == XML_TEXT_NODE) {
1960#ifndef XML_USE_BUFFER_CONTENT
1961 xmlNodeAddContent(cur, elem->content);
1962#else
1963 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1964#endif
1965 xmlFreeNode(elem);
1966 return(cur);
1967 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001968 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1969 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001970#ifndef XML_USE_BUFFER_CONTENT
1971 xmlChar *tmp;
1972
1973 tmp = xmlStrdup(elem->content);
1974 tmp = xmlStrcat(tmp, cur->next->content);
1975 xmlNodeSetContent(cur->next, tmp);
1976 xmlFree(tmp);
1977#else
1978 xmlBufferAddHead(cur->next->content,
1979 xmlBufferContent(elem->content),
1980 xmlBufferLength(elem->content));
1981#endif
1982 xmlFreeNode(elem);
1983 return(cur->next);
1984 }
1985 }
1986
1987 if (elem->doc != cur->doc) {
1988 xmlSetTreeDoc(elem, cur->doc);
1989 }
1990 elem->parent = cur->parent;
1991 elem->prev = cur;
1992 elem->next = cur->next;
1993 cur->next = elem;
1994 if (elem->next != NULL)
1995 elem->next->prev = elem;
1996 if ((elem->parent != NULL) && (elem->parent->last == cur))
1997 elem->parent->last = elem;
1998 return(elem);
1999}
2000
2001/**
2002 * xmlAddPrevSibling:
2003 * @cur: the child node
2004 * @elem: the new node
2005 *
2006 * Add a new element @elem as the previous siblings of @cur
2007 * merging adjacent TEXT nodes (@elem may be freed)
2008 * If the new element was already inserted in a document it is
2009 * first unlinked from its existing context.
2010 *
2011 * Returns the new element or NULL in case of error.
2012 */
2013xmlNodePtr
2014xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2015 if (cur == NULL) {
2016#ifdef DEBUG_TREE
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlAddPrevSibling : cur == NULL\n");
2019#endif
2020 return(NULL);
2021 }
2022 if (elem == NULL) {
2023#ifdef DEBUG_TREE
2024 xmlGenericError(xmlGenericErrorContext,
2025 "xmlAddPrevSibling : elem == NULL\n");
2026#endif
2027 return(NULL);
2028 }
2029
2030 xmlUnlinkNode(elem);
2031
2032 if (elem->type == XML_TEXT_NODE) {
2033 if (cur->type == XML_TEXT_NODE) {
2034#ifndef XML_USE_BUFFER_CONTENT
2035 xmlChar *tmp;
2036
2037 tmp = xmlStrdup(elem->content);
2038 tmp = xmlStrcat(tmp, cur->content);
2039 xmlNodeSetContent(cur, tmp);
2040 xmlFree(tmp);
2041#else
2042 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2043 xmlBufferLength(elem->content));
2044#endif
2045 xmlFreeNode(elem);
2046 return(cur);
2047 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002048 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2049 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002050#ifndef XML_USE_BUFFER_CONTENT
2051 xmlNodeAddContent(cur->prev, elem->content);
2052#else
2053 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2054#endif
2055 xmlFreeNode(elem);
2056 return(cur->prev);
2057 }
2058 }
2059
2060 if (elem->doc != cur->doc) {
2061 xmlSetTreeDoc(elem, cur->doc);
2062 }
2063 elem->parent = cur->parent;
2064 elem->next = cur;
2065 elem->prev = cur->prev;
2066 cur->prev = elem;
2067 if (elem->prev != NULL)
2068 elem->prev->next = elem;
2069 if ((elem->parent != NULL) && (elem->parent->children == cur))
2070 elem->parent->children = elem;
2071 return(elem);
2072}
2073
2074/**
2075 * xmlAddSibling:
2076 * @cur: the child node
2077 * @elem: the new node
2078 *
2079 * Add a new element @elem to the list of siblings of @cur
2080 * merging adjacent TEXT nodes (@elem may be freed)
2081 * If the new element was already inserted in a document it is
2082 * first unlinked from its existing context.
2083 *
2084 * Returns the new element or NULL in case of error.
2085 */
2086xmlNodePtr
2087xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2088 xmlNodePtr parent;
2089
2090 if (cur == NULL) {
2091#ifdef DEBUG_TREE
2092 xmlGenericError(xmlGenericErrorContext,
2093 "xmlAddSibling : cur == NULL\n");
2094#endif
2095 return(NULL);
2096 }
2097
2098 if (elem == NULL) {
2099#ifdef DEBUG_TREE
2100 xmlGenericError(xmlGenericErrorContext,
2101 "xmlAddSibling : elem == NULL\n");
2102#endif
2103 return(NULL);
2104 }
2105
2106 /*
2107 * Constant time is we can rely on the ->parent->last to find
2108 * the last sibling.
2109 */
2110 if ((cur->parent != NULL) &&
2111 (cur->parent->children != NULL) &&
2112 (cur->parent->last != NULL) &&
2113 (cur->parent->last->next == NULL)) {
2114 cur = cur->parent->last;
2115 } else {
2116 while (cur->next != NULL) cur = cur->next;
2117 }
2118
2119 xmlUnlinkNode(elem);
2120
2121 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2122#ifndef XML_USE_BUFFER_CONTENT
2123 xmlNodeAddContent(cur, elem->content);
2124#else
2125 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2126#endif
2127 xmlFreeNode(elem);
2128 return(cur);
2129 }
2130
2131 if (elem->doc != cur->doc) {
2132 xmlSetTreeDoc(elem, cur->doc);
2133 }
2134 parent = cur->parent;
2135 elem->prev = cur;
2136 elem->next = NULL;
2137 elem->parent = parent;
2138 cur->next = elem;
2139 if (parent != NULL)
2140 parent->last = elem;
2141
2142 return(elem);
2143}
2144
2145/**
2146 * xmlAddChildList:
2147 * @parent: the parent node
2148 * @cur: the first node in the list
2149 *
2150 * Add a list of node at the end of the child list of the parent
2151 * merging adjacent TEXT nodes (@cur may be freed)
2152 *
2153 * Returns the last child or NULL in case of error.
2154 */
2155xmlNodePtr
2156xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2157 xmlNodePtr prev;
2158
2159 if (parent == NULL) {
2160#ifdef DEBUG_TREE
2161 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002162 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002163#endif
2164 return(NULL);
2165 }
2166
2167 if (cur == NULL) {
2168#ifdef DEBUG_TREE
2169 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002170 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002171#endif
2172 return(NULL);
2173 }
2174
2175 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2176 (cur->doc != parent->doc)) {
2177#ifdef DEBUG_TREE
2178 xmlGenericError(xmlGenericErrorContext,
2179 "Elements moved to a different document\n");
2180#endif
2181 }
2182
2183 /*
2184 * add the first element at the end of the children list.
2185 */
2186 if (parent->children == NULL) {
2187 parent->children = cur;
2188 } else {
2189 /*
2190 * If cur and parent->last both are TEXT nodes, then merge them.
2191 */
2192 if ((cur->type == XML_TEXT_NODE) &&
2193 (parent->last->type == XML_TEXT_NODE) &&
2194 (cur->name == parent->last->name)) {
2195#ifndef XML_USE_BUFFER_CONTENT
2196 xmlNodeAddContent(parent->last, cur->content);
2197#else
2198 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2199#endif
2200 /*
2201 * if it's the only child, nothing more to be done.
2202 */
2203 if (cur->next == NULL) {
2204 xmlFreeNode(cur);
2205 return(parent->last);
2206 }
2207 prev = cur;
2208 cur = cur->next;
2209 xmlFreeNode(prev);
2210 }
2211 prev = parent->last;
2212 prev->next = cur;
2213 cur->prev = prev;
2214 }
2215 while (cur->next != NULL) {
2216 cur->parent = parent;
2217 if (cur->doc != parent->doc) {
2218 xmlSetTreeDoc(cur, parent->doc);
2219 }
2220 cur = cur->next;
2221 }
2222 cur->parent = parent;
2223 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2224 parent->last = cur;
2225
2226 return(cur);
2227}
2228
2229/**
2230 * xmlAddChild:
2231 * @parent: the parent node
2232 * @cur: the child node
2233 *
2234 * Add a new child element, to @parent, at the end of the child list
2235 * merging adjacent TEXT nodes (in which case @cur is freed)
2236 * Returns the child or NULL in case of error.
2237 */
2238xmlNodePtr
2239xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2240 xmlNodePtr prev;
2241
2242 if (parent == NULL) {
2243#ifdef DEBUG_TREE
2244 xmlGenericError(xmlGenericErrorContext,
2245 "xmlAddChild : parent == NULL\n");
2246#endif
2247 return(NULL);
2248 }
2249
2250 if (cur == NULL) {
2251#ifdef DEBUG_TREE
2252 xmlGenericError(xmlGenericErrorContext,
2253 "xmlAddChild : child == NULL\n");
2254#endif
2255 return(NULL);
2256 }
2257
Owen Taylor3473f882001-02-23 17:55:21 +00002258 /*
2259 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002260 * cur is then freed.
2261 */
2262 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002263 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002264 (parent->content != NULL)) {
2265#ifndef XML_USE_BUFFER_CONTENT
2266 xmlNodeAddContent(parent, cur->content);
2267#else
2268 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2269#endif
2270 xmlFreeNode(cur);
2271 return(parent);
2272 }
2273 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2274 (parent->last->name == cur->name)) {
2275#ifndef XML_USE_BUFFER_CONTENT
2276 xmlNodeAddContent(parent->last, cur->content);
2277#else
2278 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2279#endif
2280 xmlFreeNode(cur);
2281 return(parent->last);
2282 }
2283 }
2284
2285 /*
2286 * add the new element at the end of the children list.
2287 */
2288 cur->parent = parent;
2289 if (cur->doc != parent->doc) {
2290 xmlSetTreeDoc(cur, parent->doc);
2291 }
2292
2293 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002294 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002295 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002296 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002297 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002298#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002299 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002300#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002301 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002302#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002303 xmlFreeNode(cur);
2304 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002305 }
2306 if (parent->children == NULL) {
2307 parent->children = cur;
2308 parent->last = cur;
2309 } else {
2310 prev = parent->last;
2311 prev->next = cur;
2312 cur->prev = prev;
2313 parent->last = cur;
2314 }
2315
2316 return(cur);
2317}
2318
2319/**
2320 * xmlGetLastChild:
2321 * @parent: the parent node
2322 *
2323 * Search the last child of a node.
2324 * Returns the last child or NULL if none.
2325 */
2326xmlNodePtr
2327xmlGetLastChild(xmlNodePtr parent) {
2328 if (parent == NULL) {
2329#ifdef DEBUG_TREE
2330 xmlGenericError(xmlGenericErrorContext,
2331 "xmlGetLastChild : parent == NULL\n");
2332#endif
2333 return(NULL);
2334 }
2335 return(parent->last);
2336}
2337
2338/**
2339 * xmlFreeNodeList:
2340 * @cur: the first node in the list
2341 *
2342 * Free a node and all its siblings, this is a recursive behaviour, all
2343 * the children are freed too.
2344 */
2345void
2346xmlFreeNodeList(xmlNodePtr cur) {
2347 xmlNodePtr next;
2348 if (cur == NULL) {
2349#ifdef DEBUG_TREE
2350 xmlGenericError(xmlGenericErrorContext,
2351 "xmlFreeNodeList : node == NULL\n");
2352#endif
2353 return;
2354 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002355 if (cur->type == XML_NAMESPACE_DECL) {
2356 xmlFreeNsList((xmlNsPtr) cur);
2357 return;
2358 }
Owen Taylor3473f882001-02-23 17:55:21 +00002359 while (cur != NULL) {
2360 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002361 /* unroll to speed up freeing the document */
2362 if (cur->type != XML_DTD_NODE) {
2363 if ((cur->children != NULL) &&
2364 (cur->type != XML_ENTITY_REF_NODE))
2365 xmlFreeNodeList(cur->children);
2366 if (cur->properties != NULL)
2367 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002368 if ((cur->type != XML_ELEMENT_NODE) &&
2369 (cur->type != XML_XINCLUDE_START) &&
2370 (cur->type != XML_XINCLUDE_END) &&
2371 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002372#ifndef XML_USE_BUFFER_CONTENT
2373 if (cur->content != NULL) xmlFree(cur->content);
2374#else
2375 if (cur->content != NULL) xmlBufferFree(cur->content);
2376#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002377 }
2378 if (((cur->type == XML_ELEMENT_NODE) ||
2379 (cur->type == XML_XINCLUDE_START) ||
2380 (cur->type == XML_XINCLUDE_END)) &&
2381 (cur->nsDef != NULL))
2382 xmlFreeNsList(cur->nsDef);
2383
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002384 /*
2385 * When a node is a text node or a comment, it uses a global static
2386 * variable for the name of the node.
2387 *
2388 * The xmlStrEqual comparisons need to be done when (happened with
2389 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002390 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002391 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002392 * the string addresses compare are not sufficient.
2393 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002394 if ((cur->name != NULL) &&
2395 (cur->name != xmlStringText) &&
2396 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002397 (cur->name != xmlStringComment)) {
2398 if (cur->type == XML_TEXT_NODE) {
2399 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2400 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2401 xmlFree((char *) cur->name);
2402 } else if (cur->type == XML_COMMENT_NODE) {
2403 if (!xmlStrEqual(cur->name, xmlStringComment))
2404 xmlFree((char *) cur->name);
2405 } else
2406 xmlFree((char *) cur->name);
2407 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002408 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002409 xmlFree(cur);
2410 }
Owen Taylor3473f882001-02-23 17:55:21 +00002411 cur = next;
2412 }
2413}
2414
2415/**
2416 * xmlFreeNode:
2417 * @cur: the node
2418 *
2419 * Free a node, this is a recursive behaviour, all the children are freed too.
2420 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2421 */
2422void
2423xmlFreeNode(xmlNodePtr cur) {
2424 if (cur == NULL) {
2425#ifdef DEBUG_TREE
2426 xmlGenericError(xmlGenericErrorContext,
2427 "xmlFreeNode : node == NULL\n");
2428#endif
2429 return;
2430 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002431 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002432 if (cur->type == XML_DTD_NODE) {
2433 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002434 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002435 }
2436 if (cur->type == XML_NAMESPACE_DECL) {
2437 xmlFreeNs((xmlNsPtr) cur);
2438 return;
2439 }
Owen Taylor3473f882001-02-23 17:55:21 +00002440 if ((cur->children != NULL) &&
2441 (cur->type != XML_ENTITY_REF_NODE))
2442 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002443 if (cur->properties != NULL)
2444 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002445 if ((cur->type != XML_ELEMENT_NODE) &&
2446 (cur->content != NULL) &&
2447 (cur->type != XML_ENTITY_REF_NODE) &&
2448 (cur->type != XML_XINCLUDE_END) &&
2449 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002450#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002451 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002452#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002453 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002454#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002455 }
2456
Daniel Veillardacd370f2001-06-09 17:17:51 +00002457 /*
2458 * When a node is a text node or a comment, it uses a global static
2459 * variable for the name of the node.
2460 *
2461 * The xmlStrEqual comparisons need to be done when (happened with
2462 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002463 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002464 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002465 * are not sufficient.
2466 */
Owen Taylor3473f882001-02-23 17:55:21 +00002467 if ((cur->name != NULL) &&
2468 (cur->name != xmlStringText) &&
2469 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002470 (cur->name != xmlStringComment)) {
2471 if (cur->type == XML_TEXT_NODE) {
2472 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2473 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2474 xmlFree((char *) cur->name);
2475 } else if (cur->type == XML_COMMENT_NODE) {
2476 if (!xmlStrEqual(cur->name, xmlStringComment))
2477 xmlFree((char *) cur->name);
2478 } else
2479 xmlFree((char *) cur->name);
2480 }
2481
Owen Taylor3473f882001-02-23 17:55:21 +00002482 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002483 xmlFree(cur);
2484}
2485
2486/**
2487 * xmlUnlinkNode:
2488 * @cur: the node
2489 *
2490 * Unlink a node from it's current context, the node is not freed
2491 */
2492void
2493xmlUnlinkNode(xmlNodePtr cur) {
2494 if (cur == NULL) {
2495#ifdef DEBUG_TREE
2496 xmlGenericError(xmlGenericErrorContext,
2497 "xmlUnlinkNode : node == NULL\n");
2498#endif
2499 return;
2500 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002501 if (cur->type == XML_DTD_NODE) {
2502 xmlDocPtr doc;
2503 doc = cur->doc;
2504 if (doc->intSubset == (xmlDtdPtr) cur)
2505 doc->intSubset = NULL;
2506 if (doc->extSubset == (xmlDtdPtr) cur)
2507 doc->extSubset = NULL;
2508 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002509 if (cur->parent != NULL) {
2510 xmlNodePtr parent;
2511 parent = cur->parent;
2512 if (cur->type == XML_ATTRIBUTE_NODE) {
2513 if (parent->properties == (xmlAttrPtr) cur)
2514 parent->properties = ((xmlAttrPtr) cur)->next;
2515 } else {
2516 if (parent->children == cur)
2517 parent->children = cur->next;
2518 if (parent->last == cur)
2519 parent->last = cur->prev;
2520 }
2521 cur->parent = NULL;
2522 }
Owen Taylor3473f882001-02-23 17:55:21 +00002523 if (cur->next != NULL)
2524 cur->next->prev = cur->prev;
2525 if (cur->prev != NULL)
2526 cur->prev->next = cur->next;
2527 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002528}
2529
2530/**
2531 * xmlReplaceNode:
2532 * @old: the old node
2533 * @cur: the node
2534 *
2535 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002536 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002537 * first unlinked from its existing context.
2538 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002539 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002540 */
2541xmlNodePtr
2542xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2543 if (old == NULL) {
2544#ifdef DEBUG_TREE
2545 xmlGenericError(xmlGenericErrorContext,
2546 "xmlReplaceNode : old == NULL\n");
2547#endif
2548 return(NULL);
2549 }
2550 if (cur == NULL) {
2551 xmlUnlinkNode(old);
2552 return(old);
2553 }
2554 if (cur == old) {
2555 return(old);
2556 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002557 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2558#ifdef DEBUG_TREE
2559 xmlGenericError(xmlGenericErrorContext,
2560 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2561#endif
2562 return(old);
2563 }
2564 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2565#ifdef DEBUG_TREE
2566 xmlGenericError(xmlGenericErrorContext,
2567 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2568#endif
2569 return(old);
2570 }
Owen Taylor3473f882001-02-23 17:55:21 +00002571 xmlUnlinkNode(cur);
2572 cur->doc = old->doc;
2573 cur->parent = old->parent;
2574 cur->next = old->next;
2575 if (cur->next != NULL)
2576 cur->next->prev = cur;
2577 cur->prev = old->prev;
2578 if (cur->prev != NULL)
2579 cur->prev->next = cur;
2580 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002581 if (cur->type == XML_ATTRIBUTE_NODE) {
2582 if (cur->parent->properties == (xmlAttrPtr)old)
2583 cur->parent->properties = ((xmlAttrPtr) cur);
2584 } else {
2585 if (cur->parent->children == old)
2586 cur->parent->children = cur;
2587 if (cur->parent->last == old)
2588 cur->parent->last = cur;
2589 }
Owen Taylor3473f882001-02-23 17:55:21 +00002590 }
2591 old->next = old->prev = NULL;
2592 old->parent = NULL;
2593 return(old);
2594}
2595
2596/************************************************************************
2597 * *
2598 * Copy operations *
2599 * *
2600 ************************************************************************/
2601
2602/**
2603 * xmlCopyNamespace:
2604 * @cur: the namespace
2605 *
2606 * Do a copy of the namespace.
2607 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002608 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002609 */
2610xmlNsPtr
2611xmlCopyNamespace(xmlNsPtr cur) {
2612 xmlNsPtr ret;
2613
2614 if (cur == NULL) return(NULL);
2615 switch (cur->type) {
2616 case XML_LOCAL_NAMESPACE:
2617 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2618 break;
2619 default:
2620#ifdef DEBUG_TREE
2621 xmlGenericError(xmlGenericErrorContext,
2622 "xmlCopyNamespace: invalid type %d\n", cur->type);
2623#endif
2624 return(NULL);
2625 }
2626 return(ret);
2627}
2628
2629/**
2630 * xmlCopyNamespaceList:
2631 * @cur: the first namespace
2632 *
2633 * Do a copy of an namespace list.
2634 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002635 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002636 */
2637xmlNsPtr
2638xmlCopyNamespaceList(xmlNsPtr cur) {
2639 xmlNsPtr ret = NULL;
2640 xmlNsPtr p = NULL,q;
2641
2642 while (cur != NULL) {
2643 q = xmlCopyNamespace(cur);
2644 if (p == NULL) {
2645 ret = p = q;
2646 } else {
2647 p->next = q;
2648 p = q;
2649 }
2650 cur = cur->next;
2651 }
2652 return(ret);
2653}
2654
2655static xmlNodePtr
2656xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2657/**
2658 * xmlCopyProp:
2659 * @target: the element where the attribute will be grafted
2660 * @cur: the attribute
2661 *
2662 * Do a copy of the attribute.
2663 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002664 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002665 */
2666xmlAttrPtr
2667xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2668 xmlAttrPtr ret;
2669
2670 if (cur == NULL) return(NULL);
2671 if (target != NULL)
2672 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2673 else if (cur->parent != NULL)
2674 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2675 else if (cur->children != NULL)
2676 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2677 else
2678 ret = xmlNewDocProp(NULL, cur->name, NULL);
2679 if (ret == NULL) return(NULL);
2680 ret->parent = target;
2681
2682 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002683 xmlNsPtr ns;
2684 if (target->doc)
Owen Taylor3473f882001-02-23 17:55:21 +00002685 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
Daniel Veillard8107a222002-01-13 14:10:10 +00002686 else if (cur->doc) /* target may not yet have a doc : KPI */
2687 ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2688 else
2689 ns = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002690 ret->ns = ns;
2691 } else
2692 ret->ns = NULL;
2693
2694 if (cur->children != NULL) {
2695 xmlNodePtr tmp;
2696
2697 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2698 ret->last = NULL;
2699 tmp = ret->children;
2700 while (tmp != NULL) {
2701 /* tmp->parent = (xmlNodePtr)ret; */
2702 if (tmp->next == NULL)
2703 ret->last = tmp;
2704 tmp = tmp->next;
2705 }
2706 }
2707 return(ret);
2708}
2709
2710/**
2711 * xmlCopyPropList:
2712 * @target: the element where the attributes will be grafted
2713 * @cur: the first attribute
2714 *
2715 * Do a copy of an attribute list.
2716 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002717 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002718 */
2719xmlAttrPtr
2720xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2721 xmlAttrPtr ret = NULL;
2722 xmlAttrPtr p = NULL,q;
2723
2724 while (cur != NULL) {
2725 q = xmlCopyProp(target, cur);
2726 if (p == NULL) {
2727 ret = p = q;
2728 } else {
2729 p->next = q;
2730 q->prev = p;
2731 p = q;
2732 }
2733 cur = cur->next;
2734 }
2735 return(ret);
2736}
2737
2738/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002739 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002740 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002741 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002742 * tricky reason: namespaces. Doing a direct copy of a node
2743 * say RPM:Copyright without changing the namespace pointer to
2744 * something else can produce stale links. One way to do it is
2745 * to keep a reference counter but this doesn't work as soon
2746 * as one move the element or the subtree out of the scope of
2747 * the existing namespace. The actual solution seems to add
2748 * a copy of the namespace at the top of the copied tree if
2749 * not available in the subtree.
2750 * Hence two functions, the public front-end call the inner ones
2751 */
2752
2753static xmlNodePtr
2754xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2755
2756static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002757xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002758 int recursive) {
2759 xmlNodePtr ret;
2760
2761 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002762 switch (node->type) {
2763 case XML_TEXT_NODE:
2764 case XML_CDATA_SECTION_NODE:
2765 case XML_ELEMENT_NODE:
2766 case XML_ENTITY_REF_NODE:
2767 case XML_ENTITY_NODE:
2768 case XML_PI_NODE:
2769 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002770 case XML_XINCLUDE_START:
2771 case XML_XINCLUDE_END:
2772 break;
2773 case XML_ATTRIBUTE_NODE:
2774 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2775 case XML_NAMESPACE_DECL:
2776 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2777
Daniel Veillard39196eb2001-06-19 18:09:42 +00002778 case XML_DOCUMENT_NODE:
2779 case XML_HTML_DOCUMENT_NODE:
2780#ifdef LIBXML_DOCB_ENABLED
2781 case XML_DOCB_DOCUMENT_NODE:
2782#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002783 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002784 case XML_DOCUMENT_TYPE_NODE:
2785 case XML_DOCUMENT_FRAG_NODE:
2786 case XML_NOTATION_NODE:
2787 case XML_DTD_NODE:
2788 case XML_ELEMENT_DECL:
2789 case XML_ATTRIBUTE_DECL:
2790 case XML_ENTITY_DECL:
2791 return(NULL);
2792 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002793
Owen Taylor3473f882001-02-23 17:55:21 +00002794 /*
2795 * Allocate a new node and fill the fields.
2796 */
2797 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2798 if (ret == NULL) {
2799 xmlGenericError(xmlGenericErrorContext,
2800 "xmlStaticCopyNode : malloc failed\n");
2801 return(NULL);
2802 }
2803 memset(ret, 0, sizeof(xmlNode));
2804 ret->type = node->type;
2805
2806 ret->doc = doc;
2807 ret->parent = parent;
2808 if (node->name == xmlStringText)
2809 ret->name = xmlStringText;
2810 else if (node->name == xmlStringTextNoenc)
2811 ret->name = xmlStringTextNoenc;
2812 else if (node->name == xmlStringComment)
2813 ret->name = xmlStringComment;
2814 else if (node->name != NULL)
2815 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002816 if ((node->type != XML_ELEMENT_NODE) &&
2817 (node->content != NULL) &&
2818 (node->type != XML_ENTITY_REF_NODE) &&
2819 (node->type != XML_XINCLUDE_END) &&
2820 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002821#ifndef XML_USE_BUFFER_CONTENT
2822 ret->content = xmlStrdup(node->content);
2823#else
2824 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2825 xmlBufferSetAllocationScheme(ret->content,
2826 xmlGetBufferAllocationScheme());
2827 xmlBufferAdd(ret->content,
2828 xmlBufferContent(node->content),
2829 xmlBufferLength(node->content));
2830#endif
Daniel Veillard8107a222002-01-13 14:10:10 +00002831 }else{
2832 if (node->type == XML_ELEMENT_NODE)
2833 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002834 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002835 if (parent != NULL) {
2836 xmlNodePtr tmp;
2837
2838 tmp = xmlAddChild(parent, ret);
2839 /* node could have coalesced */
2840 if (tmp != ret)
2841 return(tmp);
2842 }
Owen Taylor3473f882001-02-23 17:55:21 +00002843
2844 if (!recursive) return(ret);
2845 if (node->nsDef != NULL)
2846 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2847
2848 if (node->ns != NULL) {
2849 xmlNsPtr ns;
2850
2851 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2852 if (ns == NULL) {
2853 /*
2854 * Humm, we are copying an element whose namespace is defined
2855 * out of the new tree scope. Search it in the original tree
2856 * and add it at the top of the new tree
2857 */
2858 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2859 if (ns != NULL) {
2860 xmlNodePtr root = ret;
2861
2862 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002863 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002864 }
2865 } else {
2866 /*
2867 * reference the existing namespace definition in our own tree.
2868 */
2869 ret->ns = ns;
2870 }
2871 }
2872 if (node->properties != NULL)
2873 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002874 if (node->type == XML_ENTITY_REF_NODE) {
2875 if ((doc == NULL) || (node->doc != doc)) {
2876 /*
2877 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002878 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002879 * we cannot keep the reference. Try to find it in the
2880 * target document.
2881 */
2882 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2883 } else {
2884 ret->children = node->children;
2885 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002886 ret->last = ret->children;
2887 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002888 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002889 UPDATE_LAST_CHILD_AND_PARENT(ret)
2890 }
Owen Taylor3473f882001-02-23 17:55:21 +00002891 return(ret);
2892}
2893
2894static xmlNodePtr
2895xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2896 xmlNodePtr ret = NULL;
2897 xmlNodePtr p = NULL,q;
2898
2899 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002900 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002901 if (doc == NULL) {
2902 node = node->next;
2903 continue;
2904 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002905 if (doc->intSubset == NULL) {
2906 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2907 q->doc = doc;
2908 q->parent = parent;
2909 doc->intSubset = (xmlDtdPtr) q;
2910 } else {
2911 q = (xmlNodePtr) doc->intSubset;
2912 }
2913 } else
2914 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002915 if (ret == NULL) {
2916 q->prev = NULL;
2917 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002918 } else if (p != q) {
2919 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002920 p->next = q;
2921 q->prev = p;
2922 p = q;
2923 }
2924 node = node->next;
2925 }
2926 return(ret);
2927}
2928
2929/**
2930 * xmlCopyNode:
2931 * @node: the node
2932 * @recursive: if 1 do a recursive copy.
2933 *
2934 * Do a copy of the node.
2935 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002936 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002937 */
2938xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002939xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002940 xmlNodePtr ret;
2941
2942 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2943 return(ret);
2944}
2945
2946/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002947 * xmlDocCopyNode:
2948 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00002949 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00002950 * @recursive: if 1 do a recursive copy.
2951 *
2952 * Do a copy of the node to a given document.
2953 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002954 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00002955 */
2956xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002957xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002958 xmlNodePtr ret;
2959
2960 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2961 return(ret);
2962}
2963
2964/**
Owen Taylor3473f882001-02-23 17:55:21 +00002965 * xmlCopyNodeList:
2966 * @node: the first node in the list.
2967 *
2968 * Do a recursive copy of the node list.
2969 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002970 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002971 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002972xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002973 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2974 return(ret);
2975}
2976
2977/**
Owen Taylor3473f882001-02-23 17:55:21 +00002978 * xmlCopyDtd:
2979 * @dtd: the dtd
2980 *
2981 * Do a copy of the dtd.
2982 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002983 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002984 */
2985xmlDtdPtr
2986xmlCopyDtd(xmlDtdPtr dtd) {
2987 xmlDtdPtr ret;
2988
2989 if (dtd == NULL) return(NULL);
2990 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2991 if (ret == NULL) return(NULL);
2992 if (dtd->entities != NULL)
2993 ret->entities = (void *) xmlCopyEntitiesTable(
2994 (xmlEntitiesTablePtr) dtd->entities);
2995 if (dtd->notations != NULL)
2996 ret->notations = (void *) xmlCopyNotationTable(
2997 (xmlNotationTablePtr) dtd->notations);
2998 if (dtd->elements != NULL)
2999 ret->elements = (void *) xmlCopyElementTable(
3000 (xmlElementTablePtr) dtd->elements);
3001 if (dtd->attributes != NULL)
3002 ret->attributes = (void *) xmlCopyAttributeTable(
3003 (xmlAttributeTablePtr) dtd->attributes);
3004 return(ret);
3005}
3006
3007/**
3008 * xmlCopyDoc:
3009 * @doc: the document
3010 * @recursive: if 1 do a recursive copy.
3011 *
3012 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003013 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003014 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003015 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003016 */
3017xmlDocPtr
3018xmlCopyDoc(xmlDocPtr doc, int recursive) {
3019 xmlDocPtr ret;
3020
3021 if (doc == NULL) return(NULL);
3022 ret = xmlNewDoc(doc->version);
3023 if (ret == NULL) return(NULL);
3024 if (doc->name != NULL)
3025 ret->name = xmlMemStrdup(doc->name);
3026 if (doc->encoding != NULL)
3027 ret->encoding = xmlStrdup(doc->encoding);
3028 ret->charset = doc->charset;
3029 ret->compression = doc->compression;
3030 ret->standalone = doc->standalone;
3031 if (!recursive) return(ret);
3032
Daniel Veillardb33c2012001-04-25 12:59:04 +00003033 ret->last = NULL;
3034 ret->children = NULL;
3035 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003036 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003037 ret->intSubset->doc = ret;
3038 ret->intSubset->parent = ret;
3039 }
Owen Taylor3473f882001-02-23 17:55:21 +00003040 if (doc->oldNs != NULL)
3041 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3042 if (doc->children != NULL) {
3043 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003044
3045 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3046 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003047 ret->last = NULL;
3048 tmp = ret->children;
3049 while (tmp != NULL) {
3050 if (tmp->next == NULL)
3051 ret->last = tmp;
3052 tmp = tmp->next;
3053 }
3054 }
3055 return(ret);
3056}
3057
3058/************************************************************************
3059 * *
3060 * Content access functions *
3061 * *
3062 ************************************************************************/
3063
3064/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003065 * xmlGetLineNo:
3066 * @node : valid node
3067 *
3068 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003069 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003070 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003071 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003072 */
3073long
3074xmlGetLineNo(xmlNodePtr node)
3075{
3076 long result = -1;
3077
3078 if (!node)
3079 return result;
3080 if (node->type == XML_ELEMENT_NODE)
3081 result = (long) node->content;
3082 else if ((node->prev != NULL) &&
3083 ((node->prev->type == XML_ELEMENT_NODE) ||
3084 (node->prev->type == XML_TEXT_NODE)))
3085 result = xmlGetLineNo(node->prev);
3086 else if ((node->parent != NULL) &&
3087 ((node->parent->type == XML_ELEMENT_NODE) ||
3088 (node->parent->type == XML_TEXT_NODE)))
3089 result = xmlGetLineNo(node->parent);
3090
3091 return result;
3092}
3093
3094/**
3095 * xmlGetNodePath:
3096 * @node: a node
3097 *
3098 * Build a structure based Path for the given node
3099 *
3100 * Returns the new path or NULL in case of error. The caller must free
3101 * the returned string
3102 */
3103xmlChar *
3104xmlGetNodePath(xmlNodePtr node)
3105{
3106 xmlNodePtr cur, tmp, next;
3107 xmlChar *buffer = NULL, *temp;
3108 size_t buf_len;
3109 xmlChar *buf;
3110 char sep;
3111 const char *name;
3112 char nametemp[100];
3113 int occur = 0;
3114
3115 if (node == NULL)
3116 return (NULL);
3117
3118 buf_len = 500;
3119 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3120 if (buffer == NULL)
3121 return (NULL);
3122 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3123 if (buf == NULL) {
3124 xmlFree(buffer);
3125 return (NULL);
3126 }
3127
3128 buffer[0] = 0;
3129 cur = node;
3130 do {
3131 name = "";
3132 sep = '?';
3133 occur = 0;
3134 if ((cur->type == XML_DOCUMENT_NODE) ||
3135 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3136 if (buffer[0] == '/')
3137 break;
3138 sep = '/';
3139 next = NULL;
3140 } else if (cur->type == XML_ELEMENT_NODE) {
3141 sep = '/';
3142 name = (const char *) cur->name;
3143 if (cur->ns) {
3144 snprintf(nametemp, sizeof(nametemp) - 1,
3145 "%s:%s", cur->ns->prefix, cur->name);
3146 nametemp[sizeof(nametemp) - 1] = 0;
3147 name = nametemp;
3148 }
3149 next = cur->parent;
3150
3151 /*
3152 * Thumbler index computation
3153 */
3154 tmp = cur->prev;
3155 while (tmp != NULL) {
3156 if (xmlStrEqual(cur->name, tmp->name))
3157 occur++;
3158 tmp = tmp->prev;
3159 }
3160 if (occur == 0) {
3161 tmp = cur->next;
3162 while (tmp != NULL) {
3163 if (xmlStrEqual(cur->name, tmp->name))
3164 occur++;
3165 tmp = tmp->next;
3166 }
3167 if (occur != 0)
3168 occur = 1;
3169 } else
3170 occur++;
3171 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3172 sep = '@';
3173 name = (const char *) (((xmlAttrPtr) cur)->name);
3174 next = ((xmlAttrPtr) cur)->parent;
3175 } else {
3176 next = cur->parent;
3177 }
3178
3179 /*
3180 * Make sure there is enough room
3181 */
3182 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3183 buf_len =
3184 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3185 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3186 if (temp == NULL) {
3187 xmlFree(buf);
3188 xmlFree(buffer);
3189 return (NULL);
3190 }
3191 buffer = temp;
3192 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3193 if (temp == NULL) {
3194 xmlFree(buf);
3195 xmlFree(buffer);
3196 return (NULL);
3197 }
3198 buf = temp;
3199 }
3200 if (occur == 0)
3201 snprintf((char *) buf, buf_len, "%c%s%s",
3202 sep, name, (char *) buffer);
3203 else
3204 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3205 sep, name, occur, (char *) buffer);
3206 snprintf((char *) buffer, buf_len, "%s", buf);
3207 cur = next;
3208 } while (cur != NULL);
3209 xmlFree(buf);
3210 return (buffer);
3211}
3212
3213/**
Owen Taylor3473f882001-02-23 17:55:21 +00003214 * xmlDocGetRootElement:
3215 * @doc: the document
3216 *
3217 * Get the root element of the document (doc->children is a list
3218 * containing possibly comments, PIs, etc ...).
3219 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003220 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003221 */
3222xmlNodePtr
3223xmlDocGetRootElement(xmlDocPtr doc) {
3224 xmlNodePtr ret;
3225
3226 if (doc == NULL) return(NULL);
3227 ret = doc->children;
3228 while (ret != NULL) {
3229 if (ret->type == XML_ELEMENT_NODE)
3230 return(ret);
3231 ret = ret->next;
3232 }
3233 return(ret);
3234}
3235
3236/**
3237 * xmlDocSetRootElement:
3238 * @doc: the document
3239 * @root: the new document root element
3240 *
3241 * Set the root element of the document (doc->children is a list
3242 * containing possibly comments, PIs, etc ...).
3243 *
3244 * Returns the old root element if any was found
3245 */
3246xmlNodePtr
3247xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3248 xmlNodePtr old = NULL;
3249
3250 if (doc == NULL) return(NULL);
3251 old = doc->children;
3252 while (old != NULL) {
3253 if (old->type == XML_ELEMENT_NODE)
3254 break;
3255 old = old->next;
3256 }
3257 if (old == NULL) {
3258 if (doc->children == NULL) {
3259 doc->children = root;
3260 doc->last = root;
3261 } else {
3262 xmlAddSibling(doc->children, root);
3263 }
3264 } else {
3265 xmlReplaceNode(old, root);
3266 }
3267 return(old);
3268}
3269
3270/**
3271 * xmlNodeSetLang:
3272 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003273 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003274 *
3275 * Set the language of a node, i.e. the values of the xml:lang
3276 * attribute.
3277 */
3278void
3279xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003280 xmlNsPtr ns;
3281
Owen Taylor3473f882001-02-23 17:55:21 +00003282 if (cur == NULL) return;
3283 switch(cur->type) {
3284 case XML_TEXT_NODE:
3285 case XML_CDATA_SECTION_NODE:
3286 case XML_COMMENT_NODE:
3287 case XML_DOCUMENT_NODE:
3288 case XML_DOCUMENT_TYPE_NODE:
3289 case XML_DOCUMENT_FRAG_NODE:
3290 case XML_NOTATION_NODE:
3291 case XML_HTML_DOCUMENT_NODE:
3292 case XML_DTD_NODE:
3293 case XML_ELEMENT_DECL:
3294 case XML_ATTRIBUTE_DECL:
3295 case XML_ENTITY_DECL:
3296 case XML_PI_NODE:
3297 case XML_ENTITY_REF_NODE:
3298 case XML_ENTITY_NODE:
3299 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003300#ifdef LIBXML_DOCB_ENABLED
3301 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003302#endif
3303 case XML_XINCLUDE_START:
3304 case XML_XINCLUDE_END:
3305 return;
3306 case XML_ELEMENT_NODE:
3307 case XML_ATTRIBUTE_NODE:
3308 break;
3309 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003310 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3311 if (ns == NULL)
3312 return;
3313 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003314}
3315
3316/**
3317 * xmlNodeGetLang:
3318 * @cur: the node being checked
3319 *
3320 * Searches the language of a node, i.e. the values of the xml:lang
3321 * attribute or the one carried by the nearest ancestor.
3322 *
3323 * Returns a pointer to the lang value, or NULL if not found
3324 * It's up to the caller to free the memory.
3325 */
3326xmlChar *
3327xmlNodeGetLang(xmlNodePtr cur) {
3328 xmlChar *lang;
3329
3330 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003331 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003332 if (lang != NULL)
3333 return(lang);
3334 cur = cur->parent;
3335 }
3336 return(NULL);
3337}
3338
3339
3340/**
3341 * xmlNodeSetSpacePreserve:
3342 * @cur: the node being changed
3343 * @val: the xml:space value ("0": default, 1: "preserve")
3344 *
3345 * Set (or reset) the space preserving behaviour of a node, i.e. the
3346 * value of the xml:space attribute.
3347 */
3348void
3349xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003350 xmlNsPtr ns;
3351
Owen Taylor3473f882001-02-23 17:55:21 +00003352 if (cur == NULL) return;
3353 switch(cur->type) {
3354 case XML_TEXT_NODE:
3355 case XML_CDATA_SECTION_NODE:
3356 case XML_COMMENT_NODE:
3357 case XML_DOCUMENT_NODE:
3358 case XML_DOCUMENT_TYPE_NODE:
3359 case XML_DOCUMENT_FRAG_NODE:
3360 case XML_NOTATION_NODE:
3361 case XML_HTML_DOCUMENT_NODE:
3362 case XML_DTD_NODE:
3363 case XML_ELEMENT_DECL:
3364 case XML_ATTRIBUTE_DECL:
3365 case XML_ENTITY_DECL:
3366 case XML_PI_NODE:
3367 case XML_ENTITY_REF_NODE:
3368 case XML_ENTITY_NODE:
3369 case XML_NAMESPACE_DECL:
3370 case XML_XINCLUDE_START:
3371 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003372#ifdef LIBXML_DOCB_ENABLED
3373 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003374#endif
3375 return;
3376 case XML_ELEMENT_NODE:
3377 case XML_ATTRIBUTE_NODE:
3378 break;
3379 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003380 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3381 if (ns == NULL)
3382 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003383 switch (val) {
3384 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003385 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003386 break;
3387 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003388 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003389 break;
3390 }
3391}
3392
3393/**
3394 * xmlNodeGetSpacePreserve:
3395 * @cur: the node being checked
3396 *
3397 * Searches the space preserving behaviour of a node, i.e. the values
3398 * of the xml:space attribute or the one carried by the nearest
3399 * ancestor.
3400 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003401 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003402 */
3403int
3404xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3405 xmlChar *space;
3406
3407 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003408 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003409 if (space != NULL) {
3410 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3411 xmlFree(space);
3412 return(1);
3413 }
3414 if (xmlStrEqual(space, BAD_CAST "default")) {
3415 xmlFree(space);
3416 return(0);
3417 }
3418 xmlFree(space);
3419 }
3420 cur = cur->parent;
3421 }
3422 return(-1);
3423}
3424
3425/**
3426 * xmlNodeSetName:
3427 * @cur: the node being changed
3428 * @name: the new tag name
3429 *
3430 * Set (or reset) the name of a node.
3431 */
3432void
3433xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3434 if (cur == NULL) return;
3435 if (name == NULL) return;
3436 switch(cur->type) {
3437 case XML_TEXT_NODE:
3438 case XML_CDATA_SECTION_NODE:
3439 case XML_COMMENT_NODE:
3440 case XML_DOCUMENT_TYPE_NODE:
3441 case XML_DOCUMENT_FRAG_NODE:
3442 case XML_NOTATION_NODE:
3443 case XML_HTML_DOCUMENT_NODE:
3444 case XML_NAMESPACE_DECL:
3445 case XML_XINCLUDE_START:
3446 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003447#ifdef LIBXML_DOCB_ENABLED
3448 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003449#endif
3450 return;
3451 case XML_ELEMENT_NODE:
3452 case XML_ATTRIBUTE_NODE:
3453 case XML_PI_NODE:
3454 case XML_ENTITY_REF_NODE:
3455 case XML_ENTITY_NODE:
3456 case XML_DTD_NODE:
3457 case XML_DOCUMENT_NODE:
3458 case XML_ELEMENT_DECL:
3459 case XML_ATTRIBUTE_DECL:
3460 case XML_ENTITY_DECL:
3461 break;
3462 }
3463 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3464 cur->name = xmlStrdup(name);
3465}
3466
3467/**
3468 * xmlNodeSetBase:
3469 * @cur: the node being changed
3470 * @uri: the new base URI
3471 *
3472 * Set (or reset) the base URI of a node, i.e. the value of the
3473 * xml:base attribute.
3474 */
3475void
3476xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003477 xmlNsPtr ns;
3478
Owen Taylor3473f882001-02-23 17:55:21 +00003479 if (cur == NULL) return;
3480 switch(cur->type) {
3481 case XML_TEXT_NODE:
3482 case XML_CDATA_SECTION_NODE:
3483 case XML_COMMENT_NODE:
3484 case XML_DOCUMENT_NODE:
3485 case XML_DOCUMENT_TYPE_NODE:
3486 case XML_DOCUMENT_FRAG_NODE:
3487 case XML_NOTATION_NODE:
3488 case XML_HTML_DOCUMENT_NODE:
3489 case XML_DTD_NODE:
3490 case XML_ELEMENT_DECL:
3491 case XML_ATTRIBUTE_DECL:
3492 case XML_ENTITY_DECL:
3493 case XML_PI_NODE:
3494 case XML_ENTITY_REF_NODE:
3495 case XML_ENTITY_NODE:
3496 case XML_NAMESPACE_DECL:
3497 case XML_XINCLUDE_START:
3498 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003499#ifdef LIBXML_DOCB_ENABLED
3500 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003501#endif
3502 return;
3503 case XML_ELEMENT_NODE:
3504 case XML_ATTRIBUTE_NODE:
3505 break;
3506 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003507
3508 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3509 if (ns == NULL)
3510 return;
3511 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003512}
3513
3514/**
Owen Taylor3473f882001-02-23 17:55:21 +00003515 * xmlNodeGetBase:
3516 * @doc: the document the node pertains to
3517 * @cur: the node being checked
3518 *
3519 * Searches for the BASE URL. The code should work on both XML
3520 * and HTML document even if base mechanisms are completely different.
3521 * It returns the base as defined in RFC 2396 sections
3522 * 5.1.1. Base URI within Document Content
3523 * and
3524 * 5.1.2. Base URI from the Encapsulating Entity
3525 * However it does not return the document base (5.1.3), use
3526 * xmlDocumentGetBase() for this
3527 *
3528 * Returns a pointer to the base URL, or NULL if not found
3529 * It's up to the caller to free the memory.
3530 */
3531xmlChar *
3532xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003533 xmlChar *oldbase = NULL;
3534 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003535
3536 if ((cur == NULL) && (doc == NULL))
3537 return(NULL);
3538 if (doc == NULL) doc = cur->doc;
3539 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3540 cur = doc->children;
3541 while ((cur != NULL) && (cur->name != NULL)) {
3542 if (cur->type != XML_ELEMENT_NODE) {
3543 cur = cur->next;
3544 continue;
3545 }
3546 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3547 cur = cur->children;
3548 continue;
3549 }
3550 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3551 cur = cur->children;
3552 continue;
3553 }
3554 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3555 return(xmlGetProp(cur, BAD_CAST "href"));
3556 }
3557 cur = cur->next;
3558 }
3559 return(NULL);
3560 }
3561 while (cur != NULL) {
3562 if (cur->type == XML_ENTITY_DECL) {
3563 xmlEntityPtr ent = (xmlEntityPtr) cur;
3564 return(xmlStrdup(ent->URI));
3565 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003566 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003567 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003568 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003569 if (oldbase != NULL) {
3570 newbase = xmlBuildURI(oldbase, base);
3571 if (newbase != NULL) {
3572 xmlFree(oldbase);
3573 xmlFree(base);
3574 oldbase = newbase;
3575 } else {
3576 xmlFree(oldbase);
3577 xmlFree(base);
3578 return(NULL);
3579 }
3580 } else {
3581 oldbase = base;
3582 }
3583 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3584 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3585 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3586 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003587 }
3588 }
Owen Taylor3473f882001-02-23 17:55:21 +00003589 cur = cur->parent;
3590 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003591 if ((doc != NULL) && (doc->URL != NULL)) {
3592 if (oldbase == NULL)
3593 return(xmlStrdup(doc->URL));
3594 newbase = xmlBuildURI(oldbase, doc->URL);
3595 xmlFree(oldbase);
3596 return(newbase);
3597 }
3598 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003599}
3600
3601/**
3602 * xmlNodeGetContent:
3603 * @cur: the node being read
3604 *
3605 * Read the value of a node, this can be either the text carried
3606 * directly by this node if it's a TEXT node or the aggregate string
3607 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003608 * Entity references are substituted.
3609 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003610 * It's up to the caller to free the memory.
3611 */
3612xmlChar *
3613xmlNodeGetContent(xmlNodePtr cur) {
3614 if (cur == NULL) return(NULL);
3615 switch (cur->type) {
3616 case XML_DOCUMENT_FRAG_NODE:
3617 case XML_ELEMENT_NODE: {
3618 xmlNodePtr tmp = cur;
3619 xmlBufferPtr buffer;
3620 xmlChar *ret;
3621
3622 buffer = xmlBufferCreate();
3623 if (buffer == NULL)
3624 return(NULL);
3625 while (tmp != NULL) {
3626 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003627 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003628 case XML_TEXT_NODE:
3629 if (tmp->content != NULL)
3630#ifndef XML_USE_BUFFER_CONTENT
3631 xmlBufferCat(buffer, tmp->content);
3632#else
3633 xmlBufferCat(buffer,
3634 xmlBufferContent(tmp->content));
3635#endif
3636 break;
3637 case XML_ENTITY_REF_NODE: {
3638 xmlEntityPtr ent;
3639
3640 ent = xmlGetDocEntity(cur->doc, tmp->name);
3641 if (ent != NULL)
3642 xmlBufferCat(buffer, ent->content);
3643 }
3644 default:
3645 break;
3646 }
3647 /*
3648 * Skip to next node
3649 */
3650 if (tmp->children != NULL) {
3651 if (tmp->children->type != XML_ENTITY_DECL) {
3652 tmp = tmp->children;
3653 continue;
3654 }
3655 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003656 if (tmp == cur)
3657 break;
3658
Owen Taylor3473f882001-02-23 17:55:21 +00003659 if (tmp->next != NULL) {
3660 tmp = tmp->next;
3661 continue;
3662 }
3663
3664 do {
3665 tmp = tmp->parent;
3666 if (tmp == NULL)
3667 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003668 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003669 tmp = NULL;
3670 break;
3671 }
3672 if (tmp->next != NULL) {
3673 tmp = tmp->next;
3674 break;
3675 }
3676 } while (tmp != NULL);
3677 }
3678 ret = buffer->content;
3679 buffer->content = NULL;
3680 xmlBufferFree(buffer);
3681 return(ret);
3682 }
3683 case XML_ATTRIBUTE_NODE: {
3684 xmlAttrPtr attr = (xmlAttrPtr) cur;
3685 if (attr->parent != NULL)
3686 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3687 else
3688 return(xmlNodeListGetString(NULL, attr->children, 1));
3689 break;
3690 }
3691 case XML_COMMENT_NODE:
3692 case XML_PI_NODE:
3693 if (cur->content != NULL)
3694#ifndef XML_USE_BUFFER_CONTENT
3695 return(xmlStrdup(cur->content));
3696#else
3697 return(xmlStrdup(xmlBufferContent(cur->content)));
3698#endif
3699 return(NULL);
3700 case XML_ENTITY_REF_NODE:
3701 /*
3702 * Locate the entity, and get it's content
3703 * @@@
3704 */
3705 return(NULL);
3706 case XML_ENTITY_NODE:
3707 case XML_DOCUMENT_NODE:
3708 case XML_HTML_DOCUMENT_NODE:
3709 case XML_DOCUMENT_TYPE_NODE:
3710 case XML_NOTATION_NODE:
3711 case XML_DTD_NODE:
3712 case XML_XINCLUDE_START:
3713 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003714#ifdef LIBXML_DOCB_ENABLED
3715 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003716#endif
3717 return(NULL);
3718 case XML_NAMESPACE_DECL:
3719 return(xmlStrdup(((xmlNsPtr)cur)->href));
3720 case XML_ELEMENT_DECL:
3721 /* TODO !!! */
3722 return(NULL);
3723 case XML_ATTRIBUTE_DECL:
3724 /* TODO !!! */
3725 return(NULL);
3726 case XML_ENTITY_DECL:
3727 /* TODO !!! */
3728 return(NULL);
3729 case XML_CDATA_SECTION_NODE:
3730 case XML_TEXT_NODE:
3731 if (cur->content != NULL)
3732#ifndef XML_USE_BUFFER_CONTENT
3733 return(xmlStrdup(cur->content));
3734#else
3735 return(xmlStrdup(xmlBufferContent(cur->content)));
3736#endif
3737 return(NULL);
3738 }
3739 return(NULL);
3740}
3741
3742/**
3743 * xmlNodeSetContent:
3744 * @cur: the node being modified
3745 * @content: the new value of the content
3746 *
3747 * Replace the content of a node.
3748 */
3749void
3750xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3751 if (cur == NULL) {
3752#ifdef DEBUG_TREE
3753 xmlGenericError(xmlGenericErrorContext,
3754 "xmlNodeSetContent : node == NULL\n");
3755#endif
3756 return;
3757 }
3758 switch (cur->type) {
3759 case XML_DOCUMENT_FRAG_NODE:
3760 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003761 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003762 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3763 cur->children = xmlStringGetNodeList(cur->doc, content);
3764 UPDATE_LAST_CHILD_AND_PARENT(cur)
3765 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003766 case XML_TEXT_NODE:
3767 case XML_CDATA_SECTION_NODE:
3768 case XML_ENTITY_REF_NODE:
3769 case XML_ENTITY_NODE:
3770 case XML_PI_NODE:
3771 case XML_COMMENT_NODE:
3772 if (cur->content != NULL) {
3773#ifndef XML_USE_BUFFER_CONTENT
3774 xmlFree(cur->content);
3775#else
3776 xmlBufferFree(cur->content);
3777#endif
3778 }
3779 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3780 cur->last = cur->children = NULL;
3781 if (content != NULL) {
3782#ifndef XML_USE_BUFFER_CONTENT
3783 cur->content = xmlStrdup(content);
3784#else
3785 cur->content = xmlBufferCreateSize(0);
3786 xmlBufferSetAllocationScheme(cur->content,
3787 xmlGetBufferAllocationScheme());
3788 xmlBufferAdd(cur->content, content, -1);
3789#endif
3790 } else
3791 cur->content = NULL;
3792 break;
3793 case XML_DOCUMENT_NODE:
3794 case XML_HTML_DOCUMENT_NODE:
3795 case XML_DOCUMENT_TYPE_NODE:
3796 case XML_XINCLUDE_START:
3797 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003798#ifdef LIBXML_DOCB_ENABLED
3799 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003800#endif
3801 break;
3802 case XML_NOTATION_NODE:
3803 break;
3804 case XML_DTD_NODE:
3805 break;
3806 case XML_NAMESPACE_DECL:
3807 break;
3808 case XML_ELEMENT_DECL:
3809 /* TODO !!! */
3810 break;
3811 case XML_ATTRIBUTE_DECL:
3812 /* TODO !!! */
3813 break;
3814 case XML_ENTITY_DECL:
3815 /* TODO !!! */
3816 break;
3817 }
3818}
3819
3820/**
3821 * xmlNodeSetContentLen:
3822 * @cur: the node being modified
3823 * @content: the new value of the content
3824 * @len: the size of @content
3825 *
3826 * Replace the content of a node.
3827 */
3828void
3829xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3830 if (cur == NULL) {
3831#ifdef DEBUG_TREE
3832 xmlGenericError(xmlGenericErrorContext,
3833 "xmlNodeSetContentLen : node == NULL\n");
3834#endif
3835 return;
3836 }
3837 switch (cur->type) {
3838 case XML_DOCUMENT_FRAG_NODE:
3839 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003840 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003841 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3842 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3843 UPDATE_LAST_CHILD_AND_PARENT(cur)
3844 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003845 case XML_TEXT_NODE:
3846 case XML_CDATA_SECTION_NODE:
3847 case XML_ENTITY_REF_NODE:
3848 case XML_ENTITY_NODE:
3849 case XML_PI_NODE:
3850 case XML_COMMENT_NODE:
3851 case XML_NOTATION_NODE:
3852 if (cur->content != NULL) {
3853#ifndef XML_USE_BUFFER_CONTENT
3854 xmlFree(cur->content);
3855#else
3856 xmlBufferFree(cur->content);
3857#endif
3858 }
3859 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3860 cur->children = cur->last = NULL;
3861 if (content != NULL) {
3862#ifndef XML_USE_BUFFER_CONTENT
3863 cur->content = xmlStrndup(content, len);
3864#else
3865 cur->content = xmlBufferCreateSize(len);
3866 xmlBufferSetAllocationScheme(cur->content,
3867 xmlGetBufferAllocationScheme());
3868 xmlBufferAdd(cur->content, content, len);
3869#endif
3870 } else
3871 cur->content = NULL;
3872 break;
3873 case XML_DOCUMENT_NODE:
3874 case XML_DTD_NODE:
3875 case XML_HTML_DOCUMENT_NODE:
3876 case XML_DOCUMENT_TYPE_NODE:
3877 case XML_NAMESPACE_DECL:
3878 case XML_XINCLUDE_START:
3879 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003880#ifdef LIBXML_DOCB_ENABLED
3881 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003882#endif
3883 break;
3884 case XML_ELEMENT_DECL:
3885 /* TODO !!! */
3886 break;
3887 case XML_ATTRIBUTE_DECL:
3888 /* TODO !!! */
3889 break;
3890 case XML_ENTITY_DECL:
3891 /* TODO !!! */
3892 break;
3893 }
3894}
3895
3896/**
3897 * xmlNodeAddContentLen:
3898 * @cur: the node being modified
3899 * @content: extra content
3900 * @len: the size of @content
3901 *
3902 * Append the extra substring to the node content.
3903 */
3904void
3905xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3906 if (cur == NULL) {
3907#ifdef DEBUG_TREE
3908 xmlGenericError(xmlGenericErrorContext,
3909 "xmlNodeAddContentLen : node == NULL\n");
3910#endif
3911 return;
3912 }
3913 if (len <= 0) return;
3914 switch (cur->type) {
3915 case XML_DOCUMENT_FRAG_NODE:
3916 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003917 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00003918
Daniel Veillard7db37732001-07-12 01:20:08 +00003919 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003920 newNode = xmlNewTextLen(content, len);
3921 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003922 tmp = xmlAddChild(cur, newNode);
3923 if (tmp != newNode)
3924 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003925 if ((last != NULL) && (last->next == newNode)) {
3926 xmlTextMerge(last, newNode);
3927 }
3928 }
3929 break;
3930 }
3931 case XML_ATTRIBUTE_NODE:
3932 break;
3933 case XML_TEXT_NODE:
3934 case XML_CDATA_SECTION_NODE:
3935 case XML_ENTITY_REF_NODE:
3936 case XML_ENTITY_NODE:
3937 case XML_PI_NODE:
3938 case XML_COMMENT_NODE:
3939 case XML_NOTATION_NODE:
3940 if (content != NULL) {
3941#ifndef XML_USE_BUFFER_CONTENT
3942 cur->content = xmlStrncat(cur->content, content, len);
3943#else
3944 xmlBufferAdd(cur->content, content, len);
3945#endif
3946 }
3947 case XML_DOCUMENT_NODE:
3948 case XML_DTD_NODE:
3949 case XML_HTML_DOCUMENT_NODE:
3950 case XML_DOCUMENT_TYPE_NODE:
3951 case XML_NAMESPACE_DECL:
3952 case XML_XINCLUDE_START:
3953 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003954#ifdef LIBXML_DOCB_ENABLED
3955 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003956#endif
3957 break;
3958 case XML_ELEMENT_DECL:
3959 case XML_ATTRIBUTE_DECL:
3960 case XML_ENTITY_DECL:
3961 break;
3962 }
3963}
3964
3965/**
3966 * xmlNodeAddContent:
3967 * @cur: the node being modified
3968 * @content: extra content
3969 *
3970 * Append the extra substring to the node content.
3971 */
3972void
3973xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3974 int len;
3975
3976 if (cur == NULL) {
3977#ifdef DEBUG_TREE
3978 xmlGenericError(xmlGenericErrorContext,
3979 "xmlNodeAddContent : node == NULL\n");
3980#endif
3981 return;
3982 }
3983 if (content == NULL) return;
3984 len = xmlStrlen(content);
3985 xmlNodeAddContentLen(cur, content, len);
3986}
3987
3988/**
3989 * xmlTextMerge:
3990 * @first: the first text node
3991 * @second: the second text node being merged
3992 *
3993 * Merge two text nodes into one
3994 * Returns the first text node augmented
3995 */
3996xmlNodePtr
3997xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3998 if (first == NULL) return(second);
3999 if (second == NULL) return(first);
4000 if (first->type != XML_TEXT_NODE) return(first);
4001 if (second->type != XML_TEXT_NODE) return(first);
4002 if (second->name != first->name)
4003 return(first);
4004#ifndef XML_USE_BUFFER_CONTENT
4005 xmlNodeAddContent(first, second->content);
4006#else
4007 xmlNodeAddContent(first, xmlBufferContent(second->content));
4008#endif
4009 xmlUnlinkNode(second);
4010 xmlFreeNode(second);
4011 return(first);
4012}
4013
4014/**
4015 * xmlGetNsList:
4016 * @doc: the document
4017 * @node: the current node
4018 *
4019 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004020 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004021 * that need to be freed by the caller or NULL if no
4022 * namespace if defined
4023 */
4024xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004025xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4026{
Owen Taylor3473f882001-02-23 17:55:21 +00004027 xmlNsPtr cur;
4028 xmlNsPtr *ret = NULL;
4029 int nbns = 0;
4030 int maxns = 10;
4031 int i;
4032
4033 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004034 if (node->type == XML_ELEMENT_NODE) {
4035 cur = node->nsDef;
4036 while (cur != NULL) {
4037 if (ret == NULL) {
4038 ret =
4039 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4040 sizeof(xmlNsPtr));
4041 if (ret == NULL) {
4042 xmlGenericError(xmlGenericErrorContext,
4043 "xmlGetNsList : out of memory!\n");
4044 return (NULL);
4045 }
4046 ret[nbns] = NULL;
4047 }
4048 for (i = 0; i < nbns; i++) {
4049 if ((cur->prefix == ret[i]->prefix) ||
4050 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4051 break;
4052 }
4053 if (i >= nbns) {
4054 if (nbns >= maxns) {
4055 maxns *= 2;
4056 ret = (xmlNsPtr *) xmlRealloc(ret,
4057 (maxns +
4058 1) *
4059 sizeof(xmlNsPtr));
4060 if (ret == NULL) {
4061 xmlGenericError(xmlGenericErrorContext,
4062 "xmlGetNsList : realloc failed!\n");
4063 return (NULL);
4064 }
4065 }
4066 ret[nbns++] = cur;
4067 ret[nbns] = NULL;
4068 }
Owen Taylor3473f882001-02-23 17:55:21 +00004069
Daniel Veillard77044732001-06-29 21:31:07 +00004070 cur = cur->next;
4071 }
4072 }
4073 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004074 }
Daniel Veillard77044732001-06-29 21:31:07 +00004075 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004076}
4077
4078/**
4079 * xmlSearchNs:
4080 * @doc: the document
4081 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004082 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004083 *
4084 * Search a Ns registered under a given name space for a document.
4085 * recurse on the parents until it finds the defined namespace
4086 * or return NULL otherwise.
4087 * @nameSpace can be NULL, this is a search for the default namespace.
4088 * We don't allow to cross entities boundaries. If you don't declare
4089 * the namespace within those you will be in troubles !!! A warning
4090 * is generated to cover this case.
4091 *
4092 * Returns the namespace pointer or NULL.
4093 */
4094xmlNsPtr
4095xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4096 xmlNsPtr cur;
4097
4098 if (node == NULL) return(NULL);
4099 if ((nameSpace != NULL) &&
4100 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004101 if (doc == NULL)
4102 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004103 if (doc->oldNs == NULL) {
4104 /*
4105 * Allocate a new Namespace and fill the fields.
4106 */
4107 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4108 if (doc->oldNs == NULL) {
4109 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004110 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004111 return(NULL);
4112 }
4113 memset(doc->oldNs, 0, sizeof(xmlNs));
4114 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4115
4116 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4117 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4118 }
4119 return(doc->oldNs);
4120 }
4121 while (node != NULL) {
4122 if ((node->type == XML_ENTITY_REF_NODE) ||
4123 (node->type == XML_ENTITY_NODE) ||
4124 (node->type == XML_ENTITY_DECL))
4125 return(NULL);
4126 if (node->type == XML_ELEMENT_NODE) {
4127 cur = node->nsDef;
4128 while (cur != NULL) {
4129 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4130 (cur->href != NULL))
4131 return(cur);
4132 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4133 (cur->href != NULL) &&
4134 (xmlStrEqual(cur->prefix, nameSpace)))
4135 return(cur);
4136 cur = cur->next;
4137 }
4138 }
4139 node = node->parent;
4140 }
4141 return(NULL);
4142}
4143
4144/**
4145 * xmlSearchNsByHref:
4146 * @doc: the document
4147 * @node: the current node
4148 * @href: the namespace value
4149 *
4150 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4151 * the defined namespace or return NULL otherwise.
4152 * Returns the namespace pointer or NULL.
4153 */
4154xmlNsPtr
4155xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4156 xmlNsPtr cur;
4157 xmlNodePtr orig = node;
4158
4159 if ((node == NULL) || (href == NULL)) return(NULL);
4160 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004161 /*
4162 * Only the document can hold the XML spec namespace.
4163 */
4164 if (doc == NULL)
4165 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004166 if (doc->oldNs == NULL) {
4167 /*
4168 * Allocate a new Namespace and fill the fields.
4169 */
4170 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4171 if (doc->oldNs == NULL) {
4172 xmlGenericError(xmlGenericErrorContext,
4173 "xmlSearchNsByHref : malloc failed\n");
4174 return(NULL);
4175 }
4176 memset(doc->oldNs, 0, sizeof(xmlNs));
4177 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4178
4179 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4180 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4181 }
4182 return(doc->oldNs);
4183 }
4184 while (node != NULL) {
4185 cur = node->nsDef;
4186 while (cur != NULL) {
4187 if ((cur->href != NULL) && (href != NULL) &&
4188 (xmlStrEqual(cur->href, href))) {
4189 /*
4190 * Check that the prefix is not shadowed between orig and node
4191 */
4192 xmlNodePtr check = orig;
4193 xmlNsPtr tst;
4194
4195 while (check != node) {
4196 tst = check->nsDef;
4197 while (tst != NULL) {
4198 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4199 goto shadowed;
4200 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4201 (xmlStrEqual(tst->prefix, cur->prefix)))
4202 goto shadowed;
4203 tst = tst->next;
4204 }
4205 check = check->parent;
4206 }
4207 return(cur);
4208 }
4209shadowed:
4210 cur = cur->next;
4211 }
4212 node = node->parent;
4213 }
4214 return(NULL);
4215}
4216
4217/**
4218 * xmlNewReconciliedNs
4219 * @doc: the document
4220 * @tree: a node expected to hold the new namespace
4221 * @ns: the original namespace
4222 *
4223 * This function tries to locate a namespace definition in a tree
4224 * ancestors, or create a new namespace definition node similar to
4225 * @ns trying to reuse the same prefix. However if the given prefix is
4226 * null (default namespace) or reused within the subtree defined by
4227 * @tree or on one of its ancestors then a new prefix is generated.
4228 * Returns the (new) namespace definition or NULL in case of error
4229 */
4230xmlNsPtr
4231xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4232 xmlNsPtr def;
4233 xmlChar prefix[50];
4234 int counter = 1;
4235
4236 if (tree == NULL) {
4237#ifdef DEBUG_TREE
4238 xmlGenericError(xmlGenericErrorContext,
4239 "xmlNewReconciliedNs : tree == NULL\n");
4240#endif
4241 return(NULL);
4242 }
4243 if (ns == NULL) {
4244#ifdef DEBUG_TREE
4245 xmlGenericError(xmlGenericErrorContext,
4246 "xmlNewReconciliedNs : ns == NULL\n");
4247#endif
4248 return(NULL);
4249 }
4250 /*
4251 * Search an existing namespace definition inherited.
4252 */
4253 def = xmlSearchNsByHref(doc, tree, ns->href);
4254 if (def != NULL)
4255 return(def);
4256
4257 /*
4258 * Find a close prefix which is not already in use.
4259 * Let's strip namespace prefixes longer than 20 chars !
4260 */
4261 sprintf((char *) prefix, "%.20s", ns->prefix);
4262 def = xmlSearchNs(doc, tree, prefix);
4263 while (def != NULL) {
4264 if (counter > 1000) return(NULL);
4265 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4266 def = xmlSearchNs(doc, tree, prefix);
4267 }
4268
4269 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004270 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004271 */
4272 def = xmlNewNs(tree, ns->href, prefix);
4273 return(def);
4274}
4275
4276/**
4277 * xmlReconciliateNs
4278 * @doc: the document
4279 * @tree: a node defining the subtree to reconciliate
4280 *
4281 * This function checks that all the namespaces declared within the given
4282 * tree are properly declared. This is needed for example after Copy or Cut
4283 * and then paste operations. The subtree may still hold pointers to
4284 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004285 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004286 * the new environment. If not possible the new namespaces are redeclared
4287 * on @tree at the top of the given subtree.
4288 * Returns the number of namespace declarations created or -1 in case of error.
4289 */
4290int
4291xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4292 xmlNsPtr *oldNs = NULL;
4293 xmlNsPtr *newNs = NULL;
4294 int sizeCache = 0;
4295 int nbCache = 0;
4296
4297 xmlNsPtr n;
4298 xmlNodePtr node = tree;
4299 xmlAttrPtr attr;
4300 int ret = 0, i;
4301
4302 while (node != NULL) {
4303 /*
4304 * Reconciliate the node namespace
4305 */
4306 if (node->ns != NULL) {
4307 /*
4308 * initialize the cache if needed
4309 */
4310 if (sizeCache == 0) {
4311 sizeCache = 10;
4312 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4313 sizeof(xmlNsPtr));
4314 if (oldNs == NULL) {
4315 xmlGenericError(xmlGenericErrorContext,
4316 "xmlReconciliateNs : memory pbm\n");
4317 return(-1);
4318 }
4319 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4320 sizeof(xmlNsPtr));
4321 if (newNs == NULL) {
4322 xmlGenericError(xmlGenericErrorContext,
4323 "xmlReconciliateNs : memory pbm\n");
4324 xmlFree(oldNs);
4325 return(-1);
4326 }
4327 }
4328 for (i = 0;i < nbCache;i++) {
4329 if (oldNs[i] == node->ns) {
4330 node->ns = newNs[i];
4331 break;
4332 }
4333 }
4334 if (i == nbCache) {
4335 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004336 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004337 */
4338 n = xmlNewReconciliedNs(doc, tree, node->ns);
4339 if (n != NULL) { /* :-( what if else ??? */
4340 /*
4341 * check if we need to grow the cache buffers.
4342 */
4343 if (sizeCache <= nbCache) {
4344 sizeCache *= 2;
4345 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4346 sizeof(xmlNsPtr));
4347 if (oldNs == NULL) {
4348 xmlGenericError(xmlGenericErrorContext,
4349 "xmlReconciliateNs : memory pbm\n");
4350 xmlFree(newNs);
4351 return(-1);
4352 }
4353 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4354 sizeof(xmlNsPtr));
4355 if (newNs == NULL) {
4356 xmlGenericError(xmlGenericErrorContext,
4357 "xmlReconciliateNs : memory pbm\n");
4358 xmlFree(oldNs);
4359 return(-1);
4360 }
4361 }
4362 newNs[nbCache] = n;
4363 oldNs[nbCache++] = node->ns;
4364 node->ns = n;
4365 }
4366 }
4367 }
4368 /*
4369 * now check for namespace hold by attributes on the node.
4370 */
4371 attr = node->properties;
4372 while (attr != NULL) {
4373 if (attr->ns != NULL) {
4374 /*
4375 * initialize the cache if needed
4376 */
4377 if (sizeCache == 0) {
4378 sizeCache = 10;
4379 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4380 sizeof(xmlNsPtr));
4381 if (oldNs == NULL) {
4382 xmlGenericError(xmlGenericErrorContext,
4383 "xmlReconciliateNs : memory pbm\n");
4384 return(-1);
4385 }
4386 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4387 sizeof(xmlNsPtr));
4388 if (newNs == NULL) {
4389 xmlGenericError(xmlGenericErrorContext,
4390 "xmlReconciliateNs : memory pbm\n");
4391 xmlFree(oldNs);
4392 return(-1);
4393 }
4394 }
4395 for (i = 0;i < nbCache;i++) {
4396 if (oldNs[i] == attr->ns) {
4397 node->ns = newNs[i];
4398 break;
4399 }
4400 }
4401 if (i == nbCache) {
4402 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004403 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004404 */
4405 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4406 if (n != NULL) { /* :-( what if else ??? */
4407 /*
4408 * check if we need to grow the cache buffers.
4409 */
4410 if (sizeCache <= nbCache) {
4411 sizeCache *= 2;
4412 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4413 sizeof(xmlNsPtr));
4414 if (oldNs == NULL) {
4415 xmlGenericError(xmlGenericErrorContext,
4416 "xmlReconciliateNs : memory pbm\n");
4417 xmlFree(newNs);
4418 return(-1);
4419 }
4420 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4421 sizeof(xmlNsPtr));
4422 if (newNs == NULL) {
4423 xmlGenericError(xmlGenericErrorContext,
4424 "xmlReconciliateNs : memory pbm\n");
4425 xmlFree(oldNs);
4426 return(-1);
4427 }
4428 }
4429 newNs[nbCache] = n;
4430 oldNs[nbCache++] = attr->ns;
4431 attr->ns = n;
4432 }
4433 }
4434 }
4435 attr = attr->next;
4436 }
4437
4438 /*
4439 * Browse the full subtree, deep first
4440 */
4441 if (node->children != NULL) {
4442 /* deep first */
4443 node = node->children;
4444 } else if ((node != tree) && (node->next != NULL)) {
4445 /* then siblings */
4446 node = node->next;
4447 } else if (node != tree) {
4448 /* go up to parents->next if needed */
4449 while (node != tree) {
4450 if (node->parent != NULL)
4451 node = node->parent;
4452 if ((node != tree) && (node->next != NULL)) {
4453 node = node->next;
4454 break;
4455 }
4456 if (node->parent == NULL) {
4457 node = NULL;
4458 break;
4459 }
4460 }
4461 /* exit condition */
4462 if (node == tree)
4463 node = NULL;
4464 }
4465 }
4466 return(ret);
4467}
4468
4469/**
4470 * xmlHasProp:
4471 * @node: the node
4472 * @name: the attribute name
4473 *
4474 * Search an attribute associated to a node
4475 * This function also looks in DTD attribute declaration for #FIXED or
4476 * default declaration values unless DTD use has been turned off.
4477 *
4478 * Returns the attribute or the attribute declaration or NULL if
4479 * neither was found.
4480 */
4481xmlAttrPtr
4482xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4483 xmlAttrPtr prop;
4484 xmlDocPtr doc;
4485
4486 if ((node == NULL) || (name == NULL)) return(NULL);
4487 /*
4488 * Check on the properties attached to the node
4489 */
4490 prop = node->properties;
4491 while (prop != NULL) {
4492 if (xmlStrEqual(prop->name, name)) {
4493 return(prop);
4494 }
4495 prop = prop->next;
4496 }
4497 if (!xmlCheckDTD) return(NULL);
4498
4499 /*
4500 * Check if there is a default declaration in the internal
4501 * or external subsets
4502 */
4503 doc = node->doc;
4504 if (doc != NULL) {
4505 xmlAttributePtr attrDecl;
4506 if (doc->intSubset != NULL) {
4507 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4508 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4509 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4510 if (attrDecl != NULL)
4511 return((xmlAttrPtr) attrDecl);
4512 }
4513 }
4514 return(NULL);
4515}
4516
4517/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004518 * xmlHasNsProp:
4519 * @node: the node
4520 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004521 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004522 *
4523 * Search for an attribute associated to a node
4524 * This attribute has to be anchored in the namespace specified.
4525 * This does the entity substitution.
4526 * This function looks in DTD attribute declaration for #FIXED or
4527 * default declaration values unless DTD use has been turned off.
4528 *
4529 * Returns the attribute or the attribute declaration or NULL
4530 * if neither was found.
4531 */
4532xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004533xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004534 xmlAttrPtr prop;
4535 xmlDocPtr doc;
4536 xmlNsPtr ns;
4537
4538 if (node == NULL)
4539 return(NULL);
4540
4541 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004542 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004543 return(xmlHasProp(node, name));
4544 while (prop != NULL) {
4545 /*
4546 * One need to have
4547 * - same attribute names
4548 * - and the attribute carrying that namespace
4549 * or
4550 * no namespace on the attribute and the element carrying it
4551 */
4552 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004553 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4554 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004555 }
4556 prop = prop->next;
4557 }
4558 if (!xmlCheckDTD) return(NULL);
4559
4560 /*
4561 * Check if there is a default declaration in the internal
4562 * or external subsets
4563 */
4564 doc = node->doc;
4565 if (doc != NULL) {
4566 if (doc->intSubset != NULL) {
4567 xmlAttributePtr attrDecl;
4568
4569 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4570 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4571 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4572
4573 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4574 /*
4575 * The DTD declaration only allows a prefix search
4576 */
4577 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004578 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004579 return((xmlAttrPtr) attrDecl);
4580 }
4581 }
4582 }
4583 return(NULL);
4584}
4585
4586/**
Owen Taylor3473f882001-02-23 17:55:21 +00004587 * xmlGetProp:
4588 * @node: the node
4589 * @name: the attribute name
4590 *
4591 * Search and get the value of an attribute associated to a node
4592 * This does the entity substitution.
4593 * This function looks in DTD attribute declaration for #FIXED or
4594 * default declaration values unless DTD use has been turned off.
4595 *
4596 * Returns the attribute value or NULL if not found.
4597 * It's up to the caller to free the memory.
4598 */
4599xmlChar *
4600xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4601 xmlAttrPtr prop;
4602 xmlDocPtr doc;
4603
4604 if ((node == NULL) || (name == NULL)) return(NULL);
4605 /*
4606 * Check on the properties attached to the node
4607 */
4608 prop = node->properties;
4609 while (prop != NULL) {
4610 if (xmlStrEqual(prop->name, name)) {
4611 xmlChar *ret;
4612
4613 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4614 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4615 return(ret);
4616 }
4617 prop = prop->next;
4618 }
4619 if (!xmlCheckDTD) return(NULL);
4620
4621 /*
4622 * Check if there is a default declaration in the internal
4623 * or external subsets
4624 */
4625 doc = node->doc;
4626 if (doc != NULL) {
4627 xmlAttributePtr attrDecl;
4628 if (doc->intSubset != NULL) {
4629 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4630 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4631 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4632 if (attrDecl != NULL)
4633 return(xmlStrdup(attrDecl->defaultValue));
4634 }
4635 }
4636 return(NULL);
4637}
4638
4639/**
4640 * xmlGetNsProp:
4641 * @node: the node
4642 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004643 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004644 *
4645 * Search and get the value of an attribute associated to a node
4646 * This attribute has to be anchored in the namespace specified.
4647 * This does the entity substitution.
4648 * This function looks in DTD attribute declaration for #FIXED or
4649 * default declaration values unless DTD use has been turned off.
4650 *
4651 * Returns the attribute value or NULL if not found.
4652 * It's up to the caller to free the memory.
4653 */
4654xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004655xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004656 xmlAttrPtr prop;
4657 xmlDocPtr doc;
4658 xmlNsPtr ns;
4659
4660 if (node == NULL)
4661 return(NULL);
4662
4663 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004664 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004665 return(xmlGetProp(node, name));
4666 while (prop != NULL) {
4667 /*
4668 * One need to have
4669 * - same attribute names
4670 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004671 */
4672 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004673 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004674 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004675 xmlChar *ret;
4676
4677 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4678 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4679 return(ret);
4680 }
4681 prop = prop->next;
4682 }
4683 if (!xmlCheckDTD) return(NULL);
4684
4685 /*
4686 * Check if there is a default declaration in the internal
4687 * or external subsets
4688 */
4689 doc = node->doc;
4690 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004691 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004692 xmlAttributePtr attrDecl;
4693
Owen Taylor3473f882001-02-23 17:55:21 +00004694 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4695 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4696 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4697
4698 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4699 /*
4700 * The DTD declaration only allows a prefix search
4701 */
4702 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004703 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004704 return(xmlStrdup(attrDecl->defaultValue));
4705 }
4706 }
4707 }
4708 return(NULL);
4709}
4710
4711/**
4712 * xmlSetProp:
4713 * @node: the node
4714 * @name: the attribute name
4715 * @value: the attribute value
4716 *
4717 * Set (or reset) an attribute carried by a node.
4718 * Returns the attribute pointer.
4719 */
4720xmlAttrPtr
4721xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004722 xmlAttrPtr prop;
4723 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004724
4725 if ((node == NULL) || (name == NULL))
4726 return(NULL);
4727 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004728 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004729 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004730 if ((xmlStrEqual(prop->name, name)) &&
4731 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004732 xmlNodePtr oldprop = prop->children;
4733
Owen Taylor3473f882001-02-23 17:55:21 +00004734 prop->children = NULL;
4735 prop->last = NULL;
4736 if (value != NULL) {
4737 xmlChar *buffer;
4738 xmlNodePtr tmp;
4739
4740 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4741 prop->children = xmlStringGetNodeList(node->doc, buffer);
4742 prop->last = NULL;
4743 prop->doc = doc;
4744 tmp = prop->children;
4745 while (tmp != NULL) {
4746 tmp->parent = (xmlNodePtr) prop;
4747 tmp->doc = doc;
4748 if (tmp->next == NULL)
4749 prop->last = tmp;
4750 tmp = tmp->next;
4751 }
4752 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004753 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004754 if (oldprop != NULL)
4755 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004756 return(prop);
4757 }
4758 prop = prop->next;
4759 }
4760 prop = xmlNewProp(node, name, value);
4761 return(prop);
4762}
4763
4764/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004765 * xmlUnsetProp:
4766 * @node: the node
4767 * @name: the attribute name
4768 *
4769 * Remove an attribute carried by a node.
4770 * Returns 0 if successful, -1 if not found
4771 */
4772int
4773xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4774 xmlAttrPtr prop = node->properties, prev = NULL;;
4775
4776 if ((node == NULL) || (name == NULL))
4777 return(-1);
4778 while (prop != NULL) {
4779 if ((xmlStrEqual(prop->name, name)) &&
4780 (prop->ns == NULL)) {
4781 if (prev == NULL)
4782 node->properties = prop->next;
4783 else
4784 prev->next = prop->next;
4785 xmlFreeProp(prop);
4786 return(0);
4787 }
4788 prev = prop;
4789 prop = prop->next;
4790 }
4791 return(-1);
4792}
4793
4794/**
Owen Taylor3473f882001-02-23 17:55:21 +00004795 * xmlSetNsProp:
4796 * @node: the node
4797 * @ns: the namespace definition
4798 * @name: the attribute name
4799 * @value: the attribute value
4800 *
4801 * Set (or reset) an attribute carried by a node.
4802 * The ns structure must be in scope, this is not checked.
4803 *
4804 * Returns the attribute pointer.
4805 */
4806xmlAttrPtr
4807xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4808 const xmlChar *value) {
4809 xmlAttrPtr prop;
4810
4811 if ((node == NULL) || (name == NULL))
4812 return(NULL);
4813
4814 if (ns == NULL)
4815 return(xmlSetProp(node, name, value));
4816 if (ns->href == NULL)
4817 return(NULL);
4818 prop = node->properties;
4819
4820 while (prop != NULL) {
4821 /*
4822 * One need to have
4823 * - same attribute names
4824 * - and the attribute carrying that namespace
4825 * or
4826 * no namespace on the attribute and the element carrying it
4827 */
4828 if ((xmlStrEqual(prop->name, name)) &&
4829 (((prop->ns == NULL) && (node->ns != NULL) &&
4830 (xmlStrEqual(node->ns->href, ns->href))) ||
4831 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4832 if (prop->children != NULL)
4833 xmlFreeNodeList(prop->children);
4834 prop->children = NULL;
4835 prop->last = NULL;
4836 prop->ns = ns;
4837 if (value != NULL) {
4838 xmlChar *buffer;
4839 xmlNodePtr tmp;
4840
4841 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4842 prop->children = xmlStringGetNodeList(node->doc, buffer);
4843 prop->last = NULL;
4844 tmp = prop->children;
4845 while (tmp != NULL) {
4846 tmp->parent = (xmlNodePtr) prop;
4847 if (tmp->next == NULL)
4848 prop->last = tmp;
4849 tmp = tmp->next;
4850 }
4851 xmlFree(buffer);
4852 }
4853 return(prop);
4854 }
4855 prop = prop->next;
4856 }
4857 prop = xmlNewNsProp(node, ns, name, value);
4858 return(prop);
4859}
4860
4861/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004862 * xmlUnsetNsProp:
4863 * @node: the node
4864 * @ns: the namespace definition
4865 * @name: the attribute name
4866 *
4867 * Remove an attribute carried by a node.
4868 * Returns 0 if successful, -1 if not found
4869 */
4870int
4871xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4872 xmlAttrPtr prop = node->properties, prev = NULL;;
4873
4874 if ((node == NULL) || (name == NULL))
4875 return(-1);
4876 if (ns == NULL)
4877 return(xmlUnsetProp(node, name));
4878 if (ns->href == NULL)
4879 return(-1);
4880 while (prop != NULL) {
4881 if ((xmlStrEqual(prop->name, name)) &&
4882 (((prop->ns == NULL) && (node->ns != NULL) &&
4883 (xmlStrEqual(node->ns->href, ns->href))) ||
4884 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4885 if (prev == NULL)
4886 node->properties = prop->next;
4887 else
4888 prev->next = prop->next;
4889 xmlFreeProp(prop);
4890 return(0);
4891 }
4892 prev = prop;
4893 prop = prop->next;
4894 }
4895 return(-1);
4896}
4897
4898/**
Owen Taylor3473f882001-02-23 17:55:21 +00004899 * xmlNodeIsText:
4900 * @node: the node
4901 *
4902 * Is this node a Text node ?
4903 * Returns 1 yes, 0 no
4904 */
4905int
4906xmlNodeIsText(xmlNodePtr node) {
4907 if (node == NULL) return(0);
4908
4909 if (node->type == XML_TEXT_NODE) return(1);
4910 return(0);
4911}
4912
4913/**
4914 * xmlIsBlankNode:
4915 * @node: the node
4916 *
4917 * Checks whether this node is an empty or whitespace only
4918 * (and possibly ignorable) text-node.
4919 *
4920 * Returns 1 yes, 0 no
4921 */
4922int
4923xmlIsBlankNode(xmlNodePtr node) {
4924 const xmlChar *cur;
4925 if (node == NULL) return(0);
4926
Daniel Veillard7db37732001-07-12 01:20:08 +00004927 if ((node->type != XML_TEXT_NODE) &&
4928 (node->type != XML_CDATA_SECTION_NODE))
4929 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004930 if (node->content == NULL) return(1);
4931#ifndef XML_USE_BUFFER_CONTENT
4932 cur = node->content;
4933#else
4934 cur = xmlBufferContent(node->content);
4935#endif
4936 while (*cur != 0) {
4937 if (!IS_BLANK(*cur)) return(0);
4938 cur++;
4939 }
4940
4941 return(1);
4942}
4943
4944/**
4945 * xmlTextConcat:
4946 * @node: the node
4947 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00004948 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00004949 *
4950 * Concat the given string at the end of the existing node content
4951 */
4952
4953void
4954xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4955 if (node == NULL) return;
4956
4957 if ((node->type != XML_TEXT_NODE) &&
4958 (node->type != XML_CDATA_SECTION_NODE)) {
4959#ifdef DEBUG_TREE
4960 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004961 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004962#endif
4963 return;
4964 }
4965#ifndef XML_USE_BUFFER_CONTENT
4966 node->content = xmlStrncat(node->content, content, len);
4967#else
4968 xmlBufferAdd(node->content, content, len);
4969#endif
4970}
4971
4972/************************************************************************
4973 * *
4974 * Output : to a FILE or in memory *
4975 * *
4976 ************************************************************************/
4977
Owen Taylor3473f882001-02-23 17:55:21 +00004978/**
4979 * xmlBufferCreate:
4980 *
4981 * routine to create an XML buffer.
4982 * returns the new structure.
4983 */
4984xmlBufferPtr
4985xmlBufferCreate(void) {
4986 xmlBufferPtr ret;
4987
4988 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4989 if (ret == NULL) {
4990 xmlGenericError(xmlGenericErrorContext,
4991 "xmlBufferCreate : out of memory!\n");
4992 return(NULL);
4993 }
4994 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004995 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004996 ret->alloc = xmlBufferAllocScheme;
4997 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4998 if (ret->content == NULL) {
4999 xmlGenericError(xmlGenericErrorContext,
5000 "xmlBufferCreate : out of memory!\n");
5001 xmlFree(ret);
5002 return(NULL);
5003 }
5004 ret->content[0] = 0;
5005 return(ret);
5006}
5007
5008/**
5009 * xmlBufferCreateSize:
5010 * @size: initial size of buffer
5011 *
5012 * routine to create an XML buffer.
5013 * returns the new structure.
5014 */
5015xmlBufferPtr
5016xmlBufferCreateSize(size_t size) {
5017 xmlBufferPtr ret;
5018
5019 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5020 if (ret == NULL) {
5021 xmlGenericError(xmlGenericErrorContext,
5022 "xmlBufferCreate : out of memory!\n");
5023 return(NULL);
5024 }
5025 ret->use = 0;
5026 ret->alloc = xmlBufferAllocScheme;
5027 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5028 if (ret->size){
5029 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5030 if (ret->content == NULL) {
5031 xmlGenericError(xmlGenericErrorContext,
5032 "xmlBufferCreate : out of memory!\n");
5033 xmlFree(ret);
5034 return(NULL);
5035 }
5036 ret->content[0] = 0;
5037 } else
5038 ret->content = NULL;
5039 return(ret);
5040}
5041
5042/**
5043 * xmlBufferSetAllocationScheme:
5044 * @buf: the buffer to free
5045 * @scheme: allocation scheme to use
5046 *
5047 * Sets the allocation scheme for this buffer
5048 */
5049void
5050xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5051 xmlBufferAllocationScheme scheme) {
5052 if (buf == NULL) {
5053#ifdef DEBUG_BUFFER
5054 xmlGenericError(xmlGenericErrorContext,
5055 "xmlBufferSetAllocationScheme: buf == NULL\n");
5056#endif
5057 return;
5058 }
5059
5060 buf->alloc = scheme;
5061}
5062
5063/**
5064 * xmlBufferFree:
5065 * @buf: the buffer to free
5066 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005067 * Frees an XML buffer. It frees both the content and the structure which
5068 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005069 */
5070void
5071xmlBufferFree(xmlBufferPtr buf) {
5072 if (buf == NULL) {
5073#ifdef DEBUG_BUFFER
5074 xmlGenericError(xmlGenericErrorContext,
5075 "xmlBufferFree: buf == NULL\n");
5076#endif
5077 return;
5078 }
5079 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005080 xmlFree(buf->content);
5081 }
Owen Taylor3473f882001-02-23 17:55:21 +00005082 xmlFree(buf);
5083}
5084
5085/**
5086 * xmlBufferEmpty:
5087 * @buf: the buffer
5088 *
5089 * empty a buffer.
5090 */
5091void
5092xmlBufferEmpty(xmlBufferPtr buf) {
5093 if (buf->content == NULL) return;
5094 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005095 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005096}
5097
5098/**
5099 * xmlBufferShrink:
5100 * @buf: the buffer to dump
5101 * @len: the number of xmlChar to remove
5102 *
5103 * Remove the beginning of an XML buffer.
5104 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005105 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005106 */
5107int
5108xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5109 if (len == 0) return(0);
5110 if (len > buf->use) return(-1);
5111
5112 buf->use -= len;
5113 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5114
5115 buf->content[buf->use] = 0;
5116 return(len);
5117}
5118
5119/**
5120 * xmlBufferGrow:
5121 * @buf: the buffer
5122 * @len: the minimum free size to allocate
5123 *
5124 * Grow the available space of an XML buffer.
5125 *
5126 * Returns the new available space or -1 in case of error
5127 */
5128int
5129xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5130 int size;
5131 xmlChar *newbuf;
5132
5133 if (len + buf->use < buf->size) return(0);
5134
5135 size = buf->use + len + 100;
5136
5137 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5138 if (newbuf == NULL) return(-1);
5139 buf->content = newbuf;
5140 buf->size = size;
5141 return(buf->size - buf->use);
5142}
5143
5144/**
5145 * xmlBufferDump:
5146 * @file: the file output
5147 * @buf: the buffer to dump
5148 *
5149 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005150 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005151 */
5152int
5153xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5154 int ret;
5155
5156 if (buf == NULL) {
5157#ifdef DEBUG_BUFFER
5158 xmlGenericError(xmlGenericErrorContext,
5159 "xmlBufferDump: buf == NULL\n");
5160#endif
5161 return(0);
5162 }
5163 if (buf->content == NULL) {
5164#ifdef DEBUG_BUFFER
5165 xmlGenericError(xmlGenericErrorContext,
5166 "xmlBufferDump: buf->content == NULL\n");
5167#endif
5168 return(0);
5169 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005170 if (file == NULL)
5171 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005172 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5173 return(ret);
5174}
5175
5176/**
5177 * xmlBufferContent:
5178 * @buf: the buffer
5179 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005180 * Function to extract the content of a buffer
5181 *
Owen Taylor3473f882001-02-23 17:55:21 +00005182 * Returns the internal content
5183 */
5184
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005185const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005186xmlBufferContent(const xmlBufferPtr buf)
5187{
5188 if(!buf)
5189 return NULL;
5190
5191 return buf->content;
5192}
5193
5194/**
5195 * xmlBufferLength:
5196 * @buf: the buffer
5197 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005198 * Function to get the length of a buffer
5199 *
Owen Taylor3473f882001-02-23 17:55:21 +00005200 * Returns the length of data in the internal content
5201 */
5202
5203int
5204xmlBufferLength(const xmlBufferPtr buf)
5205{
5206 if(!buf)
5207 return 0;
5208
5209 return buf->use;
5210}
5211
5212/**
5213 * xmlBufferResize:
5214 * @buf: the buffer to resize
5215 * @size: the desired size
5216 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005217 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005218 *
5219 * Returns 0 in case of problems, 1 otherwise
5220 */
5221int
5222xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5223{
5224 unsigned int newSize;
5225 xmlChar* rebuf = NULL;
5226
5227 /*take care of empty case*/
5228 newSize = (buf->size ? buf->size*2 : size);
5229
5230 /* Don't resize if we don't have to */
5231 if (size < buf->size)
5232 return 1;
5233
5234 /* figure out new size */
5235 switch (buf->alloc){
5236 case XML_BUFFER_ALLOC_DOUBLEIT:
5237 while (size > newSize) newSize *= 2;
5238 break;
5239 case XML_BUFFER_ALLOC_EXACT:
5240 newSize = size+10;
5241 break;
5242 default:
5243 newSize = size+10;
5244 break;
5245 }
5246
5247 if (buf->content == NULL)
5248 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5249 else
5250 rebuf = (xmlChar *) xmlRealloc(buf->content,
5251 newSize * sizeof(xmlChar));
5252 if (rebuf == NULL) {
5253 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005254 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005255 return 0;
5256 }
5257 buf->content = rebuf;
5258 buf->size = newSize;
5259
5260 return 1;
5261}
5262
5263/**
5264 * xmlBufferAdd:
5265 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005266 * @str: the #xmlChar string
5267 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005268 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005269 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005270 * str is recomputed.
5271 */
5272void
5273xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5274 unsigned int needSize;
5275
5276 if (str == NULL) {
5277#ifdef DEBUG_BUFFER
5278 xmlGenericError(xmlGenericErrorContext,
5279 "xmlBufferAdd: str == NULL\n");
5280#endif
5281 return;
5282 }
5283 if (len < -1) {
5284#ifdef DEBUG_BUFFER
5285 xmlGenericError(xmlGenericErrorContext,
5286 "xmlBufferAdd: len < 0\n");
5287#endif
5288 return;
5289 }
5290 if (len == 0) return;
5291
5292 if (len < 0)
5293 len = xmlStrlen(str);
5294
5295 if (len <= 0) return;
5296
5297 needSize = buf->use + len + 2;
5298 if (needSize > buf->size){
5299 if (!xmlBufferResize(buf, needSize)){
5300 xmlGenericError(xmlGenericErrorContext,
5301 "xmlBufferAdd : out of memory!\n");
5302 return;
5303 }
5304 }
5305
5306 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5307 buf->use += len;
5308 buf->content[buf->use] = 0;
5309}
5310
5311/**
5312 * xmlBufferAddHead:
5313 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005314 * @str: the #xmlChar string
5315 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005316 *
5317 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005318 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005319 */
5320void
5321xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5322 unsigned int needSize;
5323
5324 if (str == NULL) {
5325#ifdef DEBUG_BUFFER
5326 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005327 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005328#endif
5329 return;
5330 }
5331 if (len < -1) {
5332#ifdef DEBUG_BUFFER
5333 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005334 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005335#endif
5336 return;
5337 }
5338 if (len == 0) return;
5339
5340 if (len < 0)
5341 len = xmlStrlen(str);
5342
5343 if (len <= 0) return;
5344
5345 needSize = buf->use + len + 2;
5346 if (needSize > buf->size){
5347 if (!xmlBufferResize(buf, needSize)){
5348 xmlGenericError(xmlGenericErrorContext,
5349 "xmlBufferAddHead : out of memory!\n");
5350 return;
5351 }
5352 }
5353
5354 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5355 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5356 buf->use += len;
5357 buf->content[buf->use] = 0;
5358}
5359
5360/**
5361 * xmlBufferCat:
5362 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005363 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005364 *
5365 * Append a zero terminated string to an XML buffer.
5366 */
5367void
5368xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5369 if (str != NULL)
5370 xmlBufferAdd(buf, str, -1);
5371}
5372
5373/**
5374 * xmlBufferCCat:
5375 * @buf: the buffer to dump
5376 * @str: the C char string
5377 *
5378 * Append a zero terminated C string to an XML buffer.
5379 */
5380void
5381xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5382 const char *cur;
5383
5384 if (str == NULL) {
5385#ifdef DEBUG_BUFFER
5386 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005387 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005388#endif
5389 return;
5390 }
5391 for (cur = str;*cur != 0;cur++) {
5392 if (buf->use + 10 >= buf->size) {
5393 if (!xmlBufferResize(buf, buf->use+10)){
5394 xmlGenericError(xmlGenericErrorContext,
5395 "xmlBufferCCat : out of memory!\n");
5396 return;
5397 }
5398 }
5399 buf->content[buf->use++] = *cur;
5400 }
5401 buf->content[buf->use] = 0;
5402}
5403
5404/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005405 * xmlBufferWriteXmlCHAR:
5406 * @buf: the XML buffer
5407 * @string: the string to add
5408 *
5409 * For VMS only.
5410 * routine which manages and grows an output buffer. This one adds
5411 * xmlChars at the end of the buffer.
5412 */
5413/**
Owen Taylor3473f882001-02-23 17:55:21 +00005414 * xmlBufferWriteCHAR:
5415 * @buf: the XML buffer
5416 * @string: the string to add
5417 *
5418 * routine which manages and grows an output buffer. This one adds
5419 * xmlChars at the end of the buffer.
5420 */
5421void
5422#ifdef VMS
5423xmlBufferWriteXmlCHAR
5424#else
5425xmlBufferWriteCHAR
5426#endif
5427(xmlBufferPtr buf, const xmlChar *string) {
5428 xmlBufferCat(buf, string);
5429}
5430
5431/**
5432 * xmlBufferWriteChar:
5433 * @buf: the XML buffer output
5434 * @string: the string to add
5435 *
5436 * routine which manage and grows an output buffer. This one add
5437 * C chars at the end of the array.
5438 */
5439void
5440xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5441 xmlBufferCCat(buf, string);
5442}
5443
5444
5445/**
5446 * xmlBufferWriteQuotedString:
5447 * @buf: the XML buffer output
5448 * @string: the string to add
5449 *
5450 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005451 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005452 * quote or double-quotes internally
5453 */
5454void
5455xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5456 if (xmlStrchr(string, '"')) {
5457 if (xmlStrchr(string, '\'')) {
5458#ifdef DEBUG_BUFFER
5459 xmlGenericError(xmlGenericErrorContext,
5460 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5461#endif
5462 }
5463 xmlBufferCCat(buf, "'");
5464 xmlBufferCat(buf, string);
5465 xmlBufferCCat(buf, "'");
5466 } else {
5467 xmlBufferCCat(buf, "\"");
5468 xmlBufferCat(buf, string);
5469 xmlBufferCCat(buf, "\"");
5470 }
5471}
5472
5473
5474/************************************************************************
5475 * *
5476 * Dumping XML tree content to a simple buffer *
5477 * *
5478 ************************************************************************/
5479
5480void
5481xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5482 int format);
5483static void
5484xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5485 int format);
5486void
5487htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5488
5489/**
5490 * xmlNsDump:
5491 * @buf: the XML buffer output
5492 * @cur: a namespace
5493 *
5494 * Dump a local Namespace definition.
5495 * Should be called in the context of attributes dumps.
5496 */
5497static void
5498xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5499 if (cur == NULL) {
5500#ifdef DEBUG_TREE
5501 xmlGenericError(xmlGenericErrorContext,
5502 "xmlNsDump : Ns == NULL\n");
5503#endif
5504 return;
5505 }
5506 if (cur->type == XML_LOCAL_NAMESPACE) {
5507 /* Within the context of an element attributes */
5508 if (cur->prefix != NULL) {
5509 xmlBufferWriteChar(buf, " xmlns:");
5510 xmlBufferWriteCHAR(buf, cur->prefix);
5511 } else
5512 xmlBufferWriteChar(buf, " xmlns");
5513 xmlBufferWriteChar(buf, "=");
5514 xmlBufferWriteQuotedString(buf, cur->href);
5515 }
5516}
5517
5518/**
5519 * xmlNsListDump:
5520 * @buf: the XML buffer output
5521 * @cur: the first namespace
5522 *
5523 * Dump a list of local Namespace definitions.
5524 * Should be called in the context of attributes dumps.
5525 */
5526static void
5527xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5528 while (cur != NULL) {
5529 xmlNsDump(buf, cur);
5530 cur = cur->next;
5531 }
5532}
5533
5534/**
5535 * xmlDtdDump:
5536 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005537 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005538 *
5539 * Dump the XML document DTD, if any.
5540 */
5541static void
5542xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5543 if (dtd == NULL) {
5544#ifdef DEBUG_TREE
5545 xmlGenericError(xmlGenericErrorContext,
5546 "xmlDtdDump : no internal subset\n");
5547#endif
5548 return;
5549 }
5550 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5551 xmlBufferWriteCHAR(buf, dtd->name);
5552 if (dtd->ExternalID != NULL) {
5553 xmlBufferWriteChar(buf, " PUBLIC ");
5554 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5555 xmlBufferWriteChar(buf, " ");
5556 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5557 } else if (dtd->SystemID != NULL) {
5558 xmlBufferWriteChar(buf, " SYSTEM ");
5559 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5560 }
5561 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5562 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5563 xmlBufferWriteChar(buf, ">");
5564 return;
5565 }
5566 xmlBufferWriteChar(buf, " [\n");
5567 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5568#if 0
5569 if (dtd->entities != NULL)
5570 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5571 if (dtd->notations != NULL)
5572 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5573 if (dtd->elements != NULL)
5574 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5575 if (dtd->attributes != NULL)
5576 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5577#endif
5578 xmlBufferWriteChar(buf, "]>");
5579}
5580
5581/**
5582 * xmlAttrDump:
5583 * @buf: the XML buffer output
5584 * @doc: the document
5585 * @cur: the attribute pointer
5586 *
5587 * Dump an XML attribute
5588 */
5589static void
5590xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5591 xmlChar *value;
5592
5593 if (cur == NULL) {
5594#ifdef DEBUG_TREE
5595 xmlGenericError(xmlGenericErrorContext,
5596 "xmlAttrDump : property == NULL\n");
5597#endif
5598 return;
5599 }
5600 xmlBufferWriteChar(buf, " ");
5601 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5602 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5603 xmlBufferWriteChar(buf, ":");
5604 }
5605 xmlBufferWriteCHAR(buf, cur->name);
5606 value = xmlNodeListGetString(doc, cur->children, 0);
5607 if (value != NULL) {
5608 xmlBufferWriteChar(buf, "=");
5609 xmlBufferWriteQuotedString(buf, value);
5610 xmlFree(value);
5611 } else {
5612 xmlBufferWriteChar(buf, "=\"\"");
5613 }
5614}
5615
5616/**
5617 * xmlAttrListDump:
5618 * @buf: the XML buffer output
5619 * @doc: the document
5620 * @cur: the first attribute pointer
5621 *
5622 * Dump a list of XML attributes
5623 */
5624static void
5625xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5626 if (cur == NULL) {
5627#ifdef DEBUG_TREE
5628 xmlGenericError(xmlGenericErrorContext,
5629 "xmlAttrListDump : property == NULL\n");
5630#endif
5631 return;
5632 }
5633 while (cur != NULL) {
5634 xmlAttrDump(buf, doc, cur);
5635 cur = cur->next;
5636 }
5637}
5638
5639
5640
5641/**
5642 * xmlNodeListDump:
5643 * @buf: the XML buffer output
5644 * @doc: the document
5645 * @cur: the first node
5646 * @level: the imbrication level for indenting
5647 * @format: is formatting allowed
5648 *
5649 * Dump an XML node list, recursive behaviour,children are printed too.
5650 */
5651static void
5652xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5653 int format) {
5654 int i;
5655
5656 if (cur == NULL) {
5657#ifdef DEBUG_TREE
5658 xmlGenericError(xmlGenericErrorContext,
5659 "xmlNodeListDump : node == NULL\n");
5660#endif
5661 return;
5662 }
5663 while (cur != NULL) {
5664 if ((format) && (xmlIndentTreeOutput) &&
5665 (cur->type == XML_ELEMENT_NODE))
5666 for (i = 0;i < level;i++)
5667 xmlBufferWriteChar(buf, " ");
5668 xmlNodeDump(buf, doc, cur, level, format);
5669 if (format) {
5670 xmlBufferWriteChar(buf, "\n");
5671 }
5672 cur = cur->next;
5673 }
5674}
5675
5676/**
5677 * xmlNodeDump:
5678 * @buf: the XML buffer output
5679 * @doc: the document
5680 * @cur: the current node
5681 * @level: the imbrication level for indenting
5682 * @format: is formatting allowed
5683 *
5684 * Dump an XML node, recursive behaviour,children are printed too.
5685 */
5686void
5687xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5688 int format) {
5689 int i;
5690 xmlNodePtr tmp;
5691
5692 if (cur == NULL) {
5693#ifdef DEBUG_TREE
5694 xmlGenericError(xmlGenericErrorContext,
5695 "xmlNodeDump : node == NULL\n");
5696#endif
5697 return;
5698 }
5699 if (cur->type == XML_XINCLUDE_START)
5700 return;
5701 if (cur->type == XML_XINCLUDE_END)
5702 return;
5703 if (cur->type == XML_DTD_NODE) {
5704 xmlDtdDump(buf, (xmlDtdPtr) cur);
5705 return;
5706 }
5707 if (cur->type == XML_ELEMENT_DECL) {
5708 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5709 return;
5710 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005711 if (cur->type == XML_ATTRIBUTE_NODE){
5712 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5713 return;
5714 }
Owen Taylor3473f882001-02-23 17:55:21 +00005715 if (cur->type == XML_ATTRIBUTE_DECL) {
5716 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5717 return;
5718 }
5719 if (cur->type == XML_ENTITY_DECL) {
5720 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5721 return;
5722 }
5723 if (cur->type == XML_TEXT_NODE) {
5724 if (cur->content != NULL) {
5725 if ((cur->name == xmlStringText) ||
5726 (cur->name != xmlStringTextNoenc)) {
5727 xmlChar *buffer;
5728
5729#ifndef XML_USE_BUFFER_CONTENT
5730 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5731#else
5732 buffer = xmlEncodeEntitiesReentrant(doc,
5733 xmlBufferContent(cur->content));
5734#endif
5735 if (buffer != NULL) {
5736 xmlBufferWriteCHAR(buf, buffer);
5737 xmlFree(buffer);
5738 }
5739 } else {
5740 /*
5741 * Disable escaping, needed for XSLT
5742 */
5743#ifndef XML_USE_BUFFER_CONTENT
5744 xmlBufferWriteCHAR(buf, cur->content);
5745#else
5746 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5747#endif
5748 }
5749 }
5750 return;
5751 }
5752 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005753 xmlBufferWriteChar(buf, "<?");
5754 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005755 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005756 xmlBufferWriteChar(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00005757#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard2c748c62002-01-16 15:37:50 +00005758 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005759#else
Daniel Veillard2c748c62002-01-16 15:37:50 +00005760 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00005761#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005762 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00005763 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00005764 return;
5765 }
5766 if (cur->type == XML_COMMENT_NODE) {
5767 if (cur->content != NULL) {
5768 xmlBufferWriteChar(buf, "<!--");
5769#ifndef XML_USE_BUFFER_CONTENT
5770 xmlBufferWriteCHAR(buf, cur->content);
5771#else
5772 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5773#endif
5774 xmlBufferWriteChar(buf, "-->");
5775 }
5776 return;
5777 }
5778 if (cur->type == XML_ENTITY_REF_NODE) {
5779 xmlBufferWriteChar(buf, "&");
5780 xmlBufferWriteCHAR(buf, cur->name);
5781 xmlBufferWriteChar(buf, ";");
5782 return;
5783 }
5784 if (cur->type == XML_CDATA_SECTION_NODE) {
5785 xmlBufferWriteChar(buf, "<![CDATA[");
5786 if (cur->content != NULL)
5787#ifndef XML_USE_BUFFER_CONTENT
5788 xmlBufferWriteCHAR(buf, cur->content);
5789#else
5790 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5791#endif
5792 xmlBufferWriteChar(buf, "]]>");
5793 return;
5794 }
5795
5796 if (format == 1) {
5797 tmp = cur->children;
5798 while (tmp != NULL) {
5799 if ((tmp->type == XML_TEXT_NODE) ||
5800 (tmp->type == XML_ENTITY_REF_NODE)) {
5801 format = 0;
5802 break;
5803 }
5804 tmp = tmp->next;
5805 }
5806 }
5807 xmlBufferWriteChar(buf, "<");
5808 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5809 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5810 xmlBufferWriteChar(buf, ":");
5811 }
5812
5813 xmlBufferWriteCHAR(buf, cur->name);
5814 if (cur->nsDef)
5815 xmlNsListDump(buf, cur->nsDef);
5816 if (cur->properties != NULL)
5817 xmlAttrListDump(buf, doc, cur->properties);
5818
Daniel Veillard7db37732001-07-12 01:20:08 +00005819 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5820 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005821 (!xmlSaveNoEmptyTags)) {
5822 xmlBufferWriteChar(buf, "/>");
5823 return;
5824 }
5825 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005826 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005827 xmlChar *buffer;
5828
5829#ifndef XML_USE_BUFFER_CONTENT
5830 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5831#else
5832 buffer = xmlEncodeEntitiesReentrant(doc,
5833 xmlBufferContent(cur->content));
5834#endif
5835 if (buffer != NULL) {
5836 xmlBufferWriteCHAR(buf, buffer);
5837 xmlFree(buffer);
5838 }
5839 }
5840 if (cur->children != NULL) {
5841 if (format) xmlBufferWriteChar(buf, "\n");
5842 xmlNodeListDump(buf, doc, cur->children,
5843 (level >= 0?level+1:-1), format);
5844 if ((xmlIndentTreeOutput) && (format))
5845 for (i = 0;i < level;i++)
5846 xmlBufferWriteChar(buf, " ");
5847 }
5848 xmlBufferWriteChar(buf, "</");
5849 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5850 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5851 xmlBufferWriteChar(buf, ":");
5852 }
5853
5854 xmlBufferWriteCHAR(buf, cur->name);
5855 xmlBufferWriteChar(buf, ">");
5856}
5857
5858/**
5859 * xmlElemDump:
5860 * @f: the FILE * for the output
5861 * @doc: the document
5862 * @cur: the current node
5863 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005864 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00005865 */
5866void
5867xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5868 xmlBufferPtr buf;
5869
5870 if (cur == NULL) {
5871#ifdef DEBUG_TREE
5872 xmlGenericError(xmlGenericErrorContext,
5873 "xmlElemDump : cur == NULL\n");
5874#endif
5875 return;
5876 }
Owen Taylor3473f882001-02-23 17:55:21 +00005877#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005878 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005879 xmlGenericError(xmlGenericErrorContext,
5880 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005881 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005882#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005883
Owen Taylor3473f882001-02-23 17:55:21 +00005884 buf = xmlBufferCreate();
5885 if (buf == NULL) return;
5886 if ((doc != NULL) &&
5887 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5888#ifdef LIBXML_HTML_ENABLED
5889 htmlNodeDump(buf, doc, cur);
5890#else
5891 xmlGenericError(xmlGenericErrorContext,
5892 "HTML support not compiled in\n");
5893#endif /* LIBXML_HTML_ENABLED */
5894 } else
5895 xmlNodeDump(buf, doc, cur, 0, 1);
5896 xmlBufferDump(f, buf);
5897 xmlBufferFree(buf);
5898}
5899
5900/************************************************************************
5901 * *
5902 * Dumping XML tree content to an I/O output buffer *
5903 * *
5904 ************************************************************************/
5905
5906void
5907xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5908 int level, int format, const char *encoding);
5909static void
5910xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5911 int level, int format, const char *encoding);
5912/**
5913 * xmlNsDumpOutput:
5914 * @buf: the XML buffer output
5915 * @cur: a namespace
5916 *
5917 * Dump a local Namespace definition.
5918 * Should be called in the context of attributes dumps.
5919 */
5920static void
5921xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5922 if (cur == NULL) {
5923#ifdef DEBUG_TREE
5924 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005925 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005926#endif
5927 return;
5928 }
5929 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5930 /* Within the context of an element attributes */
5931 if (cur->prefix != NULL) {
5932 xmlOutputBufferWriteString(buf, " xmlns:");
5933 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5934 } else
5935 xmlOutputBufferWriteString(buf, " xmlns");
5936 xmlOutputBufferWriteString(buf, "=");
5937 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5938 }
5939}
5940
5941/**
5942 * xmlNsListDumpOutput:
5943 * @buf: the XML buffer output
5944 * @cur: the first namespace
5945 *
5946 * Dump a list of local Namespace definitions.
5947 * Should be called in the context of attributes dumps.
5948 */
5949static void
5950xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5951 while (cur != NULL) {
5952 xmlNsDumpOutput(buf, cur);
5953 cur = cur->next;
5954 }
5955}
5956
5957/**
5958 * xmlDtdDumpOutput:
5959 * @buf: the XML buffer output
5960 * @doc: the document
5961 * @encoding: an optional encoding string
5962 *
5963 * Dump the XML document DTD, if any.
5964 */
5965static void
5966xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5967 if (dtd == NULL) {
5968#ifdef DEBUG_TREE
5969 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005970 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005971#endif
5972 return;
5973 }
5974 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5975 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5976 if (dtd->ExternalID != NULL) {
5977 xmlOutputBufferWriteString(buf, " PUBLIC ");
5978 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5979 xmlOutputBufferWriteString(buf, " ");
5980 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5981 } else if (dtd->SystemID != NULL) {
5982 xmlOutputBufferWriteString(buf, " SYSTEM ");
5983 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5984 }
5985 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5986 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5987 xmlOutputBufferWriteString(buf, ">");
5988 return;
5989 }
5990 xmlOutputBufferWriteString(buf, " [\n");
5991 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5992 xmlOutputBufferWriteString(buf, "]>");
5993}
5994
5995/**
5996 * xmlAttrDumpOutput:
5997 * @buf: the XML buffer output
5998 * @doc: the document
5999 * @cur: the attribute pointer
6000 * @encoding: an optional encoding string
6001 *
6002 * Dump an XML attribute
6003 */
6004static void
6005xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006006 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006007 xmlChar *value;
6008
6009 if (cur == NULL) {
6010#ifdef DEBUG_TREE
6011 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006012 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006013#endif
6014 return;
6015 }
6016 xmlOutputBufferWriteString(buf, " ");
6017 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6018 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6019 xmlOutputBufferWriteString(buf, ":");
6020 }
6021 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6022 value = xmlNodeListGetString(doc, cur->children, 0);
6023 if (value) {
6024 xmlOutputBufferWriteString(buf, "=");
6025 xmlBufferWriteQuotedString(buf->buffer, value);
6026 xmlFree(value);
6027 } else {
6028 xmlOutputBufferWriteString(buf, "=\"\"");
6029 }
6030}
6031
6032/**
6033 * xmlAttrListDumpOutput:
6034 * @buf: the XML buffer output
6035 * @doc: the document
6036 * @cur: the first attribute pointer
6037 * @encoding: an optional encoding string
6038 *
6039 * Dump a list of XML attributes
6040 */
6041static void
6042xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6043 xmlAttrPtr cur, const char *encoding) {
6044 if (cur == NULL) {
6045#ifdef DEBUG_TREE
6046 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006047 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006048#endif
6049 return;
6050 }
6051 while (cur != NULL) {
6052 xmlAttrDumpOutput(buf, doc, cur, encoding);
6053 cur = cur->next;
6054 }
6055}
6056
6057
6058
6059/**
6060 * xmlNodeListDumpOutput:
6061 * @buf: the XML buffer output
6062 * @doc: the document
6063 * @cur: the first node
6064 * @level: the imbrication level for indenting
6065 * @format: is formatting allowed
6066 * @encoding: an optional encoding string
6067 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006068 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006069 */
6070static void
6071xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6072 xmlNodePtr cur, int level, int format, const char *encoding) {
6073 int i;
6074
6075 if (cur == NULL) {
6076#ifdef DEBUG_TREE
6077 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006078 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006079#endif
6080 return;
6081 }
6082 while (cur != NULL) {
6083 if ((format) && (xmlIndentTreeOutput) &&
6084 (cur->type == XML_ELEMENT_NODE))
6085 for (i = 0;i < level;i++)
6086 xmlOutputBufferWriteString(buf, " ");
6087 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6088 if (format) {
6089 xmlOutputBufferWriteString(buf, "\n");
6090 }
6091 cur = cur->next;
6092 }
6093}
6094
6095/**
6096 * xmlNodeDumpOutput:
6097 * @buf: the XML buffer output
6098 * @doc: the document
6099 * @cur: the current node
6100 * @level: the imbrication level for indenting
6101 * @format: is formatting allowed
6102 * @encoding: an optional encoding string
6103 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006104 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006105 */
6106void
6107xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6108 int level, int format, const char *encoding) {
6109 int i;
6110 xmlNodePtr tmp;
6111
6112 if (cur == NULL) {
6113#ifdef DEBUG_TREE
6114 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006115 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006116#endif
6117 return;
6118 }
6119 if (cur->type == XML_XINCLUDE_START)
6120 return;
6121 if (cur->type == XML_XINCLUDE_END)
6122 return;
6123 if (cur->type == XML_DTD_NODE) {
6124 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6125 return;
6126 }
6127 if (cur->type == XML_ELEMENT_DECL) {
6128 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6129 return;
6130 }
6131 if (cur->type == XML_ATTRIBUTE_DECL) {
6132 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6133 return;
6134 }
6135 if (cur->type == XML_ENTITY_DECL) {
6136 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6137 return;
6138 }
6139 if (cur->type == XML_TEXT_NODE) {
6140 if (cur->content != NULL) {
6141 if ((cur->name == xmlStringText) ||
6142 (cur->name != xmlStringTextNoenc)) {
6143 xmlChar *buffer;
6144
6145#ifndef XML_USE_BUFFER_CONTENT
6146 if (encoding == NULL)
6147 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6148 else
6149 buffer = xmlEncodeSpecialChars(doc, cur->content);
6150#else
6151 if (encoding == NULL)
6152 buffer = xmlEncodeEntitiesReentrant(doc,
6153 xmlBufferContent(cur->content));
6154 else
6155 buffer = xmlEncodeSpecialChars(doc,
6156 xmlBufferContent(cur->content));
6157#endif
6158 if (buffer != NULL) {
6159 xmlOutputBufferWriteString(buf, (const char *)buffer);
6160 xmlFree(buffer);
6161 }
6162 } else {
6163 /*
6164 * Disable escaping, needed for XSLT
6165 */
6166#ifndef XML_USE_BUFFER_CONTENT
6167 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6168#else
6169 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6170#endif
6171 }
6172 }
6173
6174 return;
6175 }
6176 if (cur->type == XML_PI_NODE) {
6177 if (cur->content != NULL) {
6178 xmlOutputBufferWriteString(buf, "<?");
6179 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6180 if (cur->content != NULL) {
6181 xmlOutputBufferWriteString(buf, " ");
6182#ifndef XML_USE_BUFFER_CONTENT
6183 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6184#else
6185 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6186#endif
6187 }
6188 xmlOutputBufferWriteString(buf, "?>");
6189 } else {
6190 xmlOutputBufferWriteString(buf, "<?");
6191 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6192 xmlOutputBufferWriteString(buf, "?>");
6193 }
6194 return;
6195 }
6196 if (cur->type == XML_COMMENT_NODE) {
6197 if (cur->content != NULL) {
6198 xmlOutputBufferWriteString(buf, "<!--");
6199#ifndef XML_USE_BUFFER_CONTENT
6200 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6201#else
6202 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6203#endif
6204 xmlOutputBufferWriteString(buf, "-->");
6205 }
6206 return;
6207 }
6208 if (cur->type == XML_ENTITY_REF_NODE) {
6209 xmlOutputBufferWriteString(buf, "&");
6210 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6211 xmlOutputBufferWriteString(buf, ";");
6212 return;
6213 }
6214 if (cur->type == XML_CDATA_SECTION_NODE) {
6215 xmlOutputBufferWriteString(buf, "<![CDATA[");
6216 if (cur->content != NULL)
6217#ifndef XML_USE_BUFFER_CONTENT
6218 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6219#else
6220 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6221#endif
6222 xmlOutputBufferWriteString(buf, "]]>");
6223 return;
6224 }
6225
6226 if (format == 1) {
6227 tmp = cur->children;
6228 while (tmp != NULL) {
6229 if ((tmp->type == XML_TEXT_NODE) ||
6230 (tmp->type == XML_ENTITY_REF_NODE)) {
6231 format = 0;
6232 break;
6233 }
6234 tmp = tmp->next;
6235 }
6236 }
6237 xmlOutputBufferWriteString(buf, "<");
6238 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6239 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6240 xmlOutputBufferWriteString(buf, ":");
6241 }
6242
6243 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6244 if (cur->nsDef)
6245 xmlNsListDumpOutput(buf, cur->nsDef);
6246 if (cur->properties != NULL)
6247 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6248
Daniel Veillard7db37732001-07-12 01:20:08 +00006249 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6250 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006251 xmlOutputBufferWriteString(buf, "/>");
6252 return;
6253 }
6254 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006255 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006256 xmlChar *buffer;
6257
6258#ifndef XML_USE_BUFFER_CONTENT
6259 if (encoding == NULL)
6260 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6261 else
6262 buffer = xmlEncodeSpecialChars(doc, cur->content);
6263#else
6264 if (encoding == NULL)
6265 buffer = xmlEncodeEntitiesReentrant(doc,
6266 xmlBufferContent(cur->content));
6267 else
6268 buffer = xmlEncodeSpecialChars(doc,
6269 xmlBufferContent(cur->content));
6270#endif
6271 if (buffer != NULL) {
6272 xmlOutputBufferWriteString(buf, (const char *)buffer);
6273 xmlFree(buffer);
6274 }
6275 }
6276 if (cur->children != NULL) {
6277 if (format) xmlOutputBufferWriteString(buf, "\n");
6278 xmlNodeListDumpOutput(buf, doc, cur->children,
6279 (level >= 0?level+1:-1), format, encoding);
6280 if ((xmlIndentTreeOutput) && (format))
6281 for (i = 0;i < level;i++)
6282 xmlOutputBufferWriteString(buf, " ");
6283 }
6284 xmlOutputBufferWriteString(buf, "</");
6285 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6286 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6287 xmlOutputBufferWriteString(buf, ":");
6288 }
6289
6290 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6291 xmlOutputBufferWriteString(buf, ">");
6292}
6293
6294/**
6295 * xmlDocContentDumpOutput:
6296 * @buf: the XML buffer output
6297 * @cur: the document
6298 * @encoding: an optional encoding string
6299 * @format: should formatting spaces been added
6300 *
6301 * Dump an XML document.
6302 */
6303static void
6304xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6305 const char *encoding, int format) {
6306 xmlOutputBufferWriteString(buf, "<?xml version=");
6307 if (cur->version != NULL)
6308 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6309 else
6310 xmlOutputBufferWriteString(buf, "\"1.0\"");
6311 if (encoding == NULL) {
6312 if (cur->encoding != NULL)
6313 encoding = (const char *) cur->encoding;
6314 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6315 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6316 }
6317 if (encoding != NULL) {
6318 xmlOutputBufferWriteString(buf, " encoding=");
6319 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6320 }
6321 switch (cur->standalone) {
6322 case 0:
6323 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6324 break;
6325 case 1:
6326 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6327 break;
6328 }
6329 xmlOutputBufferWriteString(buf, "?>\n");
6330 if (cur->children != NULL) {
6331 xmlNodePtr child = cur->children;
6332
6333 while (child != NULL) {
6334 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6335 xmlOutputBufferWriteString(buf, "\n");
6336 child = child->next;
6337 }
6338 }
6339}
6340
6341/************************************************************************
6342 * *
6343 * Saving functions front-ends *
6344 * *
6345 ************************************************************************/
6346
6347/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006348 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006349 * @out_doc: Document to generate XML text from
6350 * @doc_txt_ptr: Memory pointer for allocated XML text
6351 * @doc_txt_len: Length of the generated XML text
6352 * @txt_encoding: Character encoding to use when generating XML text
6353 * @format: should formatting spaces been added
6354 *
6355 * Dump the current DOM tree into memory using the character encoding specified
6356 * by the caller. Note it is up to the caller of this function to free the
6357 * allocated memory.
6358 */
6359
6360void
6361xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006362 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006363 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006364 int dummy = 0;
6365
6366 xmlCharEncoding doc_charset;
6367 xmlOutputBufferPtr out_buff = NULL;
6368 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6369
6370 if (doc_txt_len == NULL) {
6371 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6372 }
6373
6374 if (doc_txt_ptr == NULL) {
6375 *doc_txt_len = 0;
6376 xmlGenericError(xmlGenericErrorContext,
6377 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6378 return;
6379 }
6380
6381 *doc_txt_ptr = NULL;
6382 *doc_txt_len = 0;
6383
6384 if (out_doc == NULL) {
6385 /* No document, no output */
6386 xmlGenericError(xmlGenericErrorContext,
6387 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6388 return;
6389 }
6390
6391 /*
6392 * Validate the encoding value, if provided.
6393 * This logic is copied from xmlSaveFileEnc.
6394 */
6395
6396 if (txt_encoding == NULL)
6397 txt_encoding = (const char *) out_doc->encoding;
6398 if (txt_encoding != NULL) {
6399 doc_charset = xmlParseCharEncoding(txt_encoding);
6400
6401 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6402 xmlGenericError(xmlGenericErrorContext,
6403 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6404 return;
6405
6406 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6407 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6408 if ( conv_hdlr == NULL ) {
6409 xmlGenericError(xmlGenericErrorContext,
6410 "%s: %s %s '%s'\n",
6411 "xmlDocDumpFormatMemoryEnc",
6412 "Failed to identify encoding handler for",
6413 "character set",
6414 txt_encoding);
6415 return;
6416 }
6417 }
6418 }
6419
6420 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6421 xmlGenericError(xmlGenericErrorContext,
6422 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6423 return;
6424 }
6425
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006426 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006427 xmlOutputBufferFlush(out_buff);
6428 if (out_buff->conv != NULL) {
6429 *doc_txt_len = out_buff->conv->use;
6430 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6431 } else {
6432 *doc_txt_len = out_buff->buffer->use;
6433 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6434 }
6435 (void)xmlOutputBufferClose(out_buff);
6436
6437 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6438 *doc_txt_len = 0;
6439 xmlGenericError(xmlGenericErrorContext,
6440 "xmlDocDumpFormatMemoryEnc: %s\n",
6441 "Failed to allocate memory for document text representation.");
6442 }
6443
6444 return;
6445}
6446
6447/**
6448 * xmlDocDumpMemory:
6449 * @cur: the document
6450 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006451 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006452 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006453 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006454 * It's up to the caller to free the memory.
6455 */
6456void
6457xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6458 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6459}
6460
6461/**
6462 * xmlDocDumpFormatMemory:
6463 * @cur: the document
6464 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006465 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006466 * @format: should formatting spaces been added
6467 *
6468 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006469 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006470 * It's up to the caller to free the memory.
6471 */
6472void
6473xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6474 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6475}
6476
6477/**
6478 * xmlDocDumpMemoryEnc:
6479 * @out_doc: Document to generate XML text from
6480 * @doc_txt_ptr: Memory pointer for allocated XML text
6481 * @doc_txt_len: Length of the generated XML text
6482 * @txt_encoding: Character encoding to use when generating XML text
6483 *
6484 * Dump the current DOM tree into memory using the character encoding specified
6485 * by the caller. Note it is up to the caller of this function to free the
6486 * allocated memory.
6487 */
6488
6489void
6490xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6491 int * doc_txt_len, const char * txt_encoding) {
6492 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006493 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006494}
6495
6496/**
6497 * xmlGetDocCompressMode:
6498 * @doc: the document
6499 *
6500 * get the compression ratio for a document, ZLIB based
6501 * Returns 0 (uncompressed) to 9 (max compression)
6502 */
6503int
6504xmlGetDocCompressMode (xmlDocPtr doc) {
6505 if (doc == NULL) return(-1);
6506 return(doc->compression);
6507}
6508
6509/**
6510 * xmlSetDocCompressMode:
6511 * @doc: the document
6512 * @mode: the compression ratio
6513 *
6514 * set the compression ratio for a document, ZLIB based
6515 * Correct values: 0 (uncompressed) to 9 (max compression)
6516 */
6517void
6518xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6519 if (doc == NULL) return;
6520 if (mode < 0) doc->compression = 0;
6521 else if (mode > 9) doc->compression = 9;
6522 else doc->compression = mode;
6523}
6524
6525/**
6526 * xmlGetCompressMode:
6527 *
6528 * get the default compression mode used, ZLIB based.
6529 * Returns 0 (uncompressed) to 9 (max compression)
6530 */
6531int
6532 xmlGetCompressMode(void) {
6533 return(xmlCompressMode);
6534}
6535
6536/**
6537 * xmlSetCompressMode:
6538 * @mode: the compression ratio
6539 *
6540 * set the default compression mode used, ZLIB based
6541 * Correct values: 0 (uncompressed) to 9 (max compression)
6542 */
6543void
6544xmlSetCompressMode(int mode) {
6545 if (mode < 0) xmlCompressMode = 0;
6546 else if (mode > 9) xmlCompressMode = 9;
6547 else xmlCompressMode = mode;
6548}
6549
6550/**
6551 * xmlDocDump:
6552 * @f: the FILE*
6553 * @cur: the document
6554 *
6555 * Dump an XML document to an open FILE.
6556 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006557 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006558 */
6559int
6560xmlDocDump(FILE *f, xmlDocPtr cur) {
6561 xmlOutputBufferPtr buf;
6562 const char * encoding;
6563 xmlCharEncodingHandlerPtr handler = NULL;
6564 int ret;
6565
6566 if (cur == NULL) {
6567#ifdef DEBUG_TREE
6568 xmlGenericError(xmlGenericErrorContext,
6569 "xmlDocDump : document == NULL\n");
6570#endif
6571 return(-1);
6572 }
6573 encoding = (const char *) cur->encoding;
6574
6575 if (encoding != NULL) {
6576 xmlCharEncoding enc;
6577
6578 enc = xmlParseCharEncoding(encoding);
6579
6580 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6581 xmlGenericError(xmlGenericErrorContext,
6582 "xmlDocDump: document not in UTF8\n");
6583 return(-1);
6584 }
6585 if (enc != XML_CHAR_ENCODING_UTF8) {
6586 handler = xmlFindCharEncodingHandler(encoding);
6587 if (handler == NULL) {
6588 xmlFree((char *) cur->encoding);
6589 cur->encoding = NULL;
6590 }
6591 }
6592 }
6593 buf = xmlOutputBufferCreateFile(f, handler);
6594 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006595 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006596
6597 ret = xmlOutputBufferClose(buf);
6598 return(ret);
6599}
6600
6601/**
6602 * xmlSaveFileTo:
6603 * @buf: an output I/O buffer
6604 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006605 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006606 *
6607 * Dump an XML document to an I/O buffer.
6608 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006609 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006610 */
6611int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006612xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006613 int ret;
6614
6615 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006616 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006617 ret = xmlOutputBufferClose(buf);
6618 return(ret);
6619}
6620
6621/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006622 * xmlSaveFormatFileTo:
6623 * @buf: an output I/O buffer
6624 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006625 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006626 * @format: should formatting spaces been added
6627 *
6628 * Dump an XML document to an I/O buffer.
6629 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006630 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006631 */
6632int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006633xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006634 int ret;
6635
6636 if (buf == NULL) return(0);
6637 xmlDocContentDumpOutput(buf, cur, encoding, format);
6638 ret = xmlOutputBufferClose(buf);
6639 return(ret);
6640}
6641
6642/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006643 * xmlSaveFormatFileEnc
6644 * @filename: the filename or URL to output
6645 * @cur: the document being saved
6646 * @encoding: the name of the encoding to use or NULL.
6647 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006648 *
6649 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006650 */
6651int
Daniel Veillardf012a642001-07-23 19:10:52 +00006652xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6653 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006654 xmlOutputBufferPtr buf;
6655 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006656 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006657 int ret;
6658
Daniel Veillardfb25a512002-01-13 20:32:08 +00006659 if (encoding == NULL)
6660 encoding = (const char *) cur->encoding;
6661
Owen Taylor3473f882001-02-23 17:55:21 +00006662 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006663
6664 enc = xmlParseCharEncoding(encoding);
6665 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6666 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006667 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006668 return(-1);
6669 }
6670 if (enc != XML_CHAR_ENCODING_UTF8) {
6671 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006672 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006673 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006674 }
6675 }
6676
Daniel Veillardf012a642001-07-23 19:10:52 +00006677#ifdef HAVE_ZLIB_H
6678 if (cur->compression < 0) cur->compression = xmlCompressMode;
6679#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006680 /*
6681 * save the content to a temp buffer.
6682 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006683 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006684 if (buf == NULL) return(-1);
6685
Daniel Veillardf012a642001-07-23 19:10:52 +00006686 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006687
6688 ret = xmlOutputBufferClose(buf);
6689 return(ret);
6690}
6691
Daniel Veillardf012a642001-07-23 19:10:52 +00006692
6693/**
6694 * xmlSaveFileEnc:
6695 * @filename: the filename (or URL)
6696 * @cur: the document
6697 * @encoding: the name of an encoding (or NULL)
6698 *
6699 * Dump an XML document, converting it to the given encoding
6700 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006701 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006702 */
6703int
6704xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6705 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6706}
6707
Owen Taylor3473f882001-02-23 17:55:21 +00006708/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006709 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006710 * @filename: the filename (or URL)
6711 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006712 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006713 *
6714 * Dump an XML document to a file. Will use compression if
6715 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006716 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006717 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006718 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006719 */
6720int
Daniel Veillard67fee942001-04-26 18:59:03 +00006721xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006722 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006723}
6724
Daniel Veillard67fee942001-04-26 18:59:03 +00006725/**
6726 * xmlSaveFile:
6727 * @filename: the filename (or URL)
6728 * @cur: the document
6729 *
6730 * Dump an XML document to a file. Will use compression if
6731 * compiled in and enabled. If @filename is "-" the stdout file is
6732 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006733 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006734 */
6735int
6736xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006737 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006738}
6739