blob: 50a7e1ee9d5ca3a66d4e826b246b5e5ceb8703f8 [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 Veillard36065812002-01-24 15:02:46 +00001827 if(tree->type == XML_ELEMENT_NODE) {
1828 prop = tree->properties;
1829 while (prop != NULL) {
1830 prop->doc = doc;
1831 xmlSetListDoc(prop->children, doc);
1832 prop = prop->next;
1833 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00001834 }
Owen Taylor3473f882001-02-23 17:55:21 +00001835 if (tree->children != NULL)
1836 xmlSetListDoc(tree->children, doc);
1837 tree->doc = doc;
1838 }
1839}
1840
1841/**
1842 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001843 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001844 * @doc: the document
1845 *
1846 * update all nodes in the list to point to the right document
1847 */
1848void
1849xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1850 xmlNodePtr cur;
1851
1852 if (list == NULL)
1853 return;
1854 cur = list;
1855 while (cur != NULL) {
1856 if (cur->doc != doc)
1857 xmlSetTreeDoc(cur, doc);
1858 cur = cur->next;
1859 }
1860}
1861
1862
1863/**
1864 * xmlNewChild:
1865 * @parent: the parent node
1866 * @ns: a namespace if any
1867 * @name: the name of the child
1868 * @content: the XML content of the child if any.
1869 *
1870 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001871 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001872 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1873 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1874 * references, but XML special chars need to be escaped first by using
1875 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1876 * support is not needed.
1877 *
1878 * Returns a pointer to the new node object.
1879 */
1880xmlNodePtr
1881xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1882 const xmlChar *name, const xmlChar *content) {
1883 xmlNodePtr cur, prev;
1884
1885 if (parent == NULL) {
1886#ifdef DEBUG_TREE
1887 xmlGenericError(xmlGenericErrorContext,
1888 "xmlNewChild : parent == NULL\n");
1889#endif
1890 return(NULL);
1891 }
1892
1893 if (name == NULL) {
1894#ifdef DEBUG_TREE
1895 xmlGenericError(xmlGenericErrorContext,
1896 "xmlNewChild : name == NULL\n");
1897#endif
1898 return(NULL);
1899 }
1900
1901 /*
1902 * Allocate a new node
1903 */
1904 if (ns == NULL)
1905 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1906 else
1907 cur = xmlNewDocNode(parent->doc, ns, name, content);
1908 if (cur == NULL) return(NULL);
1909
1910 /*
1911 * add the new element at the end of the children list.
1912 */
1913 cur->type = XML_ELEMENT_NODE;
1914 cur->parent = parent;
1915 cur->doc = parent->doc;
1916 if (parent->children == NULL) {
1917 parent->children = cur;
1918 parent->last = cur;
1919 } else {
1920 prev = parent->last;
1921 prev->next = cur;
1922 cur->prev = prev;
1923 parent->last = cur;
1924 }
1925
1926 return(cur);
1927}
1928
1929/**
1930 * xmlAddNextSibling:
1931 * @cur: the child node
1932 * @elem: the new node
1933 *
1934 * Add a new element @elem as the next siblings of @cur
1935 * If the new element was already inserted in a document it is
1936 * first unlinked from its existing context.
1937 * As a result of text merging @elem may be freed.
1938 *
1939 * Returns the new element or NULL in case of error.
1940 */
1941xmlNodePtr
1942xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1943 if (cur == NULL) {
1944#ifdef DEBUG_TREE
1945 xmlGenericError(xmlGenericErrorContext,
1946 "xmlAddNextSibling : cur == NULL\n");
1947#endif
1948 return(NULL);
1949 }
1950 if (elem == NULL) {
1951#ifdef DEBUG_TREE
1952 xmlGenericError(xmlGenericErrorContext,
1953 "xmlAddNextSibling : elem == NULL\n");
1954#endif
1955 return(NULL);
1956 }
1957
1958 xmlUnlinkNode(elem);
1959
1960 if (elem->type == XML_TEXT_NODE) {
1961 if (cur->type == XML_TEXT_NODE) {
1962#ifndef XML_USE_BUFFER_CONTENT
1963 xmlNodeAddContent(cur, elem->content);
1964#else
1965 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1966#endif
1967 xmlFreeNode(elem);
1968 return(cur);
1969 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001970 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1971 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001972#ifndef XML_USE_BUFFER_CONTENT
1973 xmlChar *tmp;
1974
1975 tmp = xmlStrdup(elem->content);
1976 tmp = xmlStrcat(tmp, cur->next->content);
1977 xmlNodeSetContent(cur->next, tmp);
1978 xmlFree(tmp);
1979#else
1980 xmlBufferAddHead(cur->next->content,
1981 xmlBufferContent(elem->content),
1982 xmlBufferLength(elem->content));
1983#endif
1984 xmlFreeNode(elem);
1985 return(cur->next);
1986 }
1987 }
1988
1989 if (elem->doc != cur->doc) {
1990 xmlSetTreeDoc(elem, cur->doc);
1991 }
1992 elem->parent = cur->parent;
1993 elem->prev = cur;
1994 elem->next = cur->next;
1995 cur->next = elem;
1996 if (elem->next != NULL)
1997 elem->next->prev = elem;
1998 if ((elem->parent != NULL) && (elem->parent->last == cur))
1999 elem->parent->last = elem;
2000 return(elem);
2001}
2002
2003/**
2004 * xmlAddPrevSibling:
2005 * @cur: the child node
2006 * @elem: the new node
2007 *
2008 * Add a new element @elem as the previous siblings of @cur
2009 * merging adjacent TEXT nodes (@elem may be freed)
2010 * If the new element was already inserted in a document it is
2011 * first unlinked from its existing context.
2012 *
2013 * Returns the new element or NULL in case of error.
2014 */
2015xmlNodePtr
2016xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2017 if (cur == NULL) {
2018#ifdef DEBUG_TREE
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlAddPrevSibling : cur == NULL\n");
2021#endif
2022 return(NULL);
2023 }
2024 if (elem == NULL) {
2025#ifdef DEBUG_TREE
2026 xmlGenericError(xmlGenericErrorContext,
2027 "xmlAddPrevSibling : elem == NULL\n");
2028#endif
2029 return(NULL);
2030 }
2031
2032 xmlUnlinkNode(elem);
2033
2034 if (elem->type == XML_TEXT_NODE) {
2035 if (cur->type == XML_TEXT_NODE) {
2036#ifndef XML_USE_BUFFER_CONTENT
2037 xmlChar *tmp;
2038
2039 tmp = xmlStrdup(elem->content);
2040 tmp = xmlStrcat(tmp, cur->content);
2041 xmlNodeSetContent(cur, tmp);
2042 xmlFree(tmp);
2043#else
2044 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2045 xmlBufferLength(elem->content));
2046#endif
2047 xmlFreeNode(elem);
2048 return(cur);
2049 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002050 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2051 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002052#ifndef XML_USE_BUFFER_CONTENT
2053 xmlNodeAddContent(cur->prev, elem->content);
2054#else
2055 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2056#endif
2057 xmlFreeNode(elem);
2058 return(cur->prev);
2059 }
2060 }
2061
2062 if (elem->doc != cur->doc) {
2063 xmlSetTreeDoc(elem, cur->doc);
2064 }
2065 elem->parent = cur->parent;
2066 elem->next = cur;
2067 elem->prev = cur->prev;
2068 cur->prev = elem;
2069 if (elem->prev != NULL)
2070 elem->prev->next = elem;
2071 if ((elem->parent != NULL) && (elem->parent->children == cur))
2072 elem->parent->children = elem;
2073 return(elem);
2074}
2075
2076/**
2077 * xmlAddSibling:
2078 * @cur: the child node
2079 * @elem: the new node
2080 *
2081 * Add a new element @elem to the list of siblings of @cur
2082 * merging adjacent TEXT nodes (@elem may be freed)
2083 * If the new element was already inserted in a document it is
2084 * first unlinked from its existing context.
2085 *
2086 * Returns the new element or NULL in case of error.
2087 */
2088xmlNodePtr
2089xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2090 xmlNodePtr parent;
2091
2092 if (cur == NULL) {
2093#ifdef DEBUG_TREE
2094 xmlGenericError(xmlGenericErrorContext,
2095 "xmlAddSibling : cur == NULL\n");
2096#endif
2097 return(NULL);
2098 }
2099
2100 if (elem == NULL) {
2101#ifdef DEBUG_TREE
2102 xmlGenericError(xmlGenericErrorContext,
2103 "xmlAddSibling : elem == NULL\n");
2104#endif
2105 return(NULL);
2106 }
2107
2108 /*
2109 * Constant time is we can rely on the ->parent->last to find
2110 * the last sibling.
2111 */
2112 if ((cur->parent != NULL) &&
2113 (cur->parent->children != NULL) &&
2114 (cur->parent->last != NULL) &&
2115 (cur->parent->last->next == NULL)) {
2116 cur = cur->parent->last;
2117 } else {
2118 while (cur->next != NULL) cur = cur->next;
2119 }
2120
2121 xmlUnlinkNode(elem);
2122
2123 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2124#ifndef XML_USE_BUFFER_CONTENT
2125 xmlNodeAddContent(cur, elem->content);
2126#else
2127 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2128#endif
2129 xmlFreeNode(elem);
2130 return(cur);
2131 }
2132
2133 if (elem->doc != cur->doc) {
2134 xmlSetTreeDoc(elem, cur->doc);
2135 }
2136 parent = cur->parent;
2137 elem->prev = cur;
2138 elem->next = NULL;
2139 elem->parent = parent;
2140 cur->next = elem;
2141 if (parent != NULL)
2142 parent->last = elem;
2143
2144 return(elem);
2145}
2146
2147/**
2148 * xmlAddChildList:
2149 * @parent: the parent node
2150 * @cur: the first node in the list
2151 *
2152 * Add a list of node at the end of the child list of the parent
2153 * merging adjacent TEXT nodes (@cur may be freed)
2154 *
2155 * Returns the last child or NULL in case of error.
2156 */
2157xmlNodePtr
2158xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2159 xmlNodePtr prev;
2160
2161 if (parent == NULL) {
2162#ifdef DEBUG_TREE
2163 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002164 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002165#endif
2166 return(NULL);
2167 }
2168
2169 if (cur == NULL) {
2170#ifdef DEBUG_TREE
2171 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002172 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002173#endif
2174 return(NULL);
2175 }
2176
2177 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2178 (cur->doc != parent->doc)) {
2179#ifdef DEBUG_TREE
2180 xmlGenericError(xmlGenericErrorContext,
2181 "Elements moved to a different document\n");
2182#endif
2183 }
2184
2185 /*
2186 * add the first element at the end of the children list.
2187 */
2188 if (parent->children == NULL) {
2189 parent->children = cur;
2190 } else {
2191 /*
2192 * If cur and parent->last both are TEXT nodes, then merge them.
2193 */
2194 if ((cur->type == XML_TEXT_NODE) &&
2195 (parent->last->type == XML_TEXT_NODE) &&
2196 (cur->name == parent->last->name)) {
2197#ifndef XML_USE_BUFFER_CONTENT
2198 xmlNodeAddContent(parent->last, cur->content);
2199#else
2200 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2201#endif
2202 /*
2203 * if it's the only child, nothing more to be done.
2204 */
2205 if (cur->next == NULL) {
2206 xmlFreeNode(cur);
2207 return(parent->last);
2208 }
2209 prev = cur;
2210 cur = cur->next;
2211 xmlFreeNode(prev);
2212 }
2213 prev = parent->last;
2214 prev->next = cur;
2215 cur->prev = prev;
2216 }
2217 while (cur->next != NULL) {
2218 cur->parent = parent;
2219 if (cur->doc != parent->doc) {
2220 xmlSetTreeDoc(cur, parent->doc);
2221 }
2222 cur = cur->next;
2223 }
2224 cur->parent = parent;
2225 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2226 parent->last = cur;
2227
2228 return(cur);
2229}
2230
2231/**
2232 * xmlAddChild:
2233 * @parent: the parent node
2234 * @cur: the child node
2235 *
2236 * Add a new child element, to @parent, at the end of the child list
2237 * merging adjacent TEXT nodes (in which case @cur is freed)
2238 * Returns the child or NULL in case of error.
2239 */
2240xmlNodePtr
2241xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2242 xmlNodePtr prev;
2243
2244 if (parent == NULL) {
2245#ifdef DEBUG_TREE
2246 xmlGenericError(xmlGenericErrorContext,
2247 "xmlAddChild : parent == NULL\n");
2248#endif
2249 return(NULL);
2250 }
2251
2252 if (cur == NULL) {
2253#ifdef DEBUG_TREE
2254 xmlGenericError(xmlGenericErrorContext,
2255 "xmlAddChild : child == NULL\n");
2256#endif
2257 return(NULL);
2258 }
2259
Owen Taylor3473f882001-02-23 17:55:21 +00002260 /*
2261 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002262 * cur is then freed.
2263 */
2264 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002265 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002266 (parent->content != NULL)) {
2267#ifndef XML_USE_BUFFER_CONTENT
2268 xmlNodeAddContent(parent, cur->content);
2269#else
2270 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2271#endif
2272 xmlFreeNode(cur);
2273 return(parent);
2274 }
2275 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2276 (parent->last->name == cur->name)) {
2277#ifndef XML_USE_BUFFER_CONTENT
2278 xmlNodeAddContent(parent->last, cur->content);
2279#else
2280 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2281#endif
2282 xmlFreeNode(cur);
2283 return(parent->last);
2284 }
2285 }
2286
2287 /*
2288 * add the new element at the end of the children list.
2289 */
2290 cur->parent = parent;
2291 if (cur->doc != parent->doc) {
2292 xmlSetTreeDoc(cur, parent->doc);
2293 }
2294
2295 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002296 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002297 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002298 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002299 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002300#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002301 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002302#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002303 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002304#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002305 xmlFreeNode(cur);
2306 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002307 }
2308 if (parent->children == NULL) {
2309 parent->children = cur;
2310 parent->last = cur;
2311 } else {
2312 prev = parent->last;
2313 prev->next = cur;
2314 cur->prev = prev;
2315 parent->last = cur;
2316 }
2317
2318 return(cur);
2319}
2320
2321/**
2322 * xmlGetLastChild:
2323 * @parent: the parent node
2324 *
2325 * Search the last child of a node.
2326 * Returns the last child or NULL if none.
2327 */
2328xmlNodePtr
2329xmlGetLastChild(xmlNodePtr parent) {
2330 if (parent == NULL) {
2331#ifdef DEBUG_TREE
2332 xmlGenericError(xmlGenericErrorContext,
2333 "xmlGetLastChild : parent == NULL\n");
2334#endif
2335 return(NULL);
2336 }
2337 return(parent->last);
2338}
2339
2340/**
2341 * xmlFreeNodeList:
2342 * @cur: the first node in the list
2343 *
2344 * Free a node and all its siblings, this is a recursive behaviour, all
2345 * the children are freed too.
2346 */
2347void
2348xmlFreeNodeList(xmlNodePtr cur) {
2349 xmlNodePtr next;
2350 if (cur == NULL) {
2351#ifdef DEBUG_TREE
2352 xmlGenericError(xmlGenericErrorContext,
2353 "xmlFreeNodeList : node == NULL\n");
2354#endif
2355 return;
2356 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002357 if (cur->type == XML_NAMESPACE_DECL) {
2358 xmlFreeNsList((xmlNsPtr) cur);
2359 return;
2360 }
Owen Taylor3473f882001-02-23 17:55:21 +00002361 while (cur != NULL) {
2362 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002363 /* unroll to speed up freeing the document */
2364 if (cur->type != XML_DTD_NODE) {
2365 if ((cur->children != NULL) &&
2366 (cur->type != XML_ENTITY_REF_NODE))
2367 xmlFreeNodeList(cur->children);
2368 if (cur->properties != NULL)
2369 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002370 if ((cur->type != XML_ELEMENT_NODE) &&
2371 (cur->type != XML_XINCLUDE_START) &&
2372 (cur->type != XML_XINCLUDE_END) &&
2373 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002374#ifndef XML_USE_BUFFER_CONTENT
2375 if (cur->content != NULL) xmlFree(cur->content);
2376#else
2377 if (cur->content != NULL) xmlBufferFree(cur->content);
2378#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002379 }
2380 if (((cur->type == XML_ELEMENT_NODE) ||
2381 (cur->type == XML_XINCLUDE_START) ||
2382 (cur->type == XML_XINCLUDE_END)) &&
2383 (cur->nsDef != NULL))
2384 xmlFreeNsList(cur->nsDef);
2385
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002386 /*
2387 * When a node is a text node or a comment, it uses a global static
2388 * variable for the name of the node.
2389 *
2390 * The xmlStrEqual comparisons need to be done when (happened with
2391 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002392 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002393 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002394 * the string addresses compare are not sufficient.
2395 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002396 if ((cur->name != NULL) &&
2397 (cur->name != xmlStringText) &&
2398 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002399 (cur->name != xmlStringComment)) {
2400 if (cur->type == XML_TEXT_NODE) {
2401 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2402 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2403 xmlFree((char *) cur->name);
2404 } else if (cur->type == XML_COMMENT_NODE) {
2405 if (!xmlStrEqual(cur->name, xmlStringComment))
2406 xmlFree((char *) cur->name);
2407 } else
2408 xmlFree((char *) cur->name);
2409 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002410 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002411 xmlFree(cur);
2412 }
Owen Taylor3473f882001-02-23 17:55:21 +00002413 cur = next;
2414 }
2415}
2416
2417/**
2418 * xmlFreeNode:
2419 * @cur: the node
2420 *
2421 * Free a node, this is a recursive behaviour, all the children are freed too.
2422 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2423 */
2424void
2425xmlFreeNode(xmlNodePtr cur) {
2426 if (cur == NULL) {
2427#ifdef DEBUG_TREE
2428 xmlGenericError(xmlGenericErrorContext,
2429 "xmlFreeNode : node == NULL\n");
2430#endif
2431 return;
2432 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002433 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002434 if (cur->type == XML_DTD_NODE) {
2435 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002436 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002437 }
2438 if (cur->type == XML_NAMESPACE_DECL) {
2439 xmlFreeNs((xmlNsPtr) cur);
2440 return;
2441 }
Owen Taylor3473f882001-02-23 17:55:21 +00002442 if ((cur->children != NULL) &&
2443 (cur->type != XML_ENTITY_REF_NODE))
2444 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002445 if (cur->properties != NULL)
2446 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002447 if ((cur->type != XML_ELEMENT_NODE) &&
2448 (cur->content != NULL) &&
2449 (cur->type != XML_ENTITY_REF_NODE) &&
2450 (cur->type != XML_XINCLUDE_END) &&
2451 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002452#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002453 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002454#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002455 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002456#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002457 }
2458
Daniel Veillardacd370f2001-06-09 17:17:51 +00002459 /*
2460 * When a node is a text node or a comment, it uses a global static
2461 * variable for the name of the node.
2462 *
2463 * The xmlStrEqual comparisons need to be done when (happened with
2464 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002465 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002466 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002467 * are not sufficient.
2468 */
Owen Taylor3473f882001-02-23 17:55:21 +00002469 if ((cur->name != NULL) &&
2470 (cur->name != xmlStringText) &&
2471 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002472 (cur->name != xmlStringComment)) {
2473 if (cur->type == XML_TEXT_NODE) {
2474 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2475 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2476 xmlFree((char *) cur->name);
2477 } else if (cur->type == XML_COMMENT_NODE) {
2478 if (!xmlStrEqual(cur->name, xmlStringComment))
2479 xmlFree((char *) cur->name);
2480 } else
2481 xmlFree((char *) cur->name);
2482 }
2483
Owen Taylor3473f882001-02-23 17:55:21 +00002484 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002485 xmlFree(cur);
2486}
2487
2488/**
2489 * xmlUnlinkNode:
2490 * @cur: the node
2491 *
2492 * Unlink a node from it's current context, the node is not freed
2493 */
2494void
2495xmlUnlinkNode(xmlNodePtr cur) {
2496 if (cur == NULL) {
2497#ifdef DEBUG_TREE
2498 xmlGenericError(xmlGenericErrorContext,
2499 "xmlUnlinkNode : node == NULL\n");
2500#endif
2501 return;
2502 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002503 if (cur->type == XML_DTD_NODE) {
2504 xmlDocPtr doc;
2505 doc = cur->doc;
2506 if (doc->intSubset == (xmlDtdPtr) cur)
2507 doc->intSubset = NULL;
2508 if (doc->extSubset == (xmlDtdPtr) cur)
2509 doc->extSubset = NULL;
2510 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002511 if (cur->parent != NULL) {
2512 xmlNodePtr parent;
2513 parent = cur->parent;
2514 if (cur->type == XML_ATTRIBUTE_NODE) {
2515 if (parent->properties == (xmlAttrPtr) cur)
2516 parent->properties = ((xmlAttrPtr) cur)->next;
2517 } else {
2518 if (parent->children == cur)
2519 parent->children = cur->next;
2520 if (parent->last == cur)
2521 parent->last = cur->prev;
2522 }
2523 cur->parent = NULL;
2524 }
Owen Taylor3473f882001-02-23 17:55:21 +00002525 if (cur->next != NULL)
2526 cur->next->prev = cur->prev;
2527 if (cur->prev != NULL)
2528 cur->prev->next = cur->next;
2529 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002530}
2531
2532/**
2533 * xmlReplaceNode:
2534 * @old: the old node
2535 * @cur: the node
2536 *
2537 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002538 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002539 * first unlinked from its existing context.
2540 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002541 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002542 */
2543xmlNodePtr
2544xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2545 if (old == NULL) {
2546#ifdef DEBUG_TREE
2547 xmlGenericError(xmlGenericErrorContext,
2548 "xmlReplaceNode : old == NULL\n");
2549#endif
2550 return(NULL);
2551 }
2552 if (cur == NULL) {
2553 xmlUnlinkNode(old);
2554 return(old);
2555 }
2556 if (cur == old) {
2557 return(old);
2558 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002559 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2560#ifdef DEBUG_TREE
2561 xmlGenericError(xmlGenericErrorContext,
2562 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2563#endif
2564 return(old);
2565 }
2566 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2567#ifdef DEBUG_TREE
2568 xmlGenericError(xmlGenericErrorContext,
2569 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2570#endif
2571 return(old);
2572 }
Owen Taylor3473f882001-02-23 17:55:21 +00002573 xmlUnlinkNode(cur);
2574 cur->doc = old->doc;
2575 cur->parent = old->parent;
2576 cur->next = old->next;
2577 if (cur->next != NULL)
2578 cur->next->prev = cur;
2579 cur->prev = old->prev;
2580 if (cur->prev != NULL)
2581 cur->prev->next = cur;
2582 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002583 if (cur->type == XML_ATTRIBUTE_NODE) {
2584 if (cur->parent->properties == (xmlAttrPtr)old)
2585 cur->parent->properties = ((xmlAttrPtr) cur);
2586 } else {
2587 if (cur->parent->children == old)
2588 cur->parent->children = cur;
2589 if (cur->parent->last == old)
2590 cur->parent->last = cur;
2591 }
Owen Taylor3473f882001-02-23 17:55:21 +00002592 }
2593 old->next = old->prev = NULL;
2594 old->parent = NULL;
2595 return(old);
2596}
2597
2598/************************************************************************
2599 * *
2600 * Copy operations *
2601 * *
2602 ************************************************************************/
2603
2604/**
2605 * xmlCopyNamespace:
2606 * @cur: the namespace
2607 *
2608 * Do a copy of the namespace.
2609 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002610 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002611 */
2612xmlNsPtr
2613xmlCopyNamespace(xmlNsPtr cur) {
2614 xmlNsPtr ret;
2615
2616 if (cur == NULL) return(NULL);
2617 switch (cur->type) {
2618 case XML_LOCAL_NAMESPACE:
2619 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2620 break;
2621 default:
2622#ifdef DEBUG_TREE
2623 xmlGenericError(xmlGenericErrorContext,
2624 "xmlCopyNamespace: invalid type %d\n", cur->type);
2625#endif
2626 return(NULL);
2627 }
2628 return(ret);
2629}
2630
2631/**
2632 * xmlCopyNamespaceList:
2633 * @cur: the first namespace
2634 *
2635 * Do a copy of an namespace list.
2636 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002637 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002638 */
2639xmlNsPtr
2640xmlCopyNamespaceList(xmlNsPtr cur) {
2641 xmlNsPtr ret = NULL;
2642 xmlNsPtr p = NULL,q;
2643
2644 while (cur != NULL) {
2645 q = xmlCopyNamespace(cur);
2646 if (p == NULL) {
2647 ret = p = q;
2648 } else {
2649 p->next = q;
2650 p = q;
2651 }
2652 cur = cur->next;
2653 }
2654 return(ret);
2655}
2656
2657static xmlNodePtr
2658xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2659/**
2660 * xmlCopyProp:
2661 * @target: the element where the attribute will be grafted
2662 * @cur: the attribute
2663 *
2664 * Do a copy of the attribute.
2665 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002666 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002667 */
2668xmlAttrPtr
2669xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2670 xmlAttrPtr ret;
2671
2672 if (cur == NULL) return(NULL);
2673 if (target != NULL)
2674 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2675 else if (cur->parent != NULL)
2676 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2677 else if (cur->children != NULL)
2678 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2679 else
2680 ret = xmlNewDocProp(NULL, cur->name, NULL);
2681 if (ret == NULL) return(NULL);
2682 ret->parent = target;
2683
2684 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002685 xmlNsPtr ns;
2686 if (target->doc)
Owen Taylor3473f882001-02-23 17:55:21 +00002687 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
Daniel Veillard8107a222002-01-13 14:10:10 +00002688 else if (cur->doc) /* target may not yet have a doc : KPI */
2689 ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2690 else
2691 ns = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002692 ret->ns = ns;
2693 } else
2694 ret->ns = NULL;
2695
2696 if (cur->children != NULL) {
2697 xmlNodePtr tmp;
2698
2699 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2700 ret->last = NULL;
2701 tmp = ret->children;
2702 while (tmp != NULL) {
2703 /* tmp->parent = (xmlNodePtr)ret; */
2704 if (tmp->next == NULL)
2705 ret->last = tmp;
2706 tmp = tmp->next;
2707 }
2708 }
2709 return(ret);
2710}
2711
2712/**
2713 * xmlCopyPropList:
2714 * @target: the element where the attributes will be grafted
2715 * @cur: the first attribute
2716 *
2717 * Do a copy of an attribute list.
2718 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002719 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002720 */
2721xmlAttrPtr
2722xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2723 xmlAttrPtr ret = NULL;
2724 xmlAttrPtr p = NULL,q;
2725
2726 while (cur != NULL) {
2727 q = xmlCopyProp(target, cur);
2728 if (p == NULL) {
2729 ret = p = q;
2730 } else {
2731 p->next = q;
2732 q->prev = p;
2733 p = q;
2734 }
2735 cur = cur->next;
2736 }
2737 return(ret);
2738}
2739
2740/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002741 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002742 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002743 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002744 * tricky reason: namespaces. Doing a direct copy of a node
2745 * say RPM:Copyright without changing the namespace pointer to
2746 * something else can produce stale links. One way to do it is
2747 * to keep a reference counter but this doesn't work as soon
2748 * as one move the element or the subtree out of the scope of
2749 * the existing namespace. The actual solution seems to add
2750 * a copy of the namespace at the top of the copied tree if
2751 * not available in the subtree.
2752 * Hence two functions, the public front-end call the inner ones
2753 */
2754
2755static xmlNodePtr
2756xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2757
2758static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002759xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002760 int recursive) {
2761 xmlNodePtr ret;
2762
2763 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002764 switch (node->type) {
2765 case XML_TEXT_NODE:
2766 case XML_CDATA_SECTION_NODE:
2767 case XML_ELEMENT_NODE:
2768 case XML_ENTITY_REF_NODE:
2769 case XML_ENTITY_NODE:
2770 case XML_PI_NODE:
2771 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002772 case XML_XINCLUDE_START:
2773 case XML_XINCLUDE_END:
2774 break;
2775 case XML_ATTRIBUTE_NODE:
2776 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2777 case XML_NAMESPACE_DECL:
2778 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2779
Daniel Veillard39196eb2001-06-19 18:09:42 +00002780 case XML_DOCUMENT_NODE:
2781 case XML_HTML_DOCUMENT_NODE:
2782#ifdef LIBXML_DOCB_ENABLED
2783 case XML_DOCB_DOCUMENT_NODE:
2784#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002785 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002786 case XML_DOCUMENT_TYPE_NODE:
2787 case XML_DOCUMENT_FRAG_NODE:
2788 case XML_NOTATION_NODE:
2789 case XML_DTD_NODE:
2790 case XML_ELEMENT_DECL:
2791 case XML_ATTRIBUTE_DECL:
2792 case XML_ENTITY_DECL:
2793 return(NULL);
2794 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002795
Owen Taylor3473f882001-02-23 17:55:21 +00002796 /*
2797 * Allocate a new node and fill the fields.
2798 */
2799 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2800 if (ret == NULL) {
2801 xmlGenericError(xmlGenericErrorContext,
2802 "xmlStaticCopyNode : malloc failed\n");
2803 return(NULL);
2804 }
2805 memset(ret, 0, sizeof(xmlNode));
2806 ret->type = node->type;
2807
2808 ret->doc = doc;
2809 ret->parent = parent;
2810 if (node->name == xmlStringText)
2811 ret->name = xmlStringText;
2812 else if (node->name == xmlStringTextNoenc)
2813 ret->name = xmlStringTextNoenc;
2814 else if (node->name == xmlStringComment)
2815 ret->name = xmlStringComment;
2816 else if (node->name != NULL)
2817 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002818 if ((node->type != XML_ELEMENT_NODE) &&
2819 (node->content != NULL) &&
2820 (node->type != XML_ENTITY_REF_NODE) &&
2821 (node->type != XML_XINCLUDE_END) &&
2822 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002823#ifndef XML_USE_BUFFER_CONTENT
2824 ret->content = xmlStrdup(node->content);
2825#else
2826 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2827 xmlBufferSetAllocationScheme(ret->content,
2828 xmlGetBufferAllocationScheme());
2829 xmlBufferAdd(ret->content,
2830 xmlBufferContent(node->content),
2831 xmlBufferLength(node->content));
2832#endif
Daniel Veillard8107a222002-01-13 14:10:10 +00002833 }else{
2834 if (node->type == XML_ELEMENT_NODE)
2835 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002836 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002837 if (parent != NULL) {
2838 xmlNodePtr tmp;
2839
2840 tmp = xmlAddChild(parent, ret);
2841 /* node could have coalesced */
2842 if (tmp != ret)
2843 return(tmp);
2844 }
Owen Taylor3473f882001-02-23 17:55:21 +00002845
2846 if (!recursive) return(ret);
2847 if (node->nsDef != NULL)
2848 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2849
2850 if (node->ns != NULL) {
2851 xmlNsPtr ns;
2852
2853 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2854 if (ns == NULL) {
2855 /*
2856 * Humm, we are copying an element whose namespace is defined
2857 * out of the new tree scope. Search it in the original tree
2858 * and add it at the top of the new tree
2859 */
2860 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2861 if (ns != NULL) {
2862 xmlNodePtr root = ret;
2863
2864 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002865 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002866 }
2867 } else {
2868 /*
2869 * reference the existing namespace definition in our own tree.
2870 */
2871 ret->ns = ns;
2872 }
2873 }
2874 if (node->properties != NULL)
2875 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002876 if (node->type == XML_ENTITY_REF_NODE) {
2877 if ((doc == NULL) || (node->doc != doc)) {
2878 /*
2879 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002880 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002881 * we cannot keep the reference. Try to find it in the
2882 * target document.
2883 */
2884 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2885 } else {
2886 ret->children = node->children;
2887 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002888 ret->last = ret->children;
2889 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002890 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002891 UPDATE_LAST_CHILD_AND_PARENT(ret)
2892 }
Owen Taylor3473f882001-02-23 17:55:21 +00002893 return(ret);
2894}
2895
2896static xmlNodePtr
2897xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2898 xmlNodePtr ret = NULL;
2899 xmlNodePtr p = NULL,q;
2900
2901 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002902 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002903 if (doc == NULL) {
2904 node = node->next;
2905 continue;
2906 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002907 if (doc->intSubset == NULL) {
2908 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2909 q->doc = doc;
2910 q->parent = parent;
2911 doc->intSubset = (xmlDtdPtr) q;
2912 } else {
2913 q = (xmlNodePtr) doc->intSubset;
2914 }
2915 } else
2916 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002917 if (ret == NULL) {
2918 q->prev = NULL;
2919 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002920 } else if (p != q) {
2921 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002922 p->next = q;
2923 q->prev = p;
2924 p = q;
2925 }
2926 node = node->next;
2927 }
2928 return(ret);
2929}
2930
2931/**
2932 * xmlCopyNode:
2933 * @node: the node
2934 * @recursive: if 1 do a recursive copy.
2935 *
2936 * Do a copy of the node.
2937 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002938 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002939 */
2940xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002941xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002942 xmlNodePtr ret;
2943
2944 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2945 return(ret);
2946}
2947
2948/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002949 * xmlDocCopyNode:
2950 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00002951 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00002952 * @recursive: if 1 do a recursive copy.
2953 *
2954 * Do a copy of the node to a given document.
2955 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002956 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00002957 */
2958xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002959xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002960 xmlNodePtr ret;
2961
2962 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2963 return(ret);
2964}
2965
2966/**
Owen Taylor3473f882001-02-23 17:55:21 +00002967 * xmlCopyNodeList:
2968 * @node: the first node in the list.
2969 *
2970 * Do a recursive copy of the node list.
2971 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002972 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002973 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002974xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002975 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2976 return(ret);
2977}
2978
2979/**
Owen Taylor3473f882001-02-23 17:55:21 +00002980 * xmlCopyDtd:
2981 * @dtd: the dtd
2982 *
2983 * Do a copy of the dtd.
2984 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002985 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002986 */
2987xmlDtdPtr
2988xmlCopyDtd(xmlDtdPtr dtd) {
2989 xmlDtdPtr ret;
2990
2991 if (dtd == NULL) return(NULL);
2992 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2993 if (ret == NULL) return(NULL);
2994 if (dtd->entities != NULL)
2995 ret->entities = (void *) xmlCopyEntitiesTable(
2996 (xmlEntitiesTablePtr) dtd->entities);
2997 if (dtd->notations != NULL)
2998 ret->notations = (void *) xmlCopyNotationTable(
2999 (xmlNotationTablePtr) dtd->notations);
3000 if (dtd->elements != NULL)
3001 ret->elements = (void *) xmlCopyElementTable(
3002 (xmlElementTablePtr) dtd->elements);
3003 if (dtd->attributes != NULL)
3004 ret->attributes = (void *) xmlCopyAttributeTable(
3005 (xmlAttributeTablePtr) dtd->attributes);
3006 return(ret);
3007}
3008
3009/**
3010 * xmlCopyDoc:
3011 * @doc: the document
3012 * @recursive: if 1 do a recursive copy.
3013 *
3014 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003015 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003016 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003017 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003018 */
3019xmlDocPtr
3020xmlCopyDoc(xmlDocPtr doc, int recursive) {
3021 xmlDocPtr ret;
3022
3023 if (doc == NULL) return(NULL);
3024 ret = xmlNewDoc(doc->version);
3025 if (ret == NULL) return(NULL);
3026 if (doc->name != NULL)
3027 ret->name = xmlMemStrdup(doc->name);
3028 if (doc->encoding != NULL)
3029 ret->encoding = xmlStrdup(doc->encoding);
3030 ret->charset = doc->charset;
3031 ret->compression = doc->compression;
3032 ret->standalone = doc->standalone;
3033 if (!recursive) return(ret);
3034
Daniel Veillardb33c2012001-04-25 12:59:04 +00003035 ret->last = NULL;
3036 ret->children = NULL;
3037 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003038 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003039 ret->intSubset->doc = ret;
3040 ret->intSubset->parent = ret;
3041 }
Owen Taylor3473f882001-02-23 17:55:21 +00003042 if (doc->oldNs != NULL)
3043 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3044 if (doc->children != NULL) {
3045 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003046
3047 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3048 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003049 ret->last = NULL;
3050 tmp = ret->children;
3051 while (tmp != NULL) {
3052 if (tmp->next == NULL)
3053 ret->last = tmp;
3054 tmp = tmp->next;
3055 }
3056 }
3057 return(ret);
3058}
3059
3060/************************************************************************
3061 * *
3062 * Content access functions *
3063 * *
3064 ************************************************************************/
3065
3066/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003067 * xmlGetLineNo:
3068 * @node : valid node
3069 *
3070 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003071 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003072 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003073 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003074 */
3075long
3076xmlGetLineNo(xmlNodePtr node)
3077{
3078 long result = -1;
3079
3080 if (!node)
3081 return result;
3082 if (node->type == XML_ELEMENT_NODE)
3083 result = (long) node->content;
3084 else if ((node->prev != NULL) &&
3085 ((node->prev->type == XML_ELEMENT_NODE) ||
3086 (node->prev->type == XML_TEXT_NODE)))
3087 result = xmlGetLineNo(node->prev);
3088 else if ((node->parent != NULL) &&
3089 ((node->parent->type == XML_ELEMENT_NODE) ||
3090 (node->parent->type == XML_TEXT_NODE)))
3091 result = xmlGetLineNo(node->parent);
3092
3093 return result;
3094}
3095
3096/**
3097 * xmlGetNodePath:
3098 * @node: a node
3099 *
3100 * Build a structure based Path for the given node
3101 *
3102 * Returns the new path or NULL in case of error. The caller must free
3103 * the returned string
3104 */
3105xmlChar *
3106xmlGetNodePath(xmlNodePtr node)
3107{
3108 xmlNodePtr cur, tmp, next;
3109 xmlChar *buffer = NULL, *temp;
3110 size_t buf_len;
3111 xmlChar *buf;
3112 char sep;
3113 const char *name;
3114 char nametemp[100];
3115 int occur = 0;
3116
3117 if (node == NULL)
3118 return (NULL);
3119
3120 buf_len = 500;
3121 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3122 if (buffer == NULL)
3123 return (NULL);
3124 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3125 if (buf == NULL) {
3126 xmlFree(buffer);
3127 return (NULL);
3128 }
3129
3130 buffer[0] = 0;
3131 cur = node;
3132 do {
3133 name = "";
3134 sep = '?';
3135 occur = 0;
3136 if ((cur->type == XML_DOCUMENT_NODE) ||
3137 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3138 if (buffer[0] == '/')
3139 break;
3140 sep = '/';
3141 next = NULL;
3142 } else if (cur->type == XML_ELEMENT_NODE) {
3143 sep = '/';
3144 name = (const char *) cur->name;
3145 if (cur->ns) {
3146 snprintf(nametemp, sizeof(nametemp) - 1,
3147 "%s:%s", cur->ns->prefix, cur->name);
3148 nametemp[sizeof(nametemp) - 1] = 0;
3149 name = nametemp;
3150 }
3151 next = cur->parent;
3152
3153 /*
3154 * Thumbler index computation
3155 */
3156 tmp = cur->prev;
3157 while (tmp != NULL) {
3158 if (xmlStrEqual(cur->name, tmp->name))
3159 occur++;
3160 tmp = tmp->prev;
3161 }
3162 if (occur == 0) {
3163 tmp = cur->next;
3164 while (tmp != NULL) {
3165 if (xmlStrEqual(cur->name, tmp->name))
3166 occur++;
3167 tmp = tmp->next;
3168 }
3169 if (occur != 0)
3170 occur = 1;
3171 } else
3172 occur++;
3173 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3174 sep = '@';
3175 name = (const char *) (((xmlAttrPtr) cur)->name);
3176 next = ((xmlAttrPtr) cur)->parent;
3177 } else {
3178 next = cur->parent;
3179 }
3180
3181 /*
3182 * Make sure there is enough room
3183 */
3184 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3185 buf_len =
3186 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3187 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3188 if (temp == NULL) {
3189 xmlFree(buf);
3190 xmlFree(buffer);
3191 return (NULL);
3192 }
3193 buffer = temp;
3194 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3195 if (temp == NULL) {
3196 xmlFree(buf);
3197 xmlFree(buffer);
3198 return (NULL);
3199 }
3200 buf = temp;
3201 }
3202 if (occur == 0)
3203 snprintf((char *) buf, buf_len, "%c%s%s",
3204 sep, name, (char *) buffer);
3205 else
3206 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3207 sep, name, occur, (char *) buffer);
3208 snprintf((char *) buffer, buf_len, "%s", buf);
3209 cur = next;
3210 } while (cur != NULL);
3211 xmlFree(buf);
3212 return (buffer);
3213}
3214
3215/**
Owen Taylor3473f882001-02-23 17:55:21 +00003216 * xmlDocGetRootElement:
3217 * @doc: the document
3218 *
3219 * Get the root element of the document (doc->children is a list
3220 * containing possibly comments, PIs, etc ...).
3221 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003222 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003223 */
3224xmlNodePtr
3225xmlDocGetRootElement(xmlDocPtr doc) {
3226 xmlNodePtr ret;
3227
3228 if (doc == NULL) return(NULL);
3229 ret = doc->children;
3230 while (ret != NULL) {
3231 if (ret->type == XML_ELEMENT_NODE)
3232 return(ret);
3233 ret = ret->next;
3234 }
3235 return(ret);
3236}
3237
3238/**
3239 * xmlDocSetRootElement:
3240 * @doc: the document
3241 * @root: the new document root element
3242 *
3243 * Set the root element of the document (doc->children is a list
3244 * containing possibly comments, PIs, etc ...).
3245 *
3246 * Returns the old root element if any was found
3247 */
3248xmlNodePtr
3249xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3250 xmlNodePtr old = NULL;
3251
3252 if (doc == NULL) return(NULL);
3253 old = doc->children;
3254 while (old != NULL) {
3255 if (old->type == XML_ELEMENT_NODE)
3256 break;
3257 old = old->next;
3258 }
3259 if (old == NULL) {
3260 if (doc->children == NULL) {
3261 doc->children = root;
3262 doc->last = root;
3263 } else {
3264 xmlAddSibling(doc->children, root);
3265 }
3266 } else {
3267 xmlReplaceNode(old, root);
3268 }
3269 return(old);
3270}
3271
3272/**
3273 * xmlNodeSetLang:
3274 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003275 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003276 *
3277 * Set the language of a node, i.e. the values of the xml:lang
3278 * attribute.
3279 */
3280void
3281xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003282 xmlNsPtr ns;
3283
Owen Taylor3473f882001-02-23 17:55:21 +00003284 if (cur == NULL) return;
3285 switch(cur->type) {
3286 case XML_TEXT_NODE:
3287 case XML_CDATA_SECTION_NODE:
3288 case XML_COMMENT_NODE:
3289 case XML_DOCUMENT_NODE:
3290 case XML_DOCUMENT_TYPE_NODE:
3291 case XML_DOCUMENT_FRAG_NODE:
3292 case XML_NOTATION_NODE:
3293 case XML_HTML_DOCUMENT_NODE:
3294 case XML_DTD_NODE:
3295 case XML_ELEMENT_DECL:
3296 case XML_ATTRIBUTE_DECL:
3297 case XML_ENTITY_DECL:
3298 case XML_PI_NODE:
3299 case XML_ENTITY_REF_NODE:
3300 case XML_ENTITY_NODE:
3301 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003302#ifdef LIBXML_DOCB_ENABLED
3303 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003304#endif
3305 case XML_XINCLUDE_START:
3306 case XML_XINCLUDE_END:
3307 return;
3308 case XML_ELEMENT_NODE:
3309 case XML_ATTRIBUTE_NODE:
3310 break;
3311 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003312 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3313 if (ns == NULL)
3314 return;
3315 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003316}
3317
3318/**
3319 * xmlNodeGetLang:
3320 * @cur: the node being checked
3321 *
3322 * Searches the language of a node, i.e. the values of the xml:lang
3323 * attribute or the one carried by the nearest ancestor.
3324 *
3325 * Returns a pointer to the lang value, or NULL if not found
3326 * It's up to the caller to free the memory.
3327 */
3328xmlChar *
3329xmlNodeGetLang(xmlNodePtr cur) {
3330 xmlChar *lang;
3331
3332 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003333 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003334 if (lang != NULL)
3335 return(lang);
3336 cur = cur->parent;
3337 }
3338 return(NULL);
3339}
3340
3341
3342/**
3343 * xmlNodeSetSpacePreserve:
3344 * @cur: the node being changed
3345 * @val: the xml:space value ("0": default, 1: "preserve")
3346 *
3347 * Set (or reset) the space preserving behaviour of a node, i.e. the
3348 * value of the xml:space attribute.
3349 */
3350void
3351xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003352 xmlNsPtr ns;
3353
Owen Taylor3473f882001-02-23 17:55:21 +00003354 if (cur == NULL) return;
3355 switch(cur->type) {
3356 case XML_TEXT_NODE:
3357 case XML_CDATA_SECTION_NODE:
3358 case XML_COMMENT_NODE:
3359 case XML_DOCUMENT_NODE:
3360 case XML_DOCUMENT_TYPE_NODE:
3361 case XML_DOCUMENT_FRAG_NODE:
3362 case XML_NOTATION_NODE:
3363 case XML_HTML_DOCUMENT_NODE:
3364 case XML_DTD_NODE:
3365 case XML_ELEMENT_DECL:
3366 case XML_ATTRIBUTE_DECL:
3367 case XML_ENTITY_DECL:
3368 case XML_PI_NODE:
3369 case XML_ENTITY_REF_NODE:
3370 case XML_ENTITY_NODE:
3371 case XML_NAMESPACE_DECL:
3372 case XML_XINCLUDE_START:
3373 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003374#ifdef LIBXML_DOCB_ENABLED
3375 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003376#endif
3377 return;
3378 case XML_ELEMENT_NODE:
3379 case XML_ATTRIBUTE_NODE:
3380 break;
3381 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003382 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3383 if (ns == NULL)
3384 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003385 switch (val) {
3386 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003387 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003388 break;
3389 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003390 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003391 break;
3392 }
3393}
3394
3395/**
3396 * xmlNodeGetSpacePreserve:
3397 * @cur: the node being checked
3398 *
3399 * Searches the space preserving behaviour of a node, i.e. the values
3400 * of the xml:space attribute or the one carried by the nearest
3401 * ancestor.
3402 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003403 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003404 */
3405int
3406xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3407 xmlChar *space;
3408
3409 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003410 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003411 if (space != NULL) {
3412 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3413 xmlFree(space);
3414 return(1);
3415 }
3416 if (xmlStrEqual(space, BAD_CAST "default")) {
3417 xmlFree(space);
3418 return(0);
3419 }
3420 xmlFree(space);
3421 }
3422 cur = cur->parent;
3423 }
3424 return(-1);
3425}
3426
3427/**
3428 * xmlNodeSetName:
3429 * @cur: the node being changed
3430 * @name: the new tag name
3431 *
3432 * Set (or reset) the name of a node.
3433 */
3434void
3435xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3436 if (cur == NULL) return;
3437 if (name == NULL) return;
3438 switch(cur->type) {
3439 case XML_TEXT_NODE:
3440 case XML_CDATA_SECTION_NODE:
3441 case XML_COMMENT_NODE:
3442 case XML_DOCUMENT_TYPE_NODE:
3443 case XML_DOCUMENT_FRAG_NODE:
3444 case XML_NOTATION_NODE:
3445 case XML_HTML_DOCUMENT_NODE:
3446 case XML_NAMESPACE_DECL:
3447 case XML_XINCLUDE_START:
3448 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003449#ifdef LIBXML_DOCB_ENABLED
3450 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003451#endif
3452 return;
3453 case XML_ELEMENT_NODE:
3454 case XML_ATTRIBUTE_NODE:
3455 case XML_PI_NODE:
3456 case XML_ENTITY_REF_NODE:
3457 case XML_ENTITY_NODE:
3458 case XML_DTD_NODE:
3459 case XML_DOCUMENT_NODE:
3460 case XML_ELEMENT_DECL:
3461 case XML_ATTRIBUTE_DECL:
3462 case XML_ENTITY_DECL:
3463 break;
3464 }
3465 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3466 cur->name = xmlStrdup(name);
3467}
3468
3469/**
3470 * xmlNodeSetBase:
3471 * @cur: the node being changed
3472 * @uri: the new base URI
3473 *
3474 * Set (or reset) the base URI of a node, i.e. the value of the
3475 * xml:base attribute.
3476 */
3477void
3478xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003479 xmlNsPtr ns;
3480
Owen Taylor3473f882001-02-23 17:55:21 +00003481 if (cur == NULL) return;
3482 switch(cur->type) {
3483 case XML_TEXT_NODE:
3484 case XML_CDATA_SECTION_NODE:
3485 case XML_COMMENT_NODE:
3486 case XML_DOCUMENT_NODE:
3487 case XML_DOCUMENT_TYPE_NODE:
3488 case XML_DOCUMENT_FRAG_NODE:
3489 case XML_NOTATION_NODE:
3490 case XML_HTML_DOCUMENT_NODE:
3491 case XML_DTD_NODE:
3492 case XML_ELEMENT_DECL:
3493 case XML_ATTRIBUTE_DECL:
3494 case XML_ENTITY_DECL:
3495 case XML_PI_NODE:
3496 case XML_ENTITY_REF_NODE:
3497 case XML_ENTITY_NODE:
3498 case XML_NAMESPACE_DECL:
3499 case XML_XINCLUDE_START:
3500 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003501#ifdef LIBXML_DOCB_ENABLED
3502 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003503#endif
3504 return;
3505 case XML_ELEMENT_NODE:
3506 case XML_ATTRIBUTE_NODE:
3507 break;
3508 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003509
3510 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3511 if (ns == NULL)
3512 return;
3513 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003514}
3515
3516/**
Owen Taylor3473f882001-02-23 17:55:21 +00003517 * xmlNodeGetBase:
3518 * @doc: the document the node pertains to
3519 * @cur: the node being checked
3520 *
3521 * Searches for the BASE URL. The code should work on both XML
3522 * and HTML document even if base mechanisms are completely different.
3523 * It returns the base as defined in RFC 2396 sections
3524 * 5.1.1. Base URI within Document Content
3525 * and
3526 * 5.1.2. Base URI from the Encapsulating Entity
3527 * However it does not return the document base (5.1.3), use
3528 * xmlDocumentGetBase() for this
3529 *
3530 * Returns a pointer to the base URL, or NULL if not found
3531 * It's up to the caller to free the memory.
3532 */
3533xmlChar *
3534xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003535 xmlChar *oldbase = NULL;
3536 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003537
3538 if ((cur == NULL) && (doc == NULL))
3539 return(NULL);
3540 if (doc == NULL) doc = cur->doc;
3541 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3542 cur = doc->children;
3543 while ((cur != NULL) && (cur->name != NULL)) {
3544 if (cur->type != XML_ELEMENT_NODE) {
3545 cur = cur->next;
3546 continue;
3547 }
3548 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3549 cur = cur->children;
3550 continue;
3551 }
3552 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3553 cur = cur->children;
3554 continue;
3555 }
3556 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3557 return(xmlGetProp(cur, BAD_CAST "href"));
3558 }
3559 cur = cur->next;
3560 }
3561 return(NULL);
3562 }
3563 while (cur != NULL) {
3564 if (cur->type == XML_ENTITY_DECL) {
3565 xmlEntityPtr ent = (xmlEntityPtr) cur;
3566 return(xmlStrdup(ent->URI));
3567 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003568 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003569 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003570 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003571 if (oldbase != NULL) {
3572 newbase = xmlBuildURI(oldbase, base);
3573 if (newbase != NULL) {
3574 xmlFree(oldbase);
3575 xmlFree(base);
3576 oldbase = newbase;
3577 } else {
3578 xmlFree(oldbase);
3579 xmlFree(base);
3580 return(NULL);
3581 }
3582 } else {
3583 oldbase = base;
3584 }
3585 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3586 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3587 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3588 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003589 }
3590 }
Owen Taylor3473f882001-02-23 17:55:21 +00003591 cur = cur->parent;
3592 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003593 if ((doc != NULL) && (doc->URL != NULL)) {
3594 if (oldbase == NULL)
3595 return(xmlStrdup(doc->URL));
3596 newbase = xmlBuildURI(oldbase, doc->URL);
3597 xmlFree(oldbase);
3598 return(newbase);
3599 }
3600 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003601}
3602
3603/**
3604 * xmlNodeGetContent:
3605 * @cur: the node being read
3606 *
3607 * Read the value of a node, this can be either the text carried
3608 * directly by this node if it's a TEXT node or the aggregate string
3609 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003610 * Entity references are substituted.
3611 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003612 * It's up to the caller to free the memory.
3613 */
3614xmlChar *
3615xmlNodeGetContent(xmlNodePtr cur) {
3616 if (cur == NULL) return(NULL);
3617 switch (cur->type) {
3618 case XML_DOCUMENT_FRAG_NODE:
3619 case XML_ELEMENT_NODE: {
3620 xmlNodePtr tmp = cur;
3621 xmlBufferPtr buffer;
3622 xmlChar *ret;
3623
3624 buffer = xmlBufferCreate();
3625 if (buffer == NULL)
3626 return(NULL);
3627 while (tmp != NULL) {
3628 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003629 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003630 case XML_TEXT_NODE:
3631 if (tmp->content != NULL)
3632#ifndef XML_USE_BUFFER_CONTENT
3633 xmlBufferCat(buffer, tmp->content);
3634#else
3635 xmlBufferCat(buffer,
3636 xmlBufferContent(tmp->content));
3637#endif
3638 break;
3639 case XML_ENTITY_REF_NODE: {
3640 xmlEntityPtr ent;
3641
3642 ent = xmlGetDocEntity(cur->doc, tmp->name);
3643 if (ent != NULL)
3644 xmlBufferCat(buffer, ent->content);
3645 }
3646 default:
3647 break;
3648 }
3649 /*
3650 * Skip to next node
3651 */
3652 if (tmp->children != NULL) {
3653 if (tmp->children->type != XML_ENTITY_DECL) {
3654 tmp = tmp->children;
3655 continue;
3656 }
3657 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003658 if (tmp == cur)
3659 break;
3660
Owen Taylor3473f882001-02-23 17:55:21 +00003661 if (tmp->next != NULL) {
3662 tmp = tmp->next;
3663 continue;
3664 }
3665
3666 do {
3667 tmp = tmp->parent;
3668 if (tmp == NULL)
3669 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003670 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003671 tmp = NULL;
3672 break;
3673 }
3674 if (tmp->next != NULL) {
3675 tmp = tmp->next;
3676 break;
3677 }
3678 } while (tmp != NULL);
3679 }
3680 ret = buffer->content;
3681 buffer->content = NULL;
3682 xmlBufferFree(buffer);
3683 return(ret);
3684 }
3685 case XML_ATTRIBUTE_NODE: {
3686 xmlAttrPtr attr = (xmlAttrPtr) cur;
3687 if (attr->parent != NULL)
3688 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3689 else
3690 return(xmlNodeListGetString(NULL, attr->children, 1));
3691 break;
3692 }
3693 case XML_COMMENT_NODE:
3694 case XML_PI_NODE:
3695 if (cur->content != NULL)
3696#ifndef XML_USE_BUFFER_CONTENT
3697 return(xmlStrdup(cur->content));
3698#else
3699 return(xmlStrdup(xmlBufferContent(cur->content)));
3700#endif
3701 return(NULL);
3702 case XML_ENTITY_REF_NODE:
3703 /*
3704 * Locate the entity, and get it's content
3705 * @@@
3706 */
3707 return(NULL);
3708 case XML_ENTITY_NODE:
3709 case XML_DOCUMENT_NODE:
3710 case XML_HTML_DOCUMENT_NODE:
3711 case XML_DOCUMENT_TYPE_NODE:
3712 case XML_NOTATION_NODE:
3713 case XML_DTD_NODE:
3714 case XML_XINCLUDE_START:
3715 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003716#ifdef LIBXML_DOCB_ENABLED
3717 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003718#endif
3719 return(NULL);
3720 case XML_NAMESPACE_DECL:
3721 return(xmlStrdup(((xmlNsPtr)cur)->href));
3722 case XML_ELEMENT_DECL:
3723 /* TODO !!! */
3724 return(NULL);
3725 case XML_ATTRIBUTE_DECL:
3726 /* TODO !!! */
3727 return(NULL);
3728 case XML_ENTITY_DECL:
3729 /* TODO !!! */
3730 return(NULL);
3731 case XML_CDATA_SECTION_NODE:
3732 case XML_TEXT_NODE:
3733 if (cur->content != NULL)
3734#ifndef XML_USE_BUFFER_CONTENT
3735 return(xmlStrdup(cur->content));
3736#else
3737 return(xmlStrdup(xmlBufferContent(cur->content)));
3738#endif
3739 return(NULL);
3740 }
3741 return(NULL);
3742}
3743
3744/**
3745 * xmlNodeSetContent:
3746 * @cur: the node being modified
3747 * @content: the new value of the content
3748 *
3749 * Replace the content of a node.
3750 */
3751void
3752xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3753 if (cur == NULL) {
3754#ifdef DEBUG_TREE
3755 xmlGenericError(xmlGenericErrorContext,
3756 "xmlNodeSetContent : node == NULL\n");
3757#endif
3758 return;
3759 }
3760 switch (cur->type) {
3761 case XML_DOCUMENT_FRAG_NODE:
3762 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003763 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003764 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3765 cur->children = xmlStringGetNodeList(cur->doc, content);
3766 UPDATE_LAST_CHILD_AND_PARENT(cur)
3767 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003768 case XML_TEXT_NODE:
3769 case XML_CDATA_SECTION_NODE:
3770 case XML_ENTITY_REF_NODE:
3771 case XML_ENTITY_NODE:
3772 case XML_PI_NODE:
3773 case XML_COMMENT_NODE:
3774 if (cur->content != NULL) {
3775#ifndef XML_USE_BUFFER_CONTENT
3776 xmlFree(cur->content);
3777#else
3778 xmlBufferFree(cur->content);
3779#endif
3780 }
3781 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3782 cur->last = cur->children = NULL;
3783 if (content != NULL) {
3784#ifndef XML_USE_BUFFER_CONTENT
3785 cur->content = xmlStrdup(content);
3786#else
3787 cur->content = xmlBufferCreateSize(0);
3788 xmlBufferSetAllocationScheme(cur->content,
3789 xmlGetBufferAllocationScheme());
3790 xmlBufferAdd(cur->content, content, -1);
3791#endif
3792 } else
3793 cur->content = NULL;
3794 break;
3795 case XML_DOCUMENT_NODE:
3796 case XML_HTML_DOCUMENT_NODE:
3797 case XML_DOCUMENT_TYPE_NODE:
3798 case XML_XINCLUDE_START:
3799 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003800#ifdef LIBXML_DOCB_ENABLED
3801 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003802#endif
3803 break;
3804 case XML_NOTATION_NODE:
3805 break;
3806 case XML_DTD_NODE:
3807 break;
3808 case XML_NAMESPACE_DECL:
3809 break;
3810 case XML_ELEMENT_DECL:
3811 /* TODO !!! */
3812 break;
3813 case XML_ATTRIBUTE_DECL:
3814 /* TODO !!! */
3815 break;
3816 case XML_ENTITY_DECL:
3817 /* TODO !!! */
3818 break;
3819 }
3820}
3821
3822/**
3823 * xmlNodeSetContentLen:
3824 * @cur: the node being modified
3825 * @content: the new value of the content
3826 * @len: the size of @content
3827 *
3828 * Replace the content of a node.
3829 */
3830void
3831xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3832 if (cur == NULL) {
3833#ifdef DEBUG_TREE
3834 xmlGenericError(xmlGenericErrorContext,
3835 "xmlNodeSetContentLen : node == NULL\n");
3836#endif
3837 return;
3838 }
3839 switch (cur->type) {
3840 case XML_DOCUMENT_FRAG_NODE:
3841 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003842 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003843 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3844 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3845 UPDATE_LAST_CHILD_AND_PARENT(cur)
3846 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003847 case XML_TEXT_NODE:
3848 case XML_CDATA_SECTION_NODE:
3849 case XML_ENTITY_REF_NODE:
3850 case XML_ENTITY_NODE:
3851 case XML_PI_NODE:
3852 case XML_COMMENT_NODE:
3853 case XML_NOTATION_NODE:
3854 if (cur->content != NULL) {
3855#ifndef XML_USE_BUFFER_CONTENT
3856 xmlFree(cur->content);
3857#else
3858 xmlBufferFree(cur->content);
3859#endif
3860 }
3861 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3862 cur->children = cur->last = NULL;
3863 if (content != NULL) {
3864#ifndef XML_USE_BUFFER_CONTENT
3865 cur->content = xmlStrndup(content, len);
3866#else
3867 cur->content = xmlBufferCreateSize(len);
3868 xmlBufferSetAllocationScheme(cur->content,
3869 xmlGetBufferAllocationScheme());
3870 xmlBufferAdd(cur->content, content, len);
3871#endif
3872 } else
3873 cur->content = NULL;
3874 break;
3875 case XML_DOCUMENT_NODE:
3876 case XML_DTD_NODE:
3877 case XML_HTML_DOCUMENT_NODE:
3878 case XML_DOCUMENT_TYPE_NODE:
3879 case XML_NAMESPACE_DECL:
3880 case XML_XINCLUDE_START:
3881 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003882#ifdef LIBXML_DOCB_ENABLED
3883 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003884#endif
3885 break;
3886 case XML_ELEMENT_DECL:
3887 /* TODO !!! */
3888 break;
3889 case XML_ATTRIBUTE_DECL:
3890 /* TODO !!! */
3891 break;
3892 case XML_ENTITY_DECL:
3893 /* TODO !!! */
3894 break;
3895 }
3896}
3897
3898/**
3899 * xmlNodeAddContentLen:
3900 * @cur: the node being modified
3901 * @content: extra content
3902 * @len: the size of @content
3903 *
3904 * Append the extra substring to the node content.
3905 */
3906void
3907xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3908 if (cur == NULL) {
3909#ifdef DEBUG_TREE
3910 xmlGenericError(xmlGenericErrorContext,
3911 "xmlNodeAddContentLen : node == NULL\n");
3912#endif
3913 return;
3914 }
3915 if (len <= 0) return;
3916 switch (cur->type) {
3917 case XML_DOCUMENT_FRAG_NODE:
3918 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003919 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00003920
Daniel Veillard7db37732001-07-12 01:20:08 +00003921 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003922 newNode = xmlNewTextLen(content, len);
3923 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003924 tmp = xmlAddChild(cur, newNode);
3925 if (tmp != newNode)
3926 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003927 if ((last != NULL) && (last->next == newNode)) {
3928 xmlTextMerge(last, newNode);
3929 }
3930 }
3931 break;
3932 }
3933 case XML_ATTRIBUTE_NODE:
3934 break;
3935 case XML_TEXT_NODE:
3936 case XML_CDATA_SECTION_NODE:
3937 case XML_ENTITY_REF_NODE:
3938 case XML_ENTITY_NODE:
3939 case XML_PI_NODE:
3940 case XML_COMMENT_NODE:
3941 case XML_NOTATION_NODE:
3942 if (content != NULL) {
3943#ifndef XML_USE_BUFFER_CONTENT
3944 cur->content = xmlStrncat(cur->content, content, len);
3945#else
3946 xmlBufferAdd(cur->content, content, len);
3947#endif
3948 }
3949 case XML_DOCUMENT_NODE:
3950 case XML_DTD_NODE:
3951 case XML_HTML_DOCUMENT_NODE:
3952 case XML_DOCUMENT_TYPE_NODE:
3953 case XML_NAMESPACE_DECL:
3954 case XML_XINCLUDE_START:
3955 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003956#ifdef LIBXML_DOCB_ENABLED
3957 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003958#endif
3959 break;
3960 case XML_ELEMENT_DECL:
3961 case XML_ATTRIBUTE_DECL:
3962 case XML_ENTITY_DECL:
3963 break;
3964 }
3965}
3966
3967/**
3968 * xmlNodeAddContent:
3969 * @cur: the node being modified
3970 * @content: extra content
3971 *
3972 * Append the extra substring to the node content.
3973 */
3974void
3975xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3976 int len;
3977
3978 if (cur == NULL) {
3979#ifdef DEBUG_TREE
3980 xmlGenericError(xmlGenericErrorContext,
3981 "xmlNodeAddContent : node == NULL\n");
3982#endif
3983 return;
3984 }
3985 if (content == NULL) return;
3986 len = xmlStrlen(content);
3987 xmlNodeAddContentLen(cur, content, len);
3988}
3989
3990/**
3991 * xmlTextMerge:
3992 * @first: the first text node
3993 * @second: the second text node being merged
3994 *
3995 * Merge two text nodes into one
3996 * Returns the first text node augmented
3997 */
3998xmlNodePtr
3999xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4000 if (first == NULL) return(second);
4001 if (second == NULL) return(first);
4002 if (first->type != XML_TEXT_NODE) return(first);
4003 if (second->type != XML_TEXT_NODE) return(first);
4004 if (second->name != first->name)
4005 return(first);
4006#ifndef XML_USE_BUFFER_CONTENT
4007 xmlNodeAddContent(first, second->content);
4008#else
4009 xmlNodeAddContent(first, xmlBufferContent(second->content));
4010#endif
4011 xmlUnlinkNode(second);
4012 xmlFreeNode(second);
4013 return(first);
4014}
4015
4016/**
4017 * xmlGetNsList:
4018 * @doc: the document
4019 * @node: the current node
4020 *
4021 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004022 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004023 * that need to be freed by the caller or NULL if no
4024 * namespace if defined
4025 */
4026xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004027xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4028{
Owen Taylor3473f882001-02-23 17:55:21 +00004029 xmlNsPtr cur;
4030 xmlNsPtr *ret = NULL;
4031 int nbns = 0;
4032 int maxns = 10;
4033 int i;
4034
4035 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004036 if (node->type == XML_ELEMENT_NODE) {
4037 cur = node->nsDef;
4038 while (cur != NULL) {
4039 if (ret == NULL) {
4040 ret =
4041 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4042 sizeof(xmlNsPtr));
4043 if (ret == NULL) {
4044 xmlGenericError(xmlGenericErrorContext,
4045 "xmlGetNsList : out of memory!\n");
4046 return (NULL);
4047 }
4048 ret[nbns] = NULL;
4049 }
4050 for (i = 0; i < nbns; i++) {
4051 if ((cur->prefix == ret[i]->prefix) ||
4052 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4053 break;
4054 }
4055 if (i >= nbns) {
4056 if (nbns >= maxns) {
4057 maxns *= 2;
4058 ret = (xmlNsPtr *) xmlRealloc(ret,
4059 (maxns +
4060 1) *
4061 sizeof(xmlNsPtr));
4062 if (ret == NULL) {
4063 xmlGenericError(xmlGenericErrorContext,
4064 "xmlGetNsList : realloc failed!\n");
4065 return (NULL);
4066 }
4067 }
4068 ret[nbns++] = cur;
4069 ret[nbns] = NULL;
4070 }
Owen Taylor3473f882001-02-23 17:55:21 +00004071
Daniel Veillard77044732001-06-29 21:31:07 +00004072 cur = cur->next;
4073 }
4074 }
4075 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004076 }
Daniel Veillard77044732001-06-29 21:31:07 +00004077 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004078}
4079
4080/**
4081 * xmlSearchNs:
4082 * @doc: the document
4083 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004084 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004085 *
4086 * Search a Ns registered under a given name space for a document.
4087 * recurse on the parents until it finds the defined namespace
4088 * or return NULL otherwise.
4089 * @nameSpace can be NULL, this is a search for the default namespace.
4090 * We don't allow to cross entities boundaries. If you don't declare
4091 * the namespace within those you will be in troubles !!! A warning
4092 * is generated to cover this case.
4093 *
4094 * Returns the namespace pointer or NULL.
4095 */
4096xmlNsPtr
4097xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4098 xmlNsPtr cur;
4099
4100 if (node == NULL) return(NULL);
4101 if ((nameSpace != NULL) &&
4102 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004103 if (doc == NULL)
4104 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004105 if (doc->oldNs == NULL) {
4106 /*
4107 * Allocate a new Namespace and fill the fields.
4108 */
4109 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4110 if (doc->oldNs == NULL) {
4111 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004112 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004113 return(NULL);
4114 }
4115 memset(doc->oldNs, 0, sizeof(xmlNs));
4116 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4117
4118 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4119 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4120 }
4121 return(doc->oldNs);
4122 }
4123 while (node != NULL) {
4124 if ((node->type == XML_ENTITY_REF_NODE) ||
4125 (node->type == XML_ENTITY_NODE) ||
4126 (node->type == XML_ENTITY_DECL))
4127 return(NULL);
4128 if (node->type == XML_ELEMENT_NODE) {
4129 cur = node->nsDef;
4130 while (cur != NULL) {
4131 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4132 (cur->href != NULL))
4133 return(cur);
4134 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4135 (cur->href != NULL) &&
4136 (xmlStrEqual(cur->prefix, nameSpace)))
4137 return(cur);
4138 cur = cur->next;
4139 }
4140 }
4141 node = node->parent;
4142 }
4143 return(NULL);
4144}
4145
4146/**
4147 * xmlSearchNsByHref:
4148 * @doc: the document
4149 * @node: the current node
4150 * @href: the namespace value
4151 *
4152 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4153 * the defined namespace or return NULL otherwise.
4154 * Returns the namespace pointer or NULL.
4155 */
4156xmlNsPtr
4157xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4158 xmlNsPtr cur;
4159 xmlNodePtr orig = node;
4160
4161 if ((node == NULL) || (href == NULL)) return(NULL);
4162 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004163 /*
4164 * Only the document can hold the XML spec namespace.
4165 */
4166 if (doc == NULL)
4167 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004168 if (doc->oldNs == NULL) {
4169 /*
4170 * Allocate a new Namespace and fill the fields.
4171 */
4172 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4173 if (doc->oldNs == NULL) {
4174 xmlGenericError(xmlGenericErrorContext,
4175 "xmlSearchNsByHref : malloc failed\n");
4176 return(NULL);
4177 }
4178 memset(doc->oldNs, 0, sizeof(xmlNs));
4179 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4180
4181 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4182 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4183 }
4184 return(doc->oldNs);
4185 }
4186 while (node != NULL) {
4187 cur = node->nsDef;
4188 while (cur != NULL) {
4189 if ((cur->href != NULL) && (href != NULL) &&
4190 (xmlStrEqual(cur->href, href))) {
4191 /*
4192 * Check that the prefix is not shadowed between orig and node
4193 */
4194 xmlNodePtr check = orig;
4195 xmlNsPtr tst;
4196
4197 while (check != node) {
4198 tst = check->nsDef;
4199 while (tst != NULL) {
4200 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4201 goto shadowed;
4202 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4203 (xmlStrEqual(tst->prefix, cur->prefix)))
4204 goto shadowed;
4205 tst = tst->next;
4206 }
4207 check = check->parent;
4208 }
4209 return(cur);
4210 }
4211shadowed:
4212 cur = cur->next;
4213 }
4214 node = node->parent;
4215 }
4216 return(NULL);
4217}
4218
4219/**
4220 * xmlNewReconciliedNs
4221 * @doc: the document
4222 * @tree: a node expected to hold the new namespace
4223 * @ns: the original namespace
4224 *
4225 * This function tries to locate a namespace definition in a tree
4226 * ancestors, or create a new namespace definition node similar to
4227 * @ns trying to reuse the same prefix. However if the given prefix is
4228 * null (default namespace) or reused within the subtree defined by
4229 * @tree or on one of its ancestors then a new prefix is generated.
4230 * Returns the (new) namespace definition or NULL in case of error
4231 */
4232xmlNsPtr
4233xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4234 xmlNsPtr def;
4235 xmlChar prefix[50];
4236 int counter = 1;
4237
4238 if (tree == NULL) {
4239#ifdef DEBUG_TREE
4240 xmlGenericError(xmlGenericErrorContext,
4241 "xmlNewReconciliedNs : tree == NULL\n");
4242#endif
4243 return(NULL);
4244 }
4245 if (ns == NULL) {
4246#ifdef DEBUG_TREE
4247 xmlGenericError(xmlGenericErrorContext,
4248 "xmlNewReconciliedNs : ns == NULL\n");
4249#endif
4250 return(NULL);
4251 }
4252 /*
4253 * Search an existing namespace definition inherited.
4254 */
4255 def = xmlSearchNsByHref(doc, tree, ns->href);
4256 if (def != NULL)
4257 return(def);
4258
4259 /*
4260 * Find a close prefix which is not already in use.
4261 * Let's strip namespace prefixes longer than 20 chars !
4262 */
4263 sprintf((char *) prefix, "%.20s", ns->prefix);
4264 def = xmlSearchNs(doc, tree, prefix);
4265 while (def != NULL) {
4266 if (counter > 1000) return(NULL);
4267 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4268 def = xmlSearchNs(doc, tree, prefix);
4269 }
4270
4271 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004272 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004273 */
4274 def = xmlNewNs(tree, ns->href, prefix);
4275 return(def);
4276}
4277
4278/**
4279 * xmlReconciliateNs
4280 * @doc: the document
4281 * @tree: a node defining the subtree to reconciliate
4282 *
4283 * This function checks that all the namespaces declared within the given
4284 * tree are properly declared. This is needed for example after Copy or Cut
4285 * and then paste operations. The subtree may still hold pointers to
4286 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004287 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004288 * the new environment. If not possible the new namespaces are redeclared
4289 * on @tree at the top of the given subtree.
4290 * Returns the number of namespace declarations created or -1 in case of error.
4291 */
4292int
4293xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4294 xmlNsPtr *oldNs = NULL;
4295 xmlNsPtr *newNs = NULL;
4296 int sizeCache = 0;
4297 int nbCache = 0;
4298
4299 xmlNsPtr n;
4300 xmlNodePtr node = tree;
4301 xmlAttrPtr attr;
4302 int ret = 0, i;
4303
4304 while (node != NULL) {
4305 /*
4306 * Reconciliate the node namespace
4307 */
4308 if (node->ns != NULL) {
4309 /*
4310 * initialize the cache if needed
4311 */
4312 if (sizeCache == 0) {
4313 sizeCache = 10;
4314 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4315 sizeof(xmlNsPtr));
4316 if (oldNs == NULL) {
4317 xmlGenericError(xmlGenericErrorContext,
4318 "xmlReconciliateNs : memory pbm\n");
4319 return(-1);
4320 }
4321 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4322 sizeof(xmlNsPtr));
4323 if (newNs == NULL) {
4324 xmlGenericError(xmlGenericErrorContext,
4325 "xmlReconciliateNs : memory pbm\n");
4326 xmlFree(oldNs);
4327 return(-1);
4328 }
4329 }
4330 for (i = 0;i < nbCache;i++) {
4331 if (oldNs[i] == node->ns) {
4332 node->ns = newNs[i];
4333 break;
4334 }
4335 }
4336 if (i == nbCache) {
4337 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004338 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004339 */
4340 n = xmlNewReconciliedNs(doc, tree, node->ns);
4341 if (n != NULL) { /* :-( what if else ??? */
4342 /*
4343 * check if we need to grow the cache buffers.
4344 */
4345 if (sizeCache <= nbCache) {
4346 sizeCache *= 2;
4347 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4348 sizeof(xmlNsPtr));
4349 if (oldNs == NULL) {
4350 xmlGenericError(xmlGenericErrorContext,
4351 "xmlReconciliateNs : memory pbm\n");
4352 xmlFree(newNs);
4353 return(-1);
4354 }
4355 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4356 sizeof(xmlNsPtr));
4357 if (newNs == NULL) {
4358 xmlGenericError(xmlGenericErrorContext,
4359 "xmlReconciliateNs : memory pbm\n");
4360 xmlFree(oldNs);
4361 return(-1);
4362 }
4363 }
4364 newNs[nbCache] = n;
4365 oldNs[nbCache++] = node->ns;
4366 node->ns = n;
4367 }
4368 }
4369 }
4370 /*
4371 * now check for namespace hold by attributes on the node.
4372 */
4373 attr = node->properties;
4374 while (attr != NULL) {
4375 if (attr->ns != NULL) {
4376 /*
4377 * initialize the cache if needed
4378 */
4379 if (sizeCache == 0) {
4380 sizeCache = 10;
4381 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4382 sizeof(xmlNsPtr));
4383 if (oldNs == NULL) {
4384 xmlGenericError(xmlGenericErrorContext,
4385 "xmlReconciliateNs : memory pbm\n");
4386 return(-1);
4387 }
4388 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4389 sizeof(xmlNsPtr));
4390 if (newNs == NULL) {
4391 xmlGenericError(xmlGenericErrorContext,
4392 "xmlReconciliateNs : memory pbm\n");
4393 xmlFree(oldNs);
4394 return(-1);
4395 }
4396 }
4397 for (i = 0;i < nbCache;i++) {
4398 if (oldNs[i] == attr->ns) {
4399 node->ns = newNs[i];
4400 break;
4401 }
4402 }
4403 if (i == nbCache) {
4404 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004405 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004406 */
4407 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4408 if (n != NULL) { /* :-( what if else ??? */
4409 /*
4410 * check if we need to grow the cache buffers.
4411 */
4412 if (sizeCache <= nbCache) {
4413 sizeCache *= 2;
4414 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4415 sizeof(xmlNsPtr));
4416 if (oldNs == NULL) {
4417 xmlGenericError(xmlGenericErrorContext,
4418 "xmlReconciliateNs : memory pbm\n");
4419 xmlFree(newNs);
4420 return(-1);
4421 }
4422 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4423 sizeof(xmlNsPtr));
4424 if (newNs == NULL) {
4425 xmlGenericError(xmlGenericErrorContext,
4426 "xmlReconciliateNs : memory pbm\n");
4427 xmlFree(oldNs);
4428 return(-1);
4429 }
4430 }
4431 newNs[nbCache] = n;
4432 oldNs[nbCache++] = attr->ns;
4433 attr->ns = n;
4434 }
4435 }
4436 }
4437 attr = attr->next;
4438 }
4439
4440 /*
4441 * Browse the full subtree, deep first
4442 */
4443 if (node->children != NULL) {
4444 /* deep first */
4445 node = node->children;
4446 } else if ((node != tree) && (node->next != NULL)) {
4447 /* then siblings */
4448 node = node->next;
4449 } else if (node != tree) {
4450 /* go up to parents->next if needed */
4451 while (node != tree) {
4452 if (node->parent != NULL)
4453 node = node->parent;
4454 if ((node != tree) && (node->next != NULL)) {
4455 node = node->next;
4456 break;
4457 }
4458 if (node->parent == NULL) {
4459 node = NULL;
4460 break;
4461 }
4462 }
4463 /* exit condition */
4464 if (node == tree)
4465 node = NULL;
4466 }
4467 }
4468 return(ret);
4469}
4470
4471/**
4472 * xmlHasProp:
4473 * @node: the node
4474 * @name: the attribute name
4475 *
4476 * Search an attribute associated to a node
4477 * This function also looks in DTD attribute declaration for #FIXED or
4478 * default declaration values unless DTD use has been turned off.
4479 *
4480 * Returns the attribute or the attribute declaration or NULL if
4481 * neither was found.
4482 */
4483xmlAttrPtr
4484xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4485 xmlAttrPtr prop;
4486 xmlDocPtr doc;
4487
4488 if ((node == NULL) || (name == NULL)) return(NULL);
4489 /*
4490 * Check on the properties attached to the node
4491 */
4492 prop = node->properties;
4493 while (prop != NULL) {
4494 if (xmlStrEqual(prop->name, name)) {
4495 return(prop);
4496 }
4497 prop = prop->next;
4498 }
4499 if (!xmlCheckDTD) return(NULL);
4500
4501 /*
4502 * Check if there is a default declaration in the internal
4503 * or external subsets
4504 */
4505 doc = node->doc;
4506 if (doc != NULL) {
4507 xmlAttributePtr attrDecl;
4508 if (doc->intSubset != NULL) {
4509 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4510 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4511 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4512 if (attrDecl != NULL)
4513 return((xmlAttrPtr) attrDecl);
4514 }
4515 }
4516 return(NULL);
4517}
4518
4519/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004520 * xmlHasNsProp:
4521 * @node: the node
4522 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004523 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004524 *
4525 * Search for an attribute associated to a node
4526 * This attribute has to be anchored in the namespace specified.
4527 * This does the entity substitution.
4528 * This function looks in DTD attribute declaration for #FIXED or
4529 * default declaration values unless DTD use has been turned off.
4530 *
4531 * Returns the attribute or the attribute declaration or NULL
4532 * if neither was found.
4533 */
4534xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004535xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004536 xmlAttrPtr prop;
4537 xmlDocPtr doc;
4538 xmlNsPtr ns;
4539
4540 if (node == NULL)
4541 return(NULL);
4542
4543 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004544 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004545 return(xmlHasProp(node, name));
4546 while (prop != NULL) {
4547 /*
4548 * One need to have
4549 * - same attribute names
4550 * - and the attribute carrying that namespace
4551 * or
4552 * no namespace on the attribute and the element carrying it
4553 */
4554 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004555 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4556 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004557 }
4558 prop = prop->next;
4559 }
4560 if (!xmlCheckDTD) return(NULL);
4561
4562 /*
4563 * Check if there is a default declaration in the internal
4564 * or external subsets
4565 */
4566 doc = node->doc;
4567 if (doc != NULL) {
4568 if (doc->intSubset != NULL) {
4569 xmlAttributePtr attrDecl;
4570
4571 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4572 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4573 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4574
4575 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4576 /*
4577 * The DTD declaration only allows a prefix search
4578 */
4579 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004580 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004581 return((xmlAttrPtr) attrDecl);
4582 }
4583 }
4584 }
4585 return(NULL);
4586}
4587
4588/**
Owen Taylor3473f882001-02-23 17:55:21 +00004589 * xmlGetProp:
4590 * @node: the node
4591 * @name: the attribute name
4592 *
4593 * Search and get the value of an attribute associated to a node
4594 * This does the entity substitution.
4595 * This function looks in DTD attribute declaration for #FIXED or
4596 * default declaration values unless DTD use has been turned off.
4597 *
4598 * Returns the attribute value or NULL if not found.
4599 * It's up to the caller to free the memory.
4600 */
4601xmlChar *
4602xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4603 xmlAttrPtr prop;
4604 xmlDocPtr doc;
4605
4606 if ((node == NULL) || (name == NULL)) return(NULL);
4607 /*
4608 * Check on the properties attached to the node
4609 */
4610 prop = node->properties;
4611 while (prop != NULL) {
4612 if (xmlStrEqual(prop->name, name)) {
4613 xmlChar *ret;
4614
4615 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4616 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4617 return(ret);
4618 }
4619 prop = prop->next;
4620 }
4621 if (!xmlCheckDTD) return(NULL);
4622
4623 /*
4624 * Check if there is a default declaration in the internal
4625 * or external subsets
4626 */
4627 doc = node->doc;
4628 if (doc != NULL) {
4629 xmlAttributePtr attrDecl;
4630 if (doc->intSubset != NULL) {
4631 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4632 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4633 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4634 if (attrDecl != NULL)
4635 return(xmlStrdup(attrDecl->defaultValue));
4636 }
4637 }
4638 return(NULL);
4639}
4640
4641/**
4642 * xmlGetNsProp:
4643 * @node: the node
4644 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004645 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004646 *
4647 * Search and get the value of an attribute associated to a node
4648 * This attribute has to be anchored in the namespace specified.
4649 * This does the entity substitution.
4650 * This function looks in DTD attribute declaration for #FIXED or
4651 * default declaration values unless DTD use has been turned off.
4652 *
4653 * Returns the attribute value or NULL if not found.
4654 * It's up to the caller to free the memory.
4655 */
4656xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004657xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004658 xmlAttrPtr prop;
4659 xmlDocPtr doc;
4660 xmlNsPtr ns;
4661
4662 if (node == NULL)
4663 return(NULL);
4664
4665 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004666 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004667 return(xmlGetProp(node, name));
4668 while (prop != NULL) {
4669 /*
4670 * One need to have
4671 * - same attribute names
4672 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004673 */
4674 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004675 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004676 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004677 xmlChar *ret;
4678
4679 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4680 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4681 return(ret);
4682 }
4683 prop = prop->next;
4684 }
4685 if (!xmlCheckDTD) return(NULL);
4686
4687 /*
4688 * Check if there is a default declaration in the internal
4689 * or external subsets
4690 */
4691 doc = node->doc;
4692 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004693 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004694 xmlAttributePtr attrDecl;
4695
Owen Taylor3473f882001-02-23 17:55:21 +00004696 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4697 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4698 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4699
4700 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4701 /*
4702 * The DTD declaration only allows a prefix search
4703 */
4704 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004705 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004706 return(xmlStrdup(attrDecl->defaultValue));
4707 }
4708 }
4709 }
4710 return(NULL);
4711}
4712
4713/**
4714 * xmlSetProp:
4715 * @node: the node
4716 * @name: the attribute name
4717 * @value: the attribute value
4718 *
4719 * Set (or reset) an attribute carried by a node.
4720 * Returns the attribute pointer.
4721 */
4722xmlAttrPtr
4723xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004724 xmlAttrPtr prop;
4725 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004726
4727 if ((node == NULL) || (name == NULL))
4728 return(NULL);
4729 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004730 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004731 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004732 if ((xmlStrEqual(prop->name, name)) &&
4733 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004734 xmlNodePtr oldprop = prop->children;
4735
Owen Taylor3473f882001-02-23 17:55:21 +00004736 prop->children = NULL;
4737 prop->last = NULL;
4738 if (value != NULL) {
4739 xmlChar *buffer;
4740 xmlNodePtr tmp;
4741
4742 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4743 prop->children = xmlStringGetNodeList(node->doc, buffer);
4744 prop->last = NULL;
4745 prop->doc = doc;
4746 tmp = prop->children;
4747 while (tmp != NULL) {
4748 tmp->parent = (xmlNodePtr) prop;
4749 tmp->doc = doc;
4750 if (tmp->next == NULL)
4751 prop->last = tmp;
4752 tmp = tmp->next;
4753 }
4754 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004755 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004756 if (oldprop != NULL)
4757 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004758 return(prop);
4759 }
4760 prop = prop->next;
4761 }
4762 prop = xmlNewProp(node, name, value);
4763 return(prop);
4764}
4765
4766/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004767 * xmlUnsetProp:
4768 * @node: the node
4769 * @name: the attribute name
4770 *
4771 * Remove an attribute carried by a node.
4772 * Returns 0 if successful, -1 if not found
4773 */
4774int
4775xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4776 xmlAttrPtr prop = node->properties, prev = NULL;;
4777
4778 if ((node == NULL) || (name == NULL))
4779 return(-1);
4780 while (prop != NULL) {
4781 if ((xmlStrEqual(prop->name, name)) &&
4782 (prop->ns == NULL)) {
4783 if (prev == NULL)
4784 node->properties = prop->next;
4785 else
4786 prev->next = prop->next;
4787 xmlFreeProp(prop);
4788 return(0);
4789 }
4790 prev = prop;
4791 prop = prop->next;
4792 }
4793 return(-1);
4794}
4795
4796/**
Owen Taylor3473f882001-02-23 17:55:21 +00004797 * xmlSetNsProp:
4798 * @node: the node
4799 * @ns: the namespace definition
4800 * @name: the attribute name
4801 * @value: the attribute value
4802 *
4803 * Set (or reset) an attribute carried by a node.
4804 * The ns structure must be in scope, this is not checked.
4805 *
4806 * Returns the attribute pointer.
4807 */
4808xmlAttrPtr
4809xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4810 const xmlChar *value) {
4811 xmlAttrPtr prop;
4812
4813 if ((node == NULL) || (name == NULL))
4814 return(NULL);
4815
4816 if (ns == NULL)
4817 return(xmlSetProp(node, name, value));
4818 if (ns->href == NULL)
4819 return(NULL);
4820 prop = node->properties;
4821
4822 while (prop != NULL) {
4823 /*
4824 * One need to have
4825 * - same attribute names
4826 * - and the attribute carrying that namespace
4827 * or
4828 * no namespace on the attribute and the element carrying it
4829 */
4830 if ((xmlStrEqual(prop->name, name)) &&
4831 (((prop->ns == NULL) && (node->ns != NULL) &&
4832 (xmlStrEqual(node->ns->href, ns->href))) ||
4833 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4834 if (prop->children != NULL)
4835 xmlFreeNodeList(prop->children);
4836 prop->children = NULL;
4837 prop->last = NULL;
4838 prop->ns = ns;
4839 if (value != NULL) {
4840 xmlChar *buffer;
4841 xmlNodePtr tmp;
4842
4843 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4844 prop->children = xmlStringGetNodeList(node->doc, buffer);
4845 prop->last = NULL;
4846 tmp = prop->children;
4847 while (tmp != NULL) {
4848 tmp->parent = (xmlNodePtr) prop;
4849 if (tmp->next == NULL)
4850 prop->last = tmp;
4851 tmp = tmp->next;
4852 }
4853 xmlFree(buffer);
4854 }
4855 return(prop);
4856 }
4857 prop = prop->next;
4858 }
4859 prop = xmlNewNsProp(node, ns, name, value);
4860 return(prop);
4861}
4862
4863/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004864 * xmlUnsetNsProp:
4865 * @node: the node
4866 * @ns: the namespace definition
4867 * @name: the attribute name
4868 *
4869 * Remove an attribute carried by a node.
4870 * Returns 0 if successful, -1 if not found
4871 */
4872int
4873xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4874 xmlAttrPtr prop = node->properties, prev = NULL;;
4875
4876 if ((node == NULL) || (name == NULL))
4877 return(-1);
4878 if (ns == NULL)
4879 return(xmlUnsetProp(node, name));
4880 if (ns->href == NULL)
4881 return(-1);
4882 while (prop != NULL) {
4883 if ((xmlStrEqual(prop->name, name)) &&
4884 (((prop->ns == NULL) && (node->ns != NULL) &&
4885 (xmlStrEqual(node->ns->href, ns->href))) ||
4886 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4887 if (prev == NULL)
4888 node->properties = prop->next;
4889 else
4890 prev->next = prop->next;
4891 xmlFreeProp(prop);
4892 return(0);
4893 }
4894 prev = prop;
4895 prop = prop->next;
4896 }
4897 return(-1);
4898}
4899
4900/**
Owen Taylor3473f882001-02-23 17:55:21 +00004901 * xmlNodeIsText:
4902 * @node: the node
4903 *
4904 * Is this node a Text node ?
4905 * Returns 1 yes, 0 no
4906 */
4907int
4908xmlNodeIsText(xmlNodePtr node) {
4909 if (node == NULL) return(0);
4910
4911 if (node->type == XML_TEXT_NODE) return(1);
4912 return(0);
4913}
4914
4915/**
4916 * xmlIsBlankNode:
4917 * @node: the node
4918 *
4919 * Checks whether this node is an empty or whitespace only
4920 * (and possibly ignorable) text-node.
4921 *
4922 * Returns 1 yes, 0 no
4923 */
4924int
4925xmlIsBlankNode(xmlNodePtr node) {
4926 const xmlChar *cur;
4927 if (node == NULL) return(0);
4928
Daniel Veillard7db37732001-07-12 01:20:08 +00004929 if ((node->type != XML_TEXT_NODE) &&
4930 (node->type != XML_CDATA_SECTION_NODE))
4931 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004932 if (node->content == NULL) return(1);
4933#ifndef XML_USE_BUFFER_CONTENT
4934 cur = node->content;
4935#else
4936 cur = xmlBufferContent(node->content);
4937#endif
4938 while (*cur != 0) {
4939 if (!IS_BLANK(*cur)) return(0);
4940 cur++;
4941 }
4942
4943 return(1);
4944}
4945
4946/**
4947 * xmlTextConcat:
4948 * @node: the node
4949 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00004950 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00004951 *
4952 * Concat the given string at the end of the existing node content
4953 */
4954
4955void
4956xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4957 if (node == NULL) return;
4958
4959 if ((node->type != XML_TEXT_NODE) &&
4960 (node->type != XML_CDATA_SECTION_NODE)) {
4961#ifdef DEBUG_TREE
4962 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004963 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004964#endif
4965 return;
4966 }
4967#ifndef XML_USE_BUFFER_CONTENT
4968 node->content = xmlStrncat(node->content, content, len);
4969#else
4970 xmlBufferAdd(node->content, content, len);
4971#endif
4972}
4973
4974/************************************************************************
4975 * *
4976 * Output : to a FILE or in memory *
4977 * *
4978 ************************************************************************/
4979
Owen Taylor3473f882001-02-23 17:55:21 +00004980/**
4981 * xmlBufferCreate:
4982 *
4983 * routine to create an XML buffer.
4984 * returns the new structure.
4985 */
4986xmlBufferPtr
4987xmlBufferCreate(void) {
4988 xmlBufferPtr ret;
4989
4990 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4991 if (ret == NULL) {
4992 xmlGenericError(xmlGenericErrorContext,
4993 "xmlBufferCreate : out of memory!\n");
4994 return(NULL);
4995 }
4996 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004997 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004998 ret->alloc = xmlBufferAllocScheme;
4999 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5000 if (ret->content == NULL) {
5001 xmlGenericError(xmlGenericErrorContext,
5002 "xmlBufferCreate : out of memory!\n");
5003 xmlFree(ret);
5004 return(NULL);
5005 }
5006 ret->content[0] = 0;
5007 return(ret);
5008}
5009
5010/**
5011 * xmlBufferCreateSize:
5012 * @size: initial size of buffer
5013 *
5014 * routine to create an XML buffer.
5015 * returns the new structure.
5016 */
5017xmlBufferPtr
5018xmlBufferCreateSize(size_t size) {
5019 xmlBufferPtr ret;
5020
5021 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5022 if (ret == NULL) {
5023 xmlGenericError(xmlGenericErrorContext,
5024 "xmlBufferCreate : out of memory!\n");
5025 return(NULL);
5026 }
5027 ret->use = 0;
5028 ret->alloc = xmlBufferAllocScheme;
5029 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5030 if (ret->size){
5031 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5032 if (ret->content == NULL) {
5033 xmlGenericError(xmlGenericErrorContext,
5034 "xmlBufferCreate : out of memory!\n");
5035 xmlFree(ret);
5036 return(NULL);
5037 }
5038 ret->content[0] = 0;
5039 } else
5040 ret->content = NULL;
5041 return(ret);
5042}
5043
5044/**
5045 * xmlBufferSetAllocationScheme:
5046 * @buf: the buffer to free
5047 * @scheme: allocation scheme to use
5048 *
5049 * Sets the allocation scheme for this buffer
5050 */
5051void
5052xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5053 xmlBufferAllocationScheme scheme) {
5054 if (buf == NULL) {
5055#ifdef DEBUG_BUFFER
5056 xmlGenericError(xmlGenericErrorContext,
5057 "xmlBufferSetAllocationScheme: buf == NULL\n");
5058#endif
5059 return;
5060 }
5061
5062 buf->alloc = scheme;
5063}
5064
5065/**
5066 * xmlBufferFree:
5067 * @buf: the buffer to free
5068 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005069 * Frees an XML buffer. It frees both the content and the structure which
5070 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005071 */
5072void
5073xmlBufferFree(xmlBufferPtr buf) {
5074 if (buf == NULL) {
5075#ifdef DEBUG_BUFFER
5076 xmlGenericError(xmlGenericErrorContext,
5077 "xmlBufferFree: buf == NULL\n");
5078#endif
5079 return;
5080 }
5081 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005082 xmlFree(buf->content);
5083 }
Owen Taylor3473f882001-02-23 17:55:21 +00005084 xmlFree(buf);
5085}
5086
5087/**
5088 * xmlBufferEmpty:
5089 * @buf: the buffer
5090 *
5091 * empty a buffer.
5092 */
5093void
5094xmlBufferEmpty(xmlBufferPtr buf) {
5095 if (buf->content == NULL) return;
5096 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005097 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005098}
5099
5100/**
5101 * xmlBufferShrink:
5102 * @buf: the buffer to dump
5103 * @len: the number of xmlChar to remove
5104 *
5105 * Remove the beginning of an XML buffer.
5106 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005107 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005108 */
5109int
5110xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5111 if (len == 0) return(0);
5112 if (len > buf->use) return(-1);
5113
5114 buf->use -= len;
5115 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5116
5117 buf->content[buf->use] = 0;
5118 return(len);
5119}
5120
5121/**
5122 * xmlBufferGrow:
5123 * @buf: the buffer
5124 * @len: the minimum free size to allocate
5125 *
5126 * Grow the available space of an XML buffer.
5127 *
5128 * Returns the new available space or -1 in case of error
5129 */
5130int
5131xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5132 int size;
5133 xmlChar *newbuf;
5134
5135 if (len + buf->use < buf->size) return(0);
5136
5137 size = buf->use + len + 100;
5138
5139 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5140 if (newbuf == NULL) return(-1);
5141 buf->content = newbuf;
5142 buf->size = size;
5143 return(buf->size - buf->use);
5144}
5145
5146/**
5147 * xmlBufferDump:
5148 * @file: the file output
5149 * @buf: the buffer to dump
5150 *
5151 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005152 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005153 */
5154int
5155xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5156 int ret;
5157
5158 if (buf == NULL) {
5159#ifdef DEBUG_BUFFER
5160 xmlGenericError(xmlGenericErrorContext,
5161 "xmlBufferDump: buf == NULL\n");
5162#endif
5163 return(0);
5164 }
5165 if (buf->content == NULL) {
5166#ifdef DEBUG_BUFFER
5167 xmlGenericError(xmlGenericErrorContext,
5168 "xmlBufferDump: buf->content == NULL\n");
5169#endif
5170 return(0);
5171 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005172 if (file == NULL)
5173 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005174 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5175 return(ret);
5176}
5177
5178/**
5179 * xmlBufferContent:
5180 * @buf: the buffer
5181 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005182 * Function to extract the content of a buffer
5183 *
Owen Taylor3473f882001-02-23 17:55:21 +00005184 * Returns the internal content
5185 */
5186
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005187const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005188xmlBufferContent(const xmlBufferPtr buf)
5189{
5190 if(!buf)
5191 return NULL;
5192
5193 return buf->content;
5194}
5195
5196/**
5197 * xmlBufferLength:
5198 * @buf: the buffer
5199 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005200 * Function to get the length of a buffer
5201 *
Owen Taylor3473f882001-02-23 17:55:21 +00005202 * Returns the length of data in the internal content
5203 */
5204
5205int
5206xmlBufferLength(const xmlBufferPtr buf)
5207{
5208 if(!buf)
5209 return 0;
5210
5211 return buf->use;
5212}
5213
5214/**
5215 * xmlBufferResize:
5216 * @buf: the buffer to resize
5217 * @size: the desired size
5218 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005219 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005220 *
5221 * Returns 0 in case of problems, 1 otherwise
5222 */
5223int
5224xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5225{
5226 unsigned int newSize;
5227 xmlChar* rebuf = NULL;
5228
5229 /*take care of empty case*/
5230 newSize = (buf->size ? buf->size*2 : size);
5231
5232 /* Don't resize if we don't have to */
5233 if (size < buf->size)
5234 return 1;
5235
5236 /* figure out new size */
5237 switch (buf->alloc){
5238 case XML_BUFFER_ALLOC_DOUBLEIT:
5239 while (size > newSize) newSize *= 2;
5240 break;
5241 case XML_BUFFER_ALLOC_EXACT:
5242 newSize = size+10;
5243 break;
5244 default:
5245 newSize = size+10;
5246 break;
5247 }
5248
5249 if (buf->content == NULL)
5250 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5251 else
5252 rebuf = (xmlChar *) xmlRealloc(buf->content,
5253 newSize * sizeof(xmlChar));
5254 if (rebuf == NULL) {
5255 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005256 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005257 return 0;
5258 }
5259 buf->content = rebuf;
5260 buf->size = newSize;
5261
5262 return 1;
5263}
5264
5265/**
5266 * xmlBufferAdd:
5267 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005268 * @str: the #xmlChar string
5269 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005270 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005271 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005272 * str is recomputed.
5273 */
5274void
5275xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5276 unsigned int needSize;
5277
5278 if (str == NULL) {
5279#ifdef DEBUG_BUFFER
5280 xmlGenericError(xmlGenericErrorContext,
5281 "xmlBufferAdd: str == NULL\n");
5282#endif
5283 return;
5284 }
5285 if (len < -1) {
5286#ifdef DEBUG_BUFFER
5287 xmlGenericError(xmlGenericErrorContext,
5288 "xmlBufferAdd: len < 0\n");
5289#endif
5290 return;
5291 }
5292 if (len == 0) return;
5293
5294 if (len < 0)
5295 len = xmlStrlen(str);
5296
5297 if (len <= 0) return;
5298
5299 needSize = buf->use + len + 2;
5300 if (needSize > buf->size){
5301 if (!xmlBufferResize(buf, needSize)){
5302 xmlGenericError(xmlGenericErrorContext,
5303 "xmlBufferAdd : out of memory!\n");
5304 return;
5305 }
5306 }
5307
5308 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5309 buf->use += len;
5310 buf->content[buf->use] = 0;
5311}
5312
5313/**
5314 * xmlBufferAddHead:
5315 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005316 * @str: the #xmlChar string
5317 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005318 *
5319 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005320 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005321 */
5322void
5323xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5324 unsigned int needSize;
5325
5326 if (str == NULL) {
5327#ifdef DEBUG_BUFFER
5328 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005329 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005330#endif
5331 return;
5332 }
5333 if (len < -1) {
5334#ifdef DEBUG_BUFFER
5335 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005336 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005337#endif
5338 return;
5339 }
5340 if (len == 0) return;
5341
5342 if (len < 0)
5343 len = xmlStrlen(str);
5344
5345 if (len <= 0) return;
5346
5347 needSize = buf->use + len + 2;
5348 if (needSize > buf->size){
5349 if (!xmlBufferResize(buf, needSize)){
5350 xmlGenericError(xmlGenericErrorContext,
5351 "xmlBufferAddHead : out of memory!\n");
5352 return;
5353 }
5354 }
5355
5356 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5357 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5358 buf->use += len;
5359 buf->content[buf->use] = 0;
5360}
5361
5362/**
5363 * xmlBufferCat:
5364 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005365 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005366 *
5367 * Append a zero terminated string to an XML buffer.
5368 */
5369void
5370xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5371 if (str != NULL)
5372 xmlBufferAdd(buf, str, -1);
5373}
5374
5375/**
5376 * xmlBufferCCat:
5377 * @buf: the buffer to dump
5378 * @str: the C char string
5379 *
5380 * Append a zero terminated C string to an XML buffer.
5381 */
5382void
5383xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5384 const char *cur;
5385
5386 if (str == NULL) {
5387#ifdef DEBUG_BUFFER
5388 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005389 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005390#endif
5391 return;
5392 }
5393 for (cur = str;*cur != 0;cur++) {
5394 if (buf->use + 10 >= buf->size) {
5395 if (!xmlBufferResize(buf, buf->use+10)){
5396 xmlGenericError(xmlGenericErrorContext,
5397 "xmlBufferCCat : out of memory!\n");
5398 return;
5399 }
5400 }
5401 buf->content[buf->use++] = *cur;
5402 }
5403 buf->content[buf->use] = 0;
5404}
5405
5406/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005407 * xmlBufferWriteXmlCHAR:
5408 * @buf: the XML buffer
5409 * @string: the string to add
5410 *
5411 * For VMS only.
5412 * routine which manages and grows an output buffer. This one adds
5413 * xmlChars at the end of the buffer.
5414 */
5415/**
Owen Taylor3473f882001-02-23 17:55:21 +00005416 * xmlBufferWriteCHAR:
5417 * @buf: the XML buffer
5418 * @string: the string to add
5419 *
5420 * routine which manages and grows an output buffer. This one adds
5421 * xmlChars at the end of the buffer.
5422 */
5423void
5424#ifdef VMS
5425xmlBufferWriteXmlCHAR
5426#else
5427xmlBufferWriteCHAR
5428#endif
5429(xmlBufferPtr buf, const xmlChar *string) {
5430 xmlBufferCat(buf, string);
5431}
5432
5433/**
5434 * xmlBufferWriteChar:
5435 * @buf: the XML buffer output
5436 * @string: the string to add
5437 *
5438 * routine which manage and grows an output buffer. This one add
5439 * C chars at the end of the array.
5440 */
5441void
5442xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5443 xmlBufferCCat(buf, string);
5444}
5445
5446
5447/**
5448 * xmlBufferWriteQuotedString:
5449 * @buf: the XML buffer output
5450 * @string: the string to add
5451 *
5452 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005453 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005454 * quote or double-quotes internally
5455 */
5456void
5457xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5458 if (xmlStrchr(string, '"')) {
5459 if (xmlStrchr(string, '\'')) {
5460#ifdef DEBUG_BUFFER
5461 xmlGenericError(xmlGenericErrorContext,
5462 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5463#endif
5464 }
5465 xmlBufferCCat(buf, "'");
5466 xmlBufferCat(buf, string);
5467 xmlBufferCCat(buf, "'");
5468 } else {
5469 xmlBufferCCat(buf, "\"");
5470 xmlBufferCat(buf, string);
5471 xmlBufferCCat(buf, "\"");
5472 }
5473}
5474
5475
5476/************************************************************************
5477 * *
5478 * Dumping XML tree content to a simple buffer *
5479 * *
5480 ************************************************************************/
5481
5482void
5483xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5484 int format);
5485static void
5486xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5487 int format);
5488void
5489htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5490
5491/**
5492 * xmlNsDump:
5493 * @buf: the XML buffer output
5494 * @cur: a namespace
5495 *
5496 * Dump a local Namespace definition.
5497 * Should be called in the context of attributes dumps.
5498 */
5499static void
5500xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5501 if (cur == NULL) {
5502#ifdef DEBUG_TREE
5503 xmlGenericError(xmlGenericErrorContext,
5504 "xmlNsDump : Ns == NULL\n");
5505#endif
5506 return;
5507 }
5508 if (cur->type == XML_LOCAL_NAMESPACE) {
5509 /* Within the context of an element attributes */
5510 if (cur->prefix != NULL) {
5511 xmlBufferWriteChar(buf, " xmlns:");
5512 xmlBufferWriteCHAR(buf, cur->prefix);
5513 } else
5514 xmlBufferWriteChar(buf, " xmlns");
5515 xmlBufferWriteChar(buf, "=");
5516 xmlBufferWriteQuotedString(buf, cur->href);
5517 }
5518}
5519
5520/**
5521 * xmlNsListDump:
5522 * @buf: the XML buffer output
5523 * @cur: the first namespace
5524 *
5525 * Dump a list of local Namespace definitions.
5526 * Should be called in the context of attributes dumps.
5527 */
5528static void
5529xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5530 while (cur != NULL) {
5531 xmlNsDump(buf, cur);
5532 cur = cur->next;
5533 }
5534}
5535
5536/**
5537 * xmlDtdDump:
5538 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005539 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005540 *
5541 * Dump the XML document DTD, if any.
5542 */
5543static void
5544xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5545 if (dtd == NULL) {
5546#ifdef DEBUG_TREE
5547 xmlGenericError(xmlGenericErrorContext,
5548 "xmlDtdDump : no internal subset\n");
5549#endif
5550 return;
5551 }
5552 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5553 xmlBufferWriteCHAR(buf, dtd->name);
5554 if (dtd->ExternalID != NULL) {
5555 xmlBufferWriteChar(buf, " PUBLIC ");
5556 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5557 xmlBufferWriteChar(buf, " ");
5558 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5559 } else if (dtd->SystemID != NULL) {
5560 xmlBufferWriteChar(buf, " SYSTEM ");
5561 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5562 }
5563 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5564 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5565 xmlBufferWriteChar(buf, ">");
5566 return;
5567 }
5568 xmlBufferWriteChar(buf, " [\n");
5569 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5570#if 0
5571 if (dtd->entities != NULL)
5572 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5573 if (dtd->notations != NULL)
5574 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5575 if (dtd->elements != NULL)
5576 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5577 if (dtd->attributes != NULL)
5578 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5579#endif
5580 xmlBufferWriteChar(buf, "]>");
5581}
5582
5583/**
5584 * xmlAttrDump:
5585 * @buf: the XML buffer output
5586 * @doc: the document
5587 * @cur: the attribute pointer
5588 *
5589 * Dump an XML attribute
5590 */
5591static void
5592xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5593 xmlChar *value;
5594
5595 if (cur == NULL) {
5596#ifdef DEBUG_TREE
5597 xmlGenericError(xmlGenericErrorContext,
5598 "xmlAttrDump : property == NULL\n");
5599#endif
5600 return;
5601 }
5602 xmlBufferWriteChar(buf, " ");
5603 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5604 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5605 xmlBufferWriteChar(buf, ":");
5606 }
5607 xmlBufferWriteCHAR(buf, cur->name);
5608 value = xmlNodeListGetString(doc, cur->children, 0);
5609 if (value != NULL) {
5610 xmlBufferWriteChar(buf, "=");
5611 xmlBufferWriteQuotedString(buf, value);
5612 xmlFree(value);
5613 } else {
5614 xmlBufferWriteChar(buf, "=\"\"");
5615 }
5616}
5617
5618/**
5619 * xmlAttrListDump:
5620 * @buf: the XML buffer output
5621 * @doc: the document
5622 * @cur: the first attribute pointer
5623 *
5624 * Dump a list of XML attributes
5625 */
5626static void
5627xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5628 if (cur == NULL) {
5629#ifdef DEBUG_TREE
5630 xmlGenericError(xmlGenericErrorContext,
5631 "xmlAttrListDump : property == NULL\n");
5632#endif
5633 return;
5634 }
5635 while (cur != NULL) {
5636 xmlAttrDump(buf, doc, cur);
5637 cur = cur->next;
5638 }
5639}
5640
5641
5642
5643/**
5644 * xmlNodeListDump:
5645 * @buf: the XML buffer output
5646 * @doc: the document
5647 * @cur: the first node
5648 * @level: the imbrication level for indenting
5649 * @format: is formatting allowed
5650 *
5651 * Dump an XML node list, recursive behaviour,children are printed too.
5652 */
5653static void
5654xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5655 int format) {
5656 int i;
5657
5658 if (cur == NULL) {
5659#ifdef DEBUG_TREE
5660 xmlGenericError(xmlGenericErrorContext,
5661 "xmlNodeListDump : node == NULL\n");
5662#endif
5663 return;
5664 }
5665 while (cur != NULL) {
5666 if ((format) && (xmlIndentTreeOutput) &&
5667 (cur->type == XML_ELEMENT_NODE))
5668 for (i = 0;i < level;i++)
5669 xmlBufferWriteChar(buf, " ");
5670 xmlNodeDump(buf, doc, cur, level, format);
5671 if (format) {
5672 xmlBufferWriteChar(buf, "\n");
5673 }
5674 cur = cur->next;
5675 }
5676}
5677
5678/**
5679 * xmlNodeDump:
5680 * @buf: the XML buffer output
5681 * @doc: the document
5682 * @cur: the current node
5683 * @level: the imbrication level for indenting
5684 * @format: is formatting allowed
5685 *
5686 * Dump an XML node, recursive behaviour,children are printed too.
5687 */
5688void
5689xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5690 int format) {
5691 int i;
5692 xmlNodePtr tmp;
5693
5694 if (cur == NULL) {
5695#ifdef DEBUG_TREE
5696 xmlGenericError(xmlGenericErrorContext,
5697 "xmlNodeDump : node == NULL\n");
5698#endif
5699 return;
5700 }
5701 if (cur->type == XML_XINCLUDE_START)
5702 return;
5703 if (cur->type == XML_XINCLUDE_END)
5704 return;
5705 if (cur->type == XML_DTD_NODE) {
5706 xmlDtdDump(buf, (xmlDtdPtr) cur);
5707 return;
5708 }
5709 if (cur->type == XML_ELEMENT_DECL) {
5710 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5711 return;
5712 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005713 if (cur->type == XML_ATTRIBUTE_NODE){
5714 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5715 return;
5716 }
Owen Taylor3473f882001-02-23 17:55:21 +00005717 if (cur->type == XML_ATTRIBUTE_DECL) {
5718 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5719 return;
5720 }
5721 if (cur->type == XML_ENTITY_DECL) {
5722 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5723 return;
5724 }
5725 if (cur->type == XML_TEXT_NODE) {
5726 if (cur->content != NULL) {
5727 if ((cur->name == xmlStringText) ||
5728 (cur->name != xmlStringTextNoenc)) {
5729 xmlChar *buffer;
5730
5731#ifndef XML_USE_BUFFER_CONTENT
5732 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5733#else
5734 buffer = xmlEncodeEntitiesReentrant(doc,
5735 xmlBufferContent(cur->content));
5736#endif
5737 if (buffer != NULL) {
5738 xmlBufferWriteCHAR(buf, buffer);
5739 xmlFree(buffer);
5740 }
5741 } else {
5742 /*
5743 * Disable escaping, needed for XSLT
5744 */
5745#ifndef XML_USE_BUFFER_CONTENT
5746 xmlBufferWriteCHAR(buf, cur->content);
5747#else
5748 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5749#endif
5750 }
5751 }
5752 return;
5753 }
5754 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005755 xmlBufferWriteChar(buf, "<?");
5756 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005757 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005758 xmlBufferWriteChar(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00005759#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard2c748c62002-01-16 15:37:50 +00005760 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005761#else
Daniel Veillard2c748c62002-01-16 15:37:50 +00005762 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00005763#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005764 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00005765 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00005766 return;
5767 }
5768 if (cur->type == XML_COMMENT_NODE) {
5769 if (cur->content != NULL) {
5770 xmlBufferWriteChar(buf, "<!--");
5771#ifndef XML_USE_BUFFER_CONTENT
5772 xmlBufferWriteCHAR(buf, cur->content);
5773#else
5774 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5775#endif
5776 xmlBufferWriteChar(buf, "-->");
5777 }
5778 return;
5779 }
5780 if (cur->type == XML_ENTITY_REF_NODE) {
5781 xmlBufferWriteChar(buf, "&");
5782 xmlBufferWriteCHAR(buf, cur->name);
5783 xmlBufferWriteChar(buf, ";");
5784 return;
5785 }
5786 if (cur->type == XML_CDATA_SECTION_NODE) {
5787 xmlBufferWriteChar(buf, "<![CDATA[");
5788 if (cur->content != NULL)
5789#ifndef XML_USE_BUFFER_CONTENT
5790 xmlBufferWriteCHAR(buf, cur->content);
5791#else
5792 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5793#endif
5794 xmlBufferWriteChar(buf, "]]>");
5795 return;
5796 }
5797
5798 if (format == 1) {
5799 tmp = cur->children;
5800 while (tmp != NULL) {
5801 if ((tmp->type == XML_TEXT_NODE) ||
5802 (tmp->type == XML_ENTITY_REF_NODE)) {
5803 format = 0;
5804 break;
5805 }
5806 tmp = tmp->next;
5807 }
5808 }
5809 xmlBufferWriteChar(buf, "<");
5810 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5811 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5812 xmlBufferWriteChar(buf, ":");
5813 }
5814
5815 xmlBufferWriteCHAR(buf, cur->name);
5816 if (cur->nsDef)
5817 xmlNsListDump(buf, cur->nsDef);
5818 if (cur->properties != NULL)
5819 xmlAttrListDump(buf, doc, cur->properties);
5820
Daniel Veillard7db37732001-07-12 01:20:08 +00005821 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5822 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005823 (!xmlSaveNoEmptyTags)) {
5824 xmlBufferWriteChar(buf, "/>");
5825 return;
5826 }
5827 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005828 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005829 xmlChar *buffer;
5830
5831#ifndef XML_USE_BUFFER_CONTENT
5832 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5833#else
5834 buffer = xmlEncodeEntitiesReentrant(doc,
5835 xmlBufferContent(cur->content));
5836#endif
5837 if (buffer != NULL) {
5838 xmlBufferWriteCHAR(buf, buffer);
5839 xmlFree(buffer);
5840 }
5841 }
5842 if (cur->children != NULL) {
5843 if (format) xmlBufferWriteChar(buf, "\n");
5844 xmlNodeListDump(buf, doc, cur->children,
5845 (level >= 0?level+1:-1), format);
5846 if ((xmlIndentTreeOutput) && (format))
5847 for (i = 0;i < level;i++)
5848 xmlBufferWriteChar(buf, " ");
5849 }
5850 xmlBufferWriteChar(buf, "</");
5851 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5852 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5853 xmlBufferWriteChar(buf, ":");
5854 }
5855
5856 xmlBufferWriteCHAR(buf, cur->name);
5857 xmlBufferWriteChar(buf, ">");
5858}
5859
5860/**
5861 * xmlElemDump:
5862 * @f: the FILE * for the output
5863 * @doc: the document
5864 * @cur: the current node
5865 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005866 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00005867 */
5868void
5869xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5870 xmlBufferPtr buf;
5871
5872 if (cur == NULL) {
5873#ifdef DEBUG_TREE
5874 xmlGenericError(xmlGenericErrorContext,
5875 "xmlElemDump : cur == NULL\n");
5876#endif
5877 return;
5878 }
Owen Taylor3473f882001-02-23 17:55:21 +00005879#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005880 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005881 xmlGenericError(xmlGenericErrorContext,
5882 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005883 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005884#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005885
Owen Taylor3473f882001-02-23 17:55:21 +00005886 buf = xmlBufferCreate();
5887 if (buf == NULL) return;
5888 if ((doc != NULL) &&
5889 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5890#ifdef LIBXML_HTML_ENABLED
5891 htmlNodeDump(buf, doc, cur);
5892#else
5893 xmlGenericError(xmlGenericErrorContext,
5894 "HTML support not compiled in\n");
5895#endif /* LIBXML_HTML_ENABLED */
5896 } else
5897 xmlNodeDump(buf, doc, cur, 0, 1);
5898 xmlBufferDump(f, buf);
5899 xmlBufferFree(buf);
5900}
5901
5902/************************************************************************
5903 * *
5904 * Dumping XML tree content to an I/O output buffer *
5905 * *
5906 ************************************************************************/
5907
5908void
5909xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5910 int level, int format, const char *encoding);
5911static void
5912xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5913 int level, int format, const char *encoding);
5914/**
5915 * xmlNsDumpOutput:
5916 * @buf: the XML buffer output
5917 * @cur: a namespace
5918 *
5919 * Dump a local Namespace definition.
5920 * Should be called in the context of attributes dumps.
5921 */
5922static void
5923xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5924 if (cur == NULL) {
5925#ifdef DEBUG_TREE
5926 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005927 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005928#endif
5929 return;
5930 }
5931 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5932 /* Within the context of an element attributes */
5933 if (cur->prefix != NULL) {
5934 xmlOutputBufferWriteString(buf, " xmlns:");
5935 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5936 } else
5937 xmlOutputBufferWriteString(buf, " xmlns");
5938 xmlOutputBufferWriteString(buf, "=");
5939 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5940 }
5941}
5942
5943/**
5944 * xmlNsListDumpOutput:
5945 * @buf: the XML buffer output
5946 * @cur: the first namespace
5947 *
5948 * Dump a list of local Namespace definitions.
5949 * Should be called in the context of attributes dumps.
5950 */
5951static void
5952xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5953 while (cur != NULL) {
5954 xmlNsDumpOutput(buf, cur);
5955 cur = cur->next;
5956 }
5957}
5958
5959/**
5960 * xmlDtdDumpOutput:
5961 * @buf: the XML buffer output
5962 * @doc: the document
5963 * @encoding: an optional encoding string
5964 *
5965 * Dump the XML document DTD, if any.
5966 */
5967static void
5968xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5969 if (dtd == NULL) {
5970#ifdef DEBUG_TREE
5971 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005972 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005973#endif
5974 return;
5975 }
5976 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5977 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5978 if (dtd->ExternalID != NULL) {
5979 xmlOutputBufferWriteString(buf, " PUBLIC ");
5980 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5981 xmlOutputBufferWriteString(buf, " ");
5982 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5983 } else if (dtd->SystemID != NULL) {
5984 xmlOutputBufferWriteString(buf, " SYSTEM ");
5985 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5986 }
5987 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5988 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5989 xmlOutputBufferWriteString(buf, ">");
5990 return;
5991 }
5992 xmlOutputBufferWriteString(buf, " [\n");
5993 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5994 xmlOutputBufferWriteString(buf, "]>");
5995}
5996
5997/**
5998 * xmlAttrDumpOutput:
5999 * @buf: the XML buffer output
6000 * @doc: the document
6001 * @cur: the attribute pointer
6002 * @encoding: an optional encoding string
6003 *
6004 * Dump an XML attribute
6005 */
6006static void
6007xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006008 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006009 xmlChar *value;
6010
6011 if (cur == NULL) {
6012#ifdef DEBUG_TREE
6013 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006014 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006015#endif
6016 return;
6017 }
6018 xmlOutputBufferWriteString(buf, " ");
6019 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6020 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6021 xmlOutputBufferWriteString(buf, ":");
6022 }
6023 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6024 value = xmlNodeListGetString(doc, cur->children, 0);
6025 if (value) {
6026 xmlOutputBufferWriteString(buf, "=");
6027 xmlBufferWriteQuotedString(buf->buffer, value);
6028 xmlFree(value);
6029 } else {
6030 xmlOutputBufferWriteString(buf, "=\"\"");
6031 }
6032}
6033
6034/**
6035 * xmlAttrListDumpOutput:
6036 * @buf: the XML buffer output
6037 * @doc: the document
6038 * @cur: the first attribute pointer
6039 * @encoding: an optional encoding string
6040 *
6041 * Dump a list of XML attributes
6042 */
6043static void
6044xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6045 xmlAttrPtr cur, const char *encoding) {
6046 if (cur == NULL) {
6047#ifdef DEBUG_TREE
6048 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006049 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006050#endif
6051 return;
6052 }
6053 while (cur != NULL) {
6054 xmlAttrDumpOutput(buf, doc, cur, encoding);
6055 cur = cur->next;
6056 }
6057}
6058
6059
6060
6061/**
6062 * xmlNodeListDumpOutput:
6063 * @buf: the XML buffer output
6064 * @doc: the document
6065 * @cur: the first node
6066 * @level: the imbrication level for indenting
6067 * @format: is formatting allowed
6068 * @encoding: an optional encoding string
6069 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006070 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006071 */
6072static void
6073xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6074 xmlNodePtr cur, int level, int format, const char *encoding) {
6075 int i;
6076
6077 if (cur == NULL) {
6078#ifdef DEBUG_TREE
6079 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006080 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006081#endif
6082 return;
6083 }
6084 while (cur != NULL) {
6085 if ((format) && (xmlIndentTreeOutput) &&
6086 (cur->type == XML_ELEMENT_NODE))
6087 for (i = 0;i < level;i++)
6088 xmlOutputBufferWriteString(buf, " ");
6089 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6090 if (format) {
6091 xmlOutputBufferWriteString(buf, "\n");
6092 }
6093 cur = cur->next;
6094 }
6095}
6096
6097/**
6098 * xmlNodeDumpOutput:
6099 * @buf: the XML buffer output
6100 * @doc: the document
6101 * @cur: the current node
6102 * @level: the imbrication level for indenting
6103 * @format: is formatting allowed
6104 * @encoding: an optional encoding string
6105 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006106 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006107 */
6108void
6109xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6110 int level, int format, const char *encoding) {
6111 int i;
6112 xmlNodePtr tmp;
6113
6114 if (cur == NULL) {
6115#ifdef DEBUG_TREE
6116 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006117 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006118#endif
6119 return;
6120 }
6121 if (cur->type == XML_XINCLUDE_START)
6122 return;
6123 if (cur->type == XML_XINCLUDE_END)
6124 return;
6125 if (cur->type == XML_DTD_NODE) {
6126 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6127 return;
6128 }
6129 if (cur->type == XML_ELEMENT_DECL) {
6130 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6131 return;
6132 }
6133 if (cur->type == XML_ATTRIBUTE_DECL) {
6134 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6135 return;
6136 }
6137 if (cur->type == XML_ENTITY_DECL) {
6138 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6139 return;
6140 }
6141 if (cur->type == XML_TEXT_NODE) {
6142 if (cur->content != NULL) {
6143 if ((cur->name == xmlStringText) ||
6144 (cur->name != xmlStringTextNoenc)) {
6145 xmlChar *buffer;
6146
6147#ifndef XML_USE_BUFFER_CONTENT
6148 if (encoding == NULL)
6149 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6150 else
6151 buffer = xmlEncodeSpecialChars(doc, cur->content);
6152#else
6153 if (encoding == NULL)
6154 buffer = xmlEncodeEntitiesReentrant(doc,
6155 xmlBufferContent(cur->content));
6156 else
6157 buffer = xmlEncodeSpecialChars(doc,
6158 xmlBufferContent(cur->content));
6159#endif
6160 if (buffer != NULL) {
6161 xmlOutputBufferWriteString(buf, (const char *)buffer);
6162 xmlFree(buffer);
6163 }
6164 } else {
6165 /*
6166 * Disable escaping, needed for XSLT
6167 */
6168#ifndef XML_USE_BUFFER_CONTENT
6169 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6170#else
6171 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6172#endif
6173 }
6174 }
6175
6176 return;
6177 }
6178 if (cur->type == XML_PI_NODE) {
6179 if (cur->content != NULL) {
6180 xmlOutputBufferWriteString(buf, "<?");
6181 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6182 if (cur->content != NULL) {
6183 xmlOutputBufferWriteString(buf, " ");
6184#ifndef XML_USE_BUFFER_CONTENT
6185 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6186#else
6187 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6188#endif
6189 }
6190 xmlOutputBufferWriteString(buf, "?>");
6191 } else {
6192 xmlOutputBufferWriteString(buf, "<?");
6193 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6194 xmlOutputBufferWriteString(buf, "?>");
6195 }
6196 return;
6197 }
6198 if (cur->type == XML_COMMENT_NODE) {
6199 if (cur->content != NULL) {
6200 xmlOutputBufferWriteString(buf, "<!--");
6201#ifndef XML_USE_BUFFER_CONTENT
6202 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6203#else
6204 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6205#endif
6206 xmlOutputBufferWriteString(buf, "-->");
6207 }
6208 return;
6209 }
6210 if (cur->type == XML_ENTITY_REF_NODE) {
6211 xmlOutputBufferWriteString(buf, "&");
6212 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6213 xmlOutputBufferWriteString(buf, ";");
6214 return;
6215 }
6216 if (cur->type == XML_CDATA_SECTION_NODE) {
6217 xmlOutputBufferWriteString(buf, "<![CDATA[");
6218 if (cur->content != NULL)
6219#ifndef XML_USE_BUFFER_CONTENT
6220 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6221#else
6222 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6223#endif
6224 xmlOutputBufferWriteString(buf, "]]>");
6225 return;
6226 }
6227
6228 if (format == 1) {
6229 tmp = cur->children;
6230 while (tmp != NULL) {
6231 if ((tmp->type == XML_TEXT_NODE) ||
6232 (tmp->type == XML_ENTITY_REF_NODE)) {
6233 format = 0;
6234 break;
6235 }
6236 tmp = tmp->next;
6237 }
6238 }
6239 xmlOutputBufferWriteString(buf, "<");
6240 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6241 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6242 xmlOutputBufferWriteString(buf, ":");
6243 }
6244
6245 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6246 if (cur->nsDef)
6247 xmlNsListDumpOutput(buf, cur->nsDef);
6248 if (cur->properties != NULL)
6249 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6250
Daniel Veillard7db37732001-07-12 01:20:08 +00006251 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6252 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006253 xmlOutputBufferWriteString(buf, "/>");
6254 return;
6255 }
6256 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006257 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006258 xmlChar *buffer;
6259
6260#ifndef XML_USE_BUFFER_CONTENT
6261 if (encoding == NULL)
6262 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6263 else
6264 buffer = xmlEncodeSpecialChars(doc, cur->content);
6265#else
6266 if (encoding == NULL)
6267 buffer = xmlEncodeEntitiesReentrant(doc,
6268 xmlBufferContent(cur->content));
6269 else
6270 buffer = xmlEncodeSpecialChars(doc,
6271 xmlBufferContent(cur->content));
6272#endif
6273 if (buffer != NULL) {
6274 xmlOutputBufferWriteString(buf, (const char *)buffer);
6275 xmlFree(buffer);
6276 }
6277 }
6278 if (cur->children != NULL) {
6279 if (format) xmlOutputBufferWriteString(buf, "\n");
6280 xmlNodeListDumpOutput(buf, doc, cur->children,
6281 (level >= 0?level+1:-1), format, encoding);
6282 if ((xmlIndentTreeOutput) && (format))
6283 for (i = 0;i < level;i++)
6284 xmlOutputBufferWriteString(buf, " ");
6285 }
6286 xmlOutputBufferWriteString(buf, "</");
6287 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6288 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6289 xmlOutputBufferWriteString(buf, ":");
6290 }
6291
6292 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6293 xmlOutputBufferWriteString(buf, ">");
6294}
6295
6296/**
6297 * xmlDocContentDumpOutput:
6298 * @buf: the XML buffer output
6299 * @cur: the document
6300 * @encoding: an optional encoding string
6301 * @format: should formatting spaces been added
6302 *
6303 * Dump an XML document.
6304 */
6305static void
6306xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6307 const char *encoding, int format) {
6308 xmlOutputBufferWriteString(buf, "<?xml version=");
6309 if (cur->version != NULL)
6310 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6311 else
6312 xmlOutputBufferWriteString(buf, "\"1.0\"");
6313 if (encoding == NULL) {
6314 if (cur->encoding != NULL)
6315 encoding = (const char *) cur->encoding;
6316 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6317 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6318 }
6319 if (encoding != NULL) {
6320 xmlOutputBufferWriteString(buf, " encoding=");
6321 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6322 }
6323 switch (cur->standalone) {
6324 case 0:
6325 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6326 break;
6327 case 1:
6328 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6329 break;
6330 }
6331 xmlOutputBufferWriteString(buf, "?>\n");
6332 if (cur->children != NULL) {
6333 xmlNodePtr child = cur->children;
6334
6335 while (child != NULL) {
6336 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6337 xmlOutputBufferWriteString(buf, "\n");
6338 child = child->next;
6339 }
6340 }
6341}
6342
6343/************************************************************************
6344 * *
6345 * Saving functions front-ends *
6346 * *
6347 ************************************************************************/
6348
6349/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006350 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006351 * @out_doc: Document to generate XML text from
6352 * @doc_txt_ptr: Memory pointer for allocated XML text
6353 * @doc_txt_len: Length of the generated XML text
6354 * @txt_encoding: Character encoding to use when generating XML text
6355 * @format: should formatting spaces been added
6356 *
6357 * Dump the current DOM tree into memory using the character encoding specified
6358 * by the caller. Note it is up to the caller of this function to free the
6359 * allocated memory.
6360 */
6361
6362void
6363xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006364 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006365 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006366 int dummy = 0;
6367
6368 xmlCharEncoding doc_charset;
6369 xmlOutputBufferPtr out_buff = NULL;
6370 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6371
6372 if (doc_txt_len == NULL) {
6373 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6374 }
6375
6376 if (doc_txt_ptr == NULL) {
6377 *doc_txt_len = 0;
6378 xmlGenericError(xmlGenericErrorContext,
6379 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6380 return;
6381 }
6382
6383 *doc_txt_ptr = NULL;
6384 *doc_txt_len = 0;
6385
6386 if (out_doc == NULL) {
6387 /* No document, no output */
6388 xmlGenericError(xmlGenericErrorContext,
6389 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6390 return;
6391 }
6392
6393 /*
6394 * Validate the encoding value, if provided.
6395 * This logic is copied from xmlSaveFileEnc.
6396 */
6397
6398 if (txt_encoding == NULL)
6399 txt_encoding = (const char *) out_doc->encoding;
6400 if (txt_encoding != NULL) {
6401 doc_charset = xmlParseCharEncoding(txt_encoding);
6402
6403 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6404 xmlGenericError(xmlGenericErrorContext,
6405 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6406 return;
6407
6408 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6409 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6410 if ( conv_hdlr == NULL ) {
6411 xmlGenericError(xmlGenericErrorContext,
6412 "%s: %s %s '%s'\n",
6413 "xmlDocDumpFormatMemoryEnc",
6414 "Failed to identify encoding handler for",
6415 "character set",
6416 txt_encoding);
6417 return;
6418 }
6419 }
6420 }
6421
6422 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6423 xmlGenericError(xmlGenericErrorContext,
6424 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6425 return;
6426 }
6427
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006428 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006429 xmlOutputBufferFlush(out_buff);
6430 if (out_buff->conv != NULL) {
6431 *doc_txt_len = out_buff->conv->use;
6432 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6433 } else {
6434 *doc_txt_len = out_buff->buffer->use;
6435 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6436 }
6437 (void)xmlOutputBufferClose(out_buff);
6438
6439 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6440 *doc_txt_len = 0;
6441 xmlGenericError(xmlGenericErrorContext,
6442 "xmlDocDumpFormatMemoryEnc: %s\n",
6443 "Failed to allocate memory for document text representation.");
6444 }
6445
6446 return;
6447}
6448
6449/**
6450 * xmlDocDumpMemory:
6451 * @cur: the document
6452 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006453 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006454 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006455 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006456 * It's up to the caller to free the memory.
6457 */
6458void
6459xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6460 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6461}
6462
6463/**
6464 * xmlDocDumpFormatMemory:
6465 * @cur: the document
6466 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006467 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006468 * @format: should formatting spaces been added
6469 *
6470 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006471 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006472 * It's up to the caller to free the memory.
6473 */
6474void
6475xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6476 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6477}
6478
6479/**
6480 * xmlDocDumpMemoryEnc:
6481 * @out_doc: Document to generate XML text from
6482 * @doc_txt_ptr: Memory pointer for allocated XML text
6483 * @doc_txt_len: Length of the generated XML text
6484 * @txt_encoding: Character encoding to use when generating XML text
6485 *
6486 * Dump the current DOM tree into memory using the character encoding specified
6487 * by the caller. Note it is up to the caller of this function to free the
6488 * allocated memory.
6489 */
6490
6491void
6492xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6493 int * doc_txt_len, const char * txt_encoding) {
6494 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006495 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006496}
6497
6498/**
6499 * xmlGetDocCompressMode:
6500 * @doc: the document
6501 *
6502 * get the compression ratio for a document, ZLIB based
6503 * Returns 0 (uncompressed) to 9 (max compression)
6504 */
6505int
6506xmlGetDocCompressMode (xmlDocPtr doc) {
6507 if (doc == NULL) return(-1);
6508 return(doc->compression);
6509}
6510
6511/**
6512 * xmlSetDocCompressMode:
6513 * @doc: the document
6514 * @mode: the compression ratio
6515 *
6516 * set the compression ratio for a document, ZLIB based
6517 * Correct values: 0 (uncompressed) to 9 (max compression)
6518 */
6519void
6520xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6521 if (doc == NULL) return;
6522 if (mode < 0) doc->compression = 0;
6523 else if (mode > 9) doc->compression = 9;
6524 else doc->compression = mode;
6525}
6526
6527/**
6528 * xmlGetCompressMode:
6529 *
6530 * get the default compression mode used, ZLIB based.
6531 * Returns 0 (uncompressed) to 9 (max compression)
6532 */
6533int
6534 xmlGetCompressMode(void) {
6535 return(xmlCompressMode);
6536}
6537
6538/**
6539 * xmlSetCompressMode:
6540 * @mode: the compression ratio
6541 *
6542 * set the default compression mode used, ZLIB based
6543 * Correct values: 0 (uncompressed) to 9 (max compression)
6544 */
6545void
6546xmlSetCompressMode(int mode) {
6547 if (mode < 0) xmlCompressMode = 0;
6548 else if (mode > 9) xmlCompressMode = 9;
6549 else xmlCompressMode = mode;
6550}
6551
6552/**
6553 * xmlDocDump:
6554 * @f: the FILE*
6555 * @cur: the document
6556 *
6557 * Dump an XML document to an open FILE.
6558 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006559 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006560 */
6561int
6562xmlDocDump(FILE *f, xmlDocPtr cur) {
6563 xmlOutputBufferPtr buf;
6564 const char * encoding;
6565 xmlCharEncodingHandlerPtr handler = NULL;
6566 int ret;
6567
6568 if (cur == NULL) {
6569#ifdef DEBUG_TREE
6570 xmlGenericError(xmlGenericErrorContext,
6571 "xmlDocDump : document == NULL\n");
6572#endif
6573 return(-1);
6574 }
6575 encoding = (const char *) cur->encoding;
6576
6577 if (encoding != NULL) {
6578 xmlCharEncoding enc;
6579
6580 enc = xmlParseCharEncoding(encoding);
6581
6582 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6583 xmlGenericError(xmlGenericErrorContext,
6584 "xmlDocDump: document not in UTF8\n");
6585 return(-1);
6586 }
6587 if (enc != XML_CHAR_ENCODING_UTF8) {
6588 handler = xmlFindCharEncodingHandler(encoding);
6589 if (handler == NULL) {
6590 xmlFree((char *) cur->encoding);
6591 cur->encoding = NULL;
6592 }
6593 }
6594 }
6595 buf = xmlOutputBufferCreateFile(f, handler);
6596 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006597 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006598
6599 ret = xmlOutputBufferClose(buf);
6600 return(ret);
6601}
6602
6603/**
6604 * xmlSaveFileTo:
6605 * @buf: an output I/O buffer
6606 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006607 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006608 *
6609 * Dump an XML document to an I/O buffer.
6610 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006611 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006612 */
6613int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006614xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006615 int ret;
6616
6617 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006618 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006619 ret = xmlOutputBufferClose(buf);
6620 return(ret);
6621}
6622
6623/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006624 * xmlSaveFormatFileTo:
6625 * @buf: an output I/O buffer
6626 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006627 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006628 * @format: should formatting spaces been added
6629 *
6630 * Dump an XML document to an I/O buffer.
6631 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006632 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006633 */
6634int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006635xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006636 int ret;
6637
6638 if (buf == NULL) return(0);
6639 xmlDocContentDumpOutput(buf, cur, encoding, format);
6640 ret = xmlOutputBufferClose(buf);
6641 return(ret);
6642}
6643
6644/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006645 * xmlSaveFormatFileEnc
6646 * @filename: the filename or URL to output
6647 * @cur: the document being saved
6648 * @encoding: the name of the encoding to use or NULL.
6649 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006650 *
6651 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006652 */
6653int
Daniel Veillardf012a642001-07-23 19:10:52 +00006654xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6655 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006656 xmlOutputBufferPtr buf;
6657 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006658 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006659 int ret;
6660
Daniel Veillardfb25a512002-01-13 20:32:08 +00006661 if (encoding == NULL)
6662 encoding = (const char *) cur->encoding;
6663
Owen Taylor3473f882001-02-23 17:55:21 +00006664 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006665
6666 enc = xmlParseCharEncoding(encoding);
6667 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6668 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006669 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006670 return(-1);
6671 }
6672 if (enc != XML_CHAR_ENCODING_UTF8) {
6673 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006674 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006675 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006676 }
6677 }
6678
Daniel Veillardf012a642001-07-23 19:10:52 +00006679#ifdef HAVE_ZLIB_H
6680 if (cur->compression < 0) cur->compression = xmlCompressMode;
6681#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006682 /*
6683 * save the content to a temp buffer.
6684 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006685 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006686 if (buf == NULL) return(-1);
6687
Daniel Veillardf012a642001-07-23 19:10:52 +00006688 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006689
6690 ret = xmlOutputBufferClose(buf);
6691 return(ret);
6692}
6693
Daniel Veillardf012a642001-07-23 19:10:52 +00006694
6695/**
6696 * xmlSaveFileEnc:
6697 * @filename: the filename (or URL)
6698 * @cur: the document
6699 * @encoding: the name of an encoding (or NULL)
6700 *
6701 * Dump an XML document, converting it to the given encoding
6702 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006703 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006704 */
6705int
6706xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6707 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6708}
6709
Owen Taylor3473f882001-02-23 17:55:21 +00006710/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006711 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006712 * @filename: the filename (or URL)
6713 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006714 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006715 *
6716 * Dump an XML document to a file. Will use compression if
6717 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006718 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006719 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006720 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006721 */
6722int
Daniel Veillard67fee942001-04-26 18:59:03 +00006723xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006724 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006725}
6726
Daniel Veillard67fee942001-04-26 18:59:03 +00006727/**
6728 * xmlSaveFile:
6729 * @filename: the filename (or URL)
6730 * @cur: the document
6731 *
6732 * Dump an XML document to a file. Will use compression if
6733 * compiled in and enabled. If @filename is "-" the stdout file is
6734 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006735 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006736 */
6737int
6738xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006739 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006740}
6741