blob: 66e8acd89a3678f64a48bba0973c4c6969221217 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
12 */
13
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000037
Daniel Veillard56a4cb82001-03-24 17:00:36 +000038xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
39
40/************************************************************************
41 * *
42 * A few static variables and macros *
43 * *
44 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000045/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000046const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000047/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000048const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000049 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
52
Owen Taylor3473f882001-02-23 17:55:21 +000053static int xmlCompressMode = 0;
54static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000055
Owen Taylor3473f882001-02-23 17:55:21 +000056#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
57 xmlNodePtr ulccur = (n)->children; \
58 if (ulccur == NULL) { \
59 (n)->last = NULL; \
60 } else { \
61 while (ulccur->next != NULL) { \
62 ulccur->parent = (n); \
63 ulccur = ulccur->next; \
64 } \
65 ulccur->parent = (n); \
66 (n)->last = ulccur; \
67}}
68
69/* #define DEBUG_BUFFER */
70/* #define DEBUG_TREE */
71
72/************************************************************************
73 * *
74 * Allocation and deallocation of basic structures *
75 * *
76 ************************************************************************/
77
78/**
79 * xmlSetBufferAllocationScheme:
80 * @scheme: allocation method to use
81 *
82 * Set the buffer allocation method. Types are
83 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
84 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
85 * improves performance
86 */
87void
88xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
89 xmlBufferAllocScheme = scheme;
90}
91
92/**
93 * xmlGetBufferAllocationScheme:
94 *
95 * Types are
96 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
97 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
98 * improves performance
99 *
100 * Returns the current allocation scheme
101 */
102xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000103xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000104 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000105}
106
107/**
108 * xmlNewNs:
109 * @node: the element carrying the namespace
110 * @href: the URI associated
111 * @prefix: the prefix for the namespace
112 *
113 * Creation of a new Namespace. This function will refuse to create
114 * a namespace with a similar prefix than an existing one present on this
115 * node.
116 * We use href==NULL in the case of an element creation where the namespace
117 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000118 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000119 */
120xmlNsPtr
121xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
122 xmlNsPtr cur;
123
124 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
125 return(NULL);
126
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000127 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
128 return(NULL);
129
Owen Taylor3473f882001-02-23 17:55:21 +0000130 /*
131 * Allocate a new Namespace and fill the fields.
132 */
133 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
134 if (cur == NULL) {
135 xmlGenericError(xmlGenericErrorContext,
136 "xmlNewNs : malloc failed\n");
137 return(NULL);
138 }
139 memset(cur, 0, sizeof(xmlNs));
140 cur->type = XML_LOCAL_NAMESPACE;
141
142 if (href != NULL)
143 cur->href = xmlStrdup(href);
144 if (prefix != NULL)
145 cur->prefix = xmlStrdup(prefix);
146
147 /*
148 * Add it at the end to preserve parsing order ...
149 * and checks for existing use of the prefix
150 */
151 if (node != NULL) {
152 if (node->nsDef == NULL) {
153 node->nsDef = cur;
154 } else {
155 xmlNsPtr prev = node->nsDef;
156
157 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
158 (xmlStrEqual(prev->prefix, cur->prefix))) {
159 xmlFreeNs(cur);
160 return(NULL);
161 }
162 while (prev->next != NULL) {
163 prev = prev->next;
164 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
165 (xmlStrEqual(prev->prefix, cur->prefix))) {
166 xmlFreeNs(cur);
167 return(NULL);
168 }
169 }
170 prev->next = cur;
171 }
172 }
173 return(cur);
174}
175
176/**
177 * xmlSetNs:
178 * @node: a node in the document
179 * @ns: a namespace pointer
180 *
181 * Associate a namespace to a node, a posteriori.
182 */
183void
184xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
185 if (node == NULL) {
186#ifdef DEBUG_TREE
187 xmlGenericError(xmlGenericErrorContext,
188 "xmlSetNs: node == NULL\n");
189#endif
190 return;
191 }
192 node->ns = ns;
193}
194
195/**
196 * xmlFreeNs:
197 * @cur: the namespace pointer
198 *
199 * Free up the structures associated to a namespace
200 */
201void
202xmlFreeNs(xmlNsPtr cur) {
203 if (cur == NULL) {
204#ifdef DEBUG_TREE
205 xmlGenericError(xmlGenericErrorContext,
206 "xmlFreeNs : ns == NULL\n");
207#endif
208 return;
209 }
210 if (cur->href != NULL) xmlFree((char *) cur->href);
211 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000212 xmlFree(cur);
213}
214
215/**
216 * xmlFreeNsList:
217 * @cur: the first namespace pointer
218 *
219 * Free up all the structures associated to the chained namespaces.
220 */
221void
222xmlFreeNsList(xmlNsPtr cur) {
223 xmlNsPtr next;
224 if (cur == NULL) {
225#ifdef DEBUG_TREE
226 xmlGenericError(xmlGenericErrorContext,
227 "xmlFreeNsList : ns == NULL\n");
228#endif
229 return;
230 }
231 while (cur != NULL) {
232 next = cur->next;
233 xmlFreeNs(cur);
234 cur = next;
235 }
236}
237
238/**
239 * xmlNewDtd:
240 * @doc: the document pointer
241 * @name: the DTD name
242 * @ExternalID: the external ID
243 * @SystemID: the system ID
244 *
245 * Creation of a new DTD for the external subset. To create an
246 * internal subset, use xmlCreateIntSubset().
247 *
248 * Returns a pointer to the new DTD structure
249 */
250xmlDtdPtr
251xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
252 const xmlChar *ExternalID, const xmlChar *SystemID) {
253 xmlDtdPtr cur;
254
255 if ((doc != NULL) && (doc->extSubset != NULL)) {
256#ifdef DEBUG_TREE
257 xmlGenericError(xmlGenericErrorContext,
258 "xmlNewDtd(%s): document %s already have a DTD %s\n",
259 /* !!! */ (char *) name, doc->name,
260 /* !!! */ (char *)doc->extSubset->name);
261#endif
262 return(NULL);
263 }
264
265 /*
266 * Allocate a new DTD and fill the fields.
267 */
268 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
269 if (cur == NULL) {
270 xmlGenericError(xmlGenericErrorContext,
271 "xmlNewDtd : malloc failed\n");
272 return(NULL);
273 }
274 memset(cur, 0 , sizeof(xmlDtd));
275 cur->type = XML_DTD_NODE;
276
277 if (name != NULL)
278 cur->name = xmlStrdup(name);
279 if (ExternalID != NULL)
280 cur->ExternalID = xmlStrdup(ExternalID);
281 if (SystemID != NULL)
282 cur->SystemID = xmlStrdup(SystemID);
283 if (doc != NULL)
284 doc->extSubset = cur;
285 cur->doc = doc;
286
287 return(cur);
288}
289
290/**
291 * xmlGetIntSubset:
292 * @doc: the document pointer
293 *
294 * Get the internal subset of a document
295 * Returns a pointer to the DTD structure or NULL if not found
296 */
297
298xmlDtdPtr
299xmlGetIntSubset(xmlDocPtr doc) {
300 xmlNodePtr cur;
301
302 if (doc == NULL)
303 return(NULL);
304 cur = doc->children;
305 while (cur != NULL) {
306 if (cur->type == XML_DTD_NODE)
307 return((xmlDtdPtr) cur);
308 cur = cur->next;
309 }
310 return((xmlDtdPtr) doc->intSubset);
311}
312
313/**
314 * xmlCreateIntSubset:
315 * @doc: the document pointer
316 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000317 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000318 * @SystemID: the system ID
319 *
320 * Create the internal subset of a document
321 * Returns a pointer to the new DTD structure
322 */
323xmlDtdPtr
324xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
325 const xmlChar *ExternalID, const xmlChar *SystemID) {
326 xmlDtdPtr cur;
327
328 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
329#ifdef DEBUG_TREE
330 xmlGenericError(xmlGenericErrorContext,
331
332 "xmlCreateIntSubset(): document %s already have an internal subset\n",
333 doc->name);
334#endif
335 return(NULL);
336 }
337
338 /*
339 * Allocate a new DTD and fill the fields.
340 */
341 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
342 if (cur == NULL) {
343 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000344 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000345 return(NULL);
346 }
347 memset(cur, 0, sizeof(xmlDtd));
348 cur->type = XML_DTD_NODE;
349
350 if (name != NULL)
351 cur->name = xmlStrdup(name);
352 if (ExternalID != NULL)
353 cur->ExternalID = xmlStrdup(ExternalID);
354 if (SystemID != NULL)
355 cur->SystemID = xmlStrdup(SystemID);
356 if (doc != NULL) {
357 doc->intSubset = cur;
358 cur->parent = doc;
359 cur->doc = doc;
360 if (doc->children == NULL) {
361 doc->children = (xmlNodePtr) cur;
362 doc->last = (xmlNodePtr) cur;
363 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000364 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000365 xmlNodePtr prev;
366
Owen Taylor3473f882001-02-23 17:55:21 +0000367 prev = doc->children;
368 prev->prev = (xmlNodePtr) cur;
369 cur->next = prev;
370 doc->children = (xmlNodePtr) cur;
371 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000372 xmlNodePtr next;
373
374 next = doc->children;
375 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
376 next = next->next;
377 if (next == NULL) {
378 cur->prev = doc->last;
379 cur->prev->next = (xmlNodePtr) cur;
380 cur->next = NULL;
381 doc->last = (xmlNodePtr) cur;
382 } else {
383 cur->next = next;
384 cur->prev = next->prev;
385 if (cur->prev == NULL)
386 doc->children = (xmlNodePtr) cur;
387 else
388 cur->prev->next = (xmlNodePtr) cur;
389 next->prev = (xmlNodePtr) cur;
390 }
Owen Taylor3473f882001-02-23 17:55:21 +0000391 }
392 }
393 }
394 return(cur);
395}
396
397/**
398 * xmlFreeDtd:
399 * @cur: the DTD structure to free up
400 *
401 * Free a DTD structure.
402 */
403void
404xmlFreeDtd(xmlDtdPtr cur) {
405 if (cur == NULL) {
406#ifdef DEBUG_TREE
407 xmlGenericError(xmlGenericErrorContext,
408 "xmlFreeDtd : DTD == NULL\n");
409#endif
410 return;
411 }
412 if (cur->children != NULL) {
413 xmlNodePtr next, c = cur->children;
414
415 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000416 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000417 * indexes.
418 */
419 while (c != NULL) {
420 next = c->next;
421 if (c->type == XML_COMMENT_NODE) {
422 xmlUnlinkNode(c);
423 xmlFreeNode(c);
424 }
425 c = next;
426 }
427 }
428 if (cur->name != NULL) xmlFree((char *) cur->name);
429 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
430 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
431 /* TODO !!! */
432 if (cur->notations != NULL)
433 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
434
435 if (cur->elements != NULL)
436 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
437 if (cur->attributes != NULL)
438 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
439 if (cur->entities != NULL)
440 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
441 if (cur->pentities != NULL)
442 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
443
Owen Taylor3473f882001-02-23 17:55:21 +0000444 xmlFree(cur);
445}
446
447/**
448 * xmlNewDoc:
449 * @version: xmlChar string giving the version of XML "1.0"
450 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000451 * Creates a new XML document
452 *
Owen Taylor3473f882001-02-23 17:55:21 +0000453 * Returns a new document
454 */
455xmlDocPtr
456xmlNewDoc(const xmlChar *version) {
457 xmlDocPtr cur;
458
459 if (version == NULL)
460 version = (const xmlChar *) "1.0";
461
462 /*
463 * Allocate a new document and fill the fields.
464 */
465 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
466 if (cur == NULL) {
467 xmlGenericError(xmlGenericErrorContext,
468 "xmlNewDoc : malloc failed\n");
469 return(NULL);
470 }
471 memset(cur, 0, sizeof(xmlDoc));
472 cur->type = XML_DOCUMENT_NODE;
473
474 cur->version = xmlStrdup(version);
475 cur->standalone = -1;
476 cur->compression = -1; /* not initialized */
477 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000478 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000479 return(cur);
480}
481
482/**
483 * xmlFreeDoc:
484 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000485 *
486 * Free up all the structures used by a document, tree included.
487 */
488void
489xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000490 xmlDtdPtr extSubset, intSubset;
491
Owen Taylor3473f882001-02-23 17:55:21 +0000492 if (cur == NULL) {
493#ifdef DEBUG_TREE
494 xmlGenericError(xmlGenericErrorContext,
495 "xmlFreeDoc : document == NULL\n");
496#endif
497 return;
498 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000499 /*
500 * Do this before freeing the children list to avoid ID lookups
501 */
502 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
503 cur->ids = NULL;
504 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
505 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000506 extSubset = cur->extSubset;
507 intSubset = cur->intSubset;
508 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000509 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000510 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000511 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000512 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000513 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000514 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000515 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000516 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000517 }
518
519 if (cur->children != NULL) xmlFreeNodeList(cur->children);
520
Owen Taylor3473f882001-02-23 17:55:21 +0000521 if (cur->version != NULL) xmlFree((char *) cur->version);
522 if (cur->name != NULL) xmlFree((char *) cur->name);
523 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000524 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000525 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000526 xmlFree(cur);
527}
528
529/**
530 * xmlStringLenGetNodeList:
531 * @doc: the document
532 * @value: the value of the text
533 * @len: the length of the string value
534 *
535 * Parse the value string and build the node list associated. Should
536 * produce a flat tree with only TEXTs and ENTITY_REFs.
537 * Returns a pointer to the first child
538 */
539xmlNodePtr
540xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
541 xmlNodePtr ret = NULL, last = NULL;
542 xmlNodePtr node;
543 xmlChar *val;
544 const xmlChar *cur = value;
545 const xmlChar *q;
546 xmlEntityPtr ent;
547
548 if (value == NULL) return(NULL);
549
550 q = cur;
551 while ((*cur != 0) && (cur - value < len)) {
552 if (*cur == '&') {
553 /*
554 * Save the current text.
555 */
556 if (cur != q) {
557 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
558 xmlNodeAddContentLen(last, q, cur - q);
559 } else {
560 node = xmlNewDocTextLen(doc, q, cur - q);
561 if (node == NULL) return(ret);
562 if (last == NULL)
563 last = ret = node;
564 else {
565 last->next = node;
566 node->prev = last;
567 last = node;
568 }
569 }
570 }
571 /*
572 * Read the entity string
573 */
574 cur++;
575 q = cur;
576 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
577 if ((*cur == 0) || (cur - value >= len)) {
578#ifdef DEBUG_TREE
579 xmlGenericError(xmlGenericErrorContext,
580 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
581#endif
582 return(ret);
583 }
584 if (cur != q) {
585 /*
586 * Predefined entities don't generate nodes
587 */
588 val = xmlStrndup(q, cur - q);
589 ent = xmlGetDocEntity(doc, val);
590 if ((ent != NULL) &&
591 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
592 if (last == NULL) {
593 node = xmlNewDocText(doc, ent->content);
594 last = ret = node;
595 } else
596 xmlNodeAddContent(last, ent->content);
597
598 } else {
599 /*
600 * Create a new REFERENCE_REF node
601 */
602 node = xmlNewReference(doc, val);
603 if (node == NULL) {
604 if (val != NULL) xmlFree(val);
605 return(ret);
606 }
607 if (last == NULL)
608 last = ret = node;
609 else {
610 last->next = node;
611 node->prev = last;
612 last = node;
613 }
614 }
615 xmlFree(val);
616 }
617 cur++;
618 q = cur;
619 } else
620 cur++;
621 }
622 if (cur != q) {
623 /*
624 * Handle the last piece of text.
625 */
626 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
627 xmlNodeAddContentLen(last, q, cur - q);
628 } else {
629 node = xmlNewDocTextLen(doc, q, cur - q);
630 if (node == NULL) return(ret);
631 if (last == NULL)
632 last = ret = node;
633 else {
634 last->next = node;
635 node->prev = last;
636 last = node;
637 }
638 }
639 }
640 return(ret);
641}
642
643/**
644 * xmlStringGetNodeList:
645 * @doc: the document
646 * @value: the value of the attribute
647 *
648 * Parse the value string and build the node list associated. Should
649 * produce a flat tree with only TEXTs and ENTITY_REFs.
650 * Returns a pointer to the first child
651 */
652xmlNodePtr
653xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
654 xmlNodePtr ret = NULL, last = NULL;
655 xmlNodePtr node;
656 xmlChar *val;
657 const xmlChar *cur = value;
658 const xmlChar *q;
659 xmlEntityPtr ent;
660
661 if (value == NULL) return(NULL);
662
663 q = cur;
664 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000665 if (cur[0] == '&') {
666 int charval = 0;
667 xmlChar tmp;
668
Owen Taylor3473f882001-02-23 17:55:21 +0000669 /*
670 * Save the current text.
671 */
672 if (cur != q) {
673 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
674 xmlNodeAddContentLen(last, q, cur - q);
675 } else {
676 node = xmlNewDocTextLen(doc, q, cur - q);
677 if (node == NULL) return(ret);
678 if (last == NULL)
679 last = ret = node;
680 else {
681 last->next = node;
682 node->prev = last;
683 last = node;
684 }
685 }
686 }
Owen Taylor3473f882001-02-23 17:55:21 +0000687 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000688 if ((cur[1] == '#') && (cur[2] == 'x')) {
689 cur += 3;
690 tmp = *cur;
691 while (tmp != ';') { /* Non input consuming loop */
692 if ((tmp >= '0') && (tmp <= '9'))
693 charval = charval * 16 + (tmp - '0');
694 else if ((tmp >= 'a') && (tmp <= 'f'))
695 charval = charval * 16 + (tmp - 'a') + 10;
696 else if ((tmp >= 'A') && (tmp <= 'F'))
697 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000698 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000699 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000700 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000701 charval = 0;
702 break;
703 }
704 cur++;
705 tmp = *cur;
706 }
707 if (tmp == ';')
708 cur++;
709 q = cur;
710 } else if (cur[1] == '#') {
711 cur += 2;
712 tmp = *cur;
713 while (tmp != ';') { /* Non input consuming loops */
714 if ((tmp >= '0') && (tmp <= '9'))
715 charval = charval * 10 + (tmp - '0');
716 else {
717 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000718 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000719 charval = 0;
720 break;
721 }
722 cur++;
723 tmp = *cur;
724 }
725 if (tmp == ';')
726 cur++;
727 q = cur;
728 } else {
729 /*
730 * Read the entity string
731 */
732 cur++;
733 q = cur;
734 while ((*cur != 0) && (*cur != ';')) cur++;
735 if (*cur == 0) {
736#ifdef DEBUG_TREE
737 xmlGenericError(xmlGenericErrorContext,
738 "xmlStringGetNodeList: unterminated entity %30s\n", q);
739#endif
740 return(ret);
741 }
742 if (cur != q) {
743 /*
744 * Predefined entities don't generate nodes
745 */
746 val = xmlStrndup(q, cur - q);
747 ent = xmlGetDocEntity(doc, val);
748 if ((ent != NULL) &&
749 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
750 if (last == NULL) {
751 node = xmlNewDocText(doc, ent->content);
752 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000753 } else if (last->type != XML_TEXT_NODE) {
754 node = xmlNewDocText(doc, ent->content);
755 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000756 } else
757 xmlNodeAddContent(last, ent->content);
758
759 } else {
760 /*
761 * Create a new REFERENCE_REF node
762 */
763 node = xmlNewReference(doc, val);
764 if (node == NULL) {
765 if (val != NULL) xmlFree(val);
766 return(ret);
767 }
768 if (last == NULL) {
769 last = ret = node;
770 } else {
771 last = xmlAddNextSibling(last, node);
772 }
773 }
774 xmlFree(val);
775 }
776 cur++;
777 q = cur;
778 }
779 if (charval != 0) {
780 xmlChar buf[10];
781 int len;
782
783 len = xmlCopyCharMultiByte(buf, charval);
784 buf[len] = 0;
785 node = xmlNewDocText(doc, buf);
786 if (node != NULL) {
787 if (last == NULL) {
788 last = ret = node;
789 } else {
790 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000791 }
792 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000793
794 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000795 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000796 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000797 cur++;
798 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000799 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000800 /*
801 * Handle the last piece of text.
802 */
803 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
804 xmlNodeAddContentLen(last, q, cur - q);
805 } else {
806 node = xmlNewDocTextLen(doc, q, cur - q);
807 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000808 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000809 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000810 } else {
811 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000812 }
813 }
814 }
815 return(ret);
816}
817
818/**
819 * xmlNodeListGetString:
820 * @doc: the document
821 * @list: a Node list
822 * @inLine: should we replace entity contents or show their external form
823 *
824 * Returns the string equivalent to the text contained in the Node list
825 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000826 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000827 */
828xmlChar *
829xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
830 xmlNodePtr node = list;
831 xmlChar *ret = NULL;
832 xmlEntityPtr ent;
833
834 if (list == NULL) return(NULL);
835
836 while (node != NULL) {
837 if ((node->type == XML_TEXT_NODE) ||
838 (node->type == XML_CDATA_SECTION_NODE)) {
839 if (inLine) {
840#ifndef XML_USE_BUFFER_CONTENT
841 ret = xmlStrcat(ret, node->content);
842#else
843 ret = xmlStrcat(ret, xmlBufferContent(node->content));
844#endif
845 } else {
846 xmlChar *buffer;
847
848#ifndef XML_USE_BUFFER_CONTENT
849 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
850#else
851 buffer = xmlEncodeEntitiesReentrant(doc,
852 xmlBufferContent(node->content));
853#endif
854 if (buffer != NULL) {
855 ret = xmlStrcat(ret, buffer);
856 xmlFree(buffer);
857 }
858 }
859 } else if (node->type == XML_ENTITY_REF_NODE) {
860 if (inLine) {
861 ent = xmlGetDocEntity(doc, node->name);
862 if (ent != NULL)
863 ret = xmlStrcat(ret, ent->content);
864 else {
865#ifndef XML_USE_BUFFER_CONTENT
866 ret = xmlStrcat(ret, node->content);
867#else
868 ret = xmlStrcat(ret, xmlBufferContent(node->content));
869#endif
870 }
871 } else {
872 xmlChar buf[2];
873 buf[0] = '&'; buf[1] = 0;
874 ret = xmlStrncat(ret, buf, 1);
875 ret = xmlStrcat(ret, node->name);
876 buf[0] = ';'; buf[1] = 0;
877 ret = xmlStrncat(ret, buf, 1);
878 }
879 }
880#if 0
881 else {
882 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000883 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000884 node->type);
885 }
886#endif
887 node = node->next;
888 }
889 return(ret);
890}
891
892/**
893 * xmlNodeListGetRawString:
894 * @doc: the document
895 * @list: a Node list
896 * @inLine: should we replace entity contents or show their external form
897 *
898 * Returns the string equivalent to the text contained in the Node list
899 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
900 * this function doesn't do any character encoding handling.
901 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000902 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000903 */
904xmlChar *
905xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
906 xmlNodePtr node = list;
907 xmlChar *ret = NULL;
908 xmlEntityPtr ent;
909
910 if (list == NULL) return(NULL);
911
912 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000913 if ((node->type == XML_TEXT_NODE) ||
914 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000915 if (inLine) {
916#ifndef XML_USE_BUFFER_CONTENT
917 ret = xmlStrcat(ret, node->content);
918#else
919 ret = xmlStrcat(ret, xmlBufferContent(node->content));
920#endif
921 } else {
922 xmlChar *buffer;
923
924#ifndef XML_USE_BUFFER_CONTENT
925 buffer = xmlEncodeSpecialChars(doc, node->content);
926#else
927 buffer = xmlEncodeSpecialChars(doc,
928 xmlBufferContent(node->content));
929#endif
930 if (buffer != NULL) {
931 ret = xmlStrcat(ret, buffer);
932 xmlFree(buffer);
933 }
934 }
935 } else if (node->type == XML_ENTITY_REF_NODE) {
936 if (inLine) {
937 ent = xmlGetDocEntity(doc, node->name);
938 if (ent != NULL)
939 ret = xmlStrcat(ret, ent->content);
940 else {
941#ifndef XML_USE_BUFFER_CONTENT
942 ret = xmlStrcat(ret, node->content);
943#else
944 ret = xmlStrcat(ret, xmlBufferContent(node->content));
945#endif
946 }
947 } else {
948 xmlChar buf[2];
949 buf[0] = '&'; buf[1] = 0;
950 ret = xmlStrncat(ret, buf, 1);
951 ret = xmlStrcat(ret, node->name);
952 buf[0] = ';'; buf[1] = 0;
953 ret = xmlStrncat(ret, buf, 1);
954 }
955 }
956#if 0
957 else {
958 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000959 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000960 node->type);
961 }
962#endif
963 node = node->next;
964 }
965 return(ret);
966}
967
968/**
969 * xmlNewProp:
970 * @node: the holding node
971 * @name: the name of the attribute
972 * @value: the value of the attribute
973 *
974 * Create a new property carried by a node.
975 * Returns a pointer to the attribute
976 */
977xmlAttrPtr
978xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
979 xmlAttrPtr cur;
980 xmlDocPtr doc = NULL;
981
982 if (name == NULL) {
983#ifdef DEBUG_TREE
984 xmlGenericError(xmlGenericErrorContext,
985 "xmlNewProp : name == NULL\n");
986#endif
987 return(NULL);
988 }
989
990 /*
991 * Allocate a new property and fill the fields.
992 */
993 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
994 if (cur == NULL) {
995 xmlGenericError(xmlGenericErrorContext,
996 "xmlNewProp : malloc failed\n");
997 return(NULL);
998 }
999 memset(cur, 0, sizeof(xmlAttr));
1000 cur->type = XML_ATTRIBUTE_NODE;
1001
1002 cur->parent = node;
1003 if (node != NULL) {
1004 doc = node->doc;
1005 cur->doc = doc;
1006 }
1007 cur->name = xmlStrdup(name);
1008 if (value != NULL) {
1009 xmlChar *buffer;
1010 xmlNodePtr tmp;
1011
1012 buffer = xmlEncodeEntitiesReentrant(doc, value);
1013 cur->children = xmlStringGetNodeList(doc, buffer);
1014 cur->last = NULL;
1015 tmp = cur->children;
1016 while (tmp != NULL) {
1017 tmp->parent = (xmlNodePtr) cur;
1018 tmp->doc = doc;
1019 if (tmp->next == NULL)
1020 cur->last = tmp;
1021 tmp = tmp->next;
1022 }
1023 xmlFree(buffer);
1024 }
1025
1026 /*
1027 * Add it at the end to preserve parsing order ...
1028 */
1029 if (node != NULL) {
1030 if (node->properties == NULL) {
1031 node->properties = cur;
1032 } else {
1033 xmlAttrPtr prev = node->properties;
1034
1035 while (prev->next != NULL) prev = prev->next;
1036 prev->next = cur;
1037 cur->prev = prev;
1038 }
1039 }
1040 return(cur);
1041}
1042
1043/**
1044 * xmlNewNsProp:
1045 * @node: the holding node
1046 * @ns: the namespace
1047 * @name: the name of the attribute
1048 * @value: the value of the attribute
1049 *
1050 * Create a new property tagged with a namespace and carried by a node.
1051 * Returns a pointer to the attribute
1052 */
1053xmlAttrPtr
1054xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1055 const xmlChar *value) {
1056 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001057 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001058
1059 if (name == NULL) {
1060#ifdef DEBUG_TREE
1061 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001062 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001063#endif
1064 return(NULL);
1065 }
1066
1067 /*
1068 * Allocate a new property and fill the fields.
1069 */
1070 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1071 if (cur == NULL) {
1072 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001073 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001074 return(NULL);
1075 }
1076 memset(cur, 0, sizeof(xmlAttr));
1077 cur->type = XML_ATTRIBUTE_NODE;
1078
1079 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001080 if (node != NULL) {
1081 doc = node->doc;
1082 cur->doc = doc;
1083 }
Owen Taylor3473f882001-02-23 17:55:21 +00001084 cur->ns = ns;
1085 cur->name = xmlStrdup(name);
1086 if (value != NULL) {
1087 xmlChar *buffer;
1088 xmlNodePtr tmp;
1089
Daniel Veillarda682b212001-06-07 19:59:42 +00001090 buffer = xmlEncodeEntitiesReentrant(doc, value);
1091 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001092 cur->last = NULL;
1093 tmp = cur->children;
1094 while (tmp != NULL) {
1095 tmp->parent = (xmlNodePtr) cur;
1096 if (tmp->next == NULL)
1097 cur->last = tmp;
1098 tmp = tmp->next;
1099 }
1100 xmlFree(buffer);
1101 }
1102
1103 /*
1104 * Add it at the end to preserve parsing order ...
1105 */
1106 if (node != NULL) {
1107 if (node->properties == NULL) {
1108 node->properties = cur;
1109 } else {
1110 xmlAttrPtr prev = node->properties;
1111
1112 while (prev->next != NULL) prev = prev->next;
1113 prev->next = cur;
1114 cur->prev = prev;
1115 }
1116 }
1117 return(cur);
1118}
1119
1120/**
1121 * xmlNewDocProp:
1122 * @doc: the document
1123 * @name: the name of the attribute
1124 * @value: the value of the attribute
1125 *
1126 * Create a new property carried by a document.
1127 * Returns a pointer to the attribute
1128 */
1129xmlAttrPtr
1130xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1131 xmlAttrPtr cur;
1132
1133 if (name == NULL) {
1134#ifdef DEBUG_TREE
1135 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001136 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001137#endif
1138 return(NULL);
1139 }
1140
1141 /*
1142 * Allocate a new property and fill the fields.
1143 */
1144 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1145 if (cur == NULL) {
1146 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001147 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001148 return(NULL);
1149 }
1150 memset(cur, 0, sizeof(xmlAttr));
1151 cur->type = XML_ATTRIBUTE_NODE;
1152
1153 cur->name = xmlStrdup(name);
1154 cur->doc = doc;
1155 if (value != NULL) {
1156 xmlNodePtr tmp;
1157
1158 cur->children = xmlStringGetNodeList(doc, value);
1159 cur->last = NULL;
1160
1161 tmp = cur->children;
1162 while (tmp != NULL) {
1163 tmp->parent = (xmlNodePtr) cur;
1164 if (tmp->next == NULL)
1165 cur->last = tmp;
1166 tmp = tmp->next;
1167 }
1168 }
1169 return(cur);
1170}
1171
1172/**
1173 * xmlFreePropList:
1174 * @cur: the first property in the list
1175 *
1176 * Free a property and all its siblings, all the children are freed too.
1177 */
1178void
1179xmlFreePropList(xmlAttrPtr cur) {
1180 xmlAttrPtr next;
1181 if (cur == NULL) {
1182#ifdef DEBUG_TREE
1183 xmlGenericError(xmlGenericErrorContext,
1184 "xmlFreePropList : property == NULL\n");
1185#endif
1186 return;
1187 }
1188 while (cur != NULL) {
1189 next = cur->next;
1190 xmlFreeProp(cur);
1191 cur = next;
1192 }
1193}
1194
1195/**
1196 * xmlFreeProp:
1197 * @cur: an attribute
1198 *
1199 * Free one attribute, all the content is freed too
1200 */
1201void
1202xmlFreeProp(xmlAttrPtr cur) {
1203 if (cur == NULL) {
1204#ifdef DEBUG_TREE
1205 xmlGenericError(xmlGenericErrorContext,
1206 "xmlFreeProp : property == NULL\n");
1207#endif
1208 return;
1209 }
1210 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001211 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1212 ((cur->parent->doc->intSubset != NULL) ||
1213 (cur->parent->doc->extSubset != NULL))) {
1214 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1215 xmlRemoveID(cur->parent->doc, cur);
1216 }
Owen Taylor3473f882001-02-23 17:55:21 +00001217 if (cur->name != NULL) xmlFree((char *) cur->name);
1218 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001219 xmlFree(cur);
1220}
1221
1222/**
1223 * xmlRemoveProp:
1224 * @cur: an attribute
1225 *
1226 * Unlink and free one attribute, all the content is freed too
1227 * Note this doesn't work for namespace definition attributes
1228 *
1229 * Returns 0 if success and -1 in case of error.
1230 */
1231int
1232xmlRemoveProp(xmlAttrPtr cur) {
1233 xmlAttrPtr tmp;
1234 if (cur == NULL) {
1235#ifdef DEBUG_TREE
1236 xmlGenericError(xmlGenericErrorContext,
1237 "xmlRemoveProp : cur == NULL\n");
1238#endif
1239 return(-1);
1240 }
1241 if (cur->parent == NULL) {
1242#ifdef DEBUG_TREE
1243 xmlGenericError(xmlGenericErrorContext,
1244 "xmlRemoveProp : cur->parent == NULL\n");
1245#endif
1246 return(-1);
1247 }
1248 tmp = cur->parent->properties;
1249 if (tmp == cur) {
1250 cur->parent->properties = cur->next;
1251 xmlFreeProp(cur);
1252 return(0);
1253 }
1254 while (tmp != NULL) {
1255 if (tmp->next == cur) {
1256 tmp->next = cur->next;
1257 if (tmp->next != NULL)
1258 tmp->next->prev = tmp;
1259 xmlFreeProp(cur);
1260 return(0);
1261 }
1262 tmp = tmp->next;
1263 }
1264#ifdef DEBUG_TREE
1265 xmlGenericError(xmlGenericErrorContext,
1266 "xmlRemoveProp : attribute not owned by its node\n");
1267#endif
1268 return(-1);
1269}
1270
1271/**
1272 * xmlNewPI:
1273 * @name: the processing instruction name
1274 * @content: the PI content
1275 *
1276 * Creation of a processing instruction element.
1277 * Returns a pointer to the new node object.
1278 */
1279xmlNodePtr
1280xmlNewPI(const xmlChar *name, const xmlChar *content) {
1281 xmlNodePtr cur;
1282
1283 if (name == NULL) {
1284#ifdef DEBUG_TREE
1285 xmlGenericError(xmlGenericErrorContext,
1286 "xmlNewPI : name == NULL\n");
1287#endif
1288 return(NULL);
1289 }
1290
1291 /*
1292 * Allocate a new node and fill the fields.
1293 */
1294 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1295 if (cur == NULL) {
1296 xmlGenericError(xmlGenericErrorContext,
1297 "xmlNewPI : malloc failed\n");
1298 return(NULL);
1299 }
1300 memset(cur, 0, sizeof(xmlNode));
1301 cur->type = XML_PI_NODE;
1302
1303 cur->name = xmlStrdup(name);
1304 if (content != NULL) {
1305#ifndef XML_USE_BUFFER_CONTENT
1306 cur->content = xmlStrdup(content);
1307#else
1308 cur->content = xmlBufferCreateSize(0);
1309 xmlBufferSetAllocationScheme(cur->content,
1310 xmlGetBufferAllocationScheme());
1311 xmlBufferAdd(cur->content, content, -1);
1312#endif
1313 }
1314 return(cur);
1315}
1316
1317/**
1318 * xmlNewNode:
1319 * @ns: namespace if any
1320 * @name: the node name
1321 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001322 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001323 *
1324 * Returns a pointer to the new node object.
1325 */
1326xmlNodePtr
1327xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1328 xmlNodePtr cur;
1329
1330 if (name == NULL) {
1331#ifdef DEBUG_TREE
1332 xmlGenericError(xmlGenericErrorContext,
1333 "xmlNewNode : name == NULL\n");
1334#endif
1335 return(NULL);
1336 }
1337
1338 /*
1339 * Allocate a new node and fill the fields.
1340 */
1341 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1342 if (cur == NULL) {
1343 xmlGenericError(xmlGenericErrorContext,
1344 "xmlNewNode : malloc failed\n");
1345 return(NULL);
1346 }
1347 memset(cur, 0, sizeof(xmlNode));
1348 cur->type = XML_ELEMENT_NODE;
1349
1350 cur->name = xmlStrdup(name);
1351 cur->ns = ns;
1352 return(cur);
1353}
1354
1355/**
1356 * xmlNewDocNode:
1357 * @doc: the document
1358 * @ns: namespace if any
1359 * @name: the node name
1360 * @content: the XML text content if any
1361 *
1362 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001363 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001364 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1365 * references, but XML special chars need to be escaped first by using
1366 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1367 * need entities support.
1368 *
1369 * Returns a pointer to the new node object.
1370 */
1371xmlNodePtr
1372xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1373 const xmlChar *name, const xmlChar *content) {
1374 xmlNodePtr cur;
1375
1376 cur = xmlNewNode(ns, name);
1377 if (cur != NULL) {
1378 cur->doc = doc;
1379 if (content != NULL) {
1380 cur->children = xmlStringGetNodeList(doc, content);
1381 UPDATE_LAST_CHILD_AND_PARENT(cur)
1382 }
1383 }
1384 return(cur);
1385}
1386
1387
1388/**
1389 * xmlNewDocRawNode:
1390 * @doc: the document
1391 * @ns: namespace if any
1392 * @name: the node name
1393 * @content: the text content if any
1394 *
1395 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001396 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001397 *
1398 * Returns a pointer to the new node object.
1399 */
1400xmlNodePtr
1401xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1402 const xmlChar *name, const xmlChar *content) {
1403 xmlNodePtr cur;
1404
1405 cur = xmlNewNode(ns, name);
1406 if (cur != NULL) {
1407 cur->doc = doc;
1408 if (content != NULL) {
1409 cur->children = xmlNewDocText(doc, content);
1410 UPDATE_LAST_CHILD_AND_PARENT(cur)
1411 }
1412 }
1413 return(cur);
1414}
1415
1416/**
1417 * xmlNewDocFragment:
1418 * @doc: the document owning the fragment
1419 *
1420 * Creation of a new Fragment node.
1421 * Returns a pointer to the new node object.
1422 */
1423xmlNodePtr
1424xmlNewDocFragment(xmlDocPtr doc) {
1425 xmlNodePtr cur;
1426
1427 /*
1428 * Allocate a new DocumentFragment node and fill the fields.
1429 */
1430 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1431 if (cur == NULL) {
1432 xmlGenericError(xmlGenericErrorContext,
1433 "xmlNewDocFragment : malloc failed\n");
1434 return(NULL);
1435 }
1436 memset(cur, 0, sizeof(xmlNode));
1437 cur->type = XML_DOCUMENT_FRAG_NODE;
1438
1439 cur->doc = doc;
1440 return(cur);
1441}
1442
1443/**
1444 * xmlNewText:
1445 * @content: the text content
1446 *
1447 * Creation of a new text node.
1448 * Returns a pointer to the new node object.
1449 */
1450xmlNodePtr
1451xmlNewText(const xmlChar *content) {
1452 xmlNodePtr cur;
1453
1454 /*
1455 * Allocate a new node and fill the fields.
1456 */
1457 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1458 if (cur == NULL) {
1459 xmlGenericError(xmlGenericErrorContext,
1460 "xmlNewText : malloc failed\n");
1461 return(NULL);
1462 }
1463 memset(cur, 0, sizeof(xmlNode));
1464 cur->type = XML_TEXT_NODE;
1465
1466 cur->name = xmlStringText;
1467 if (content != NULL) {
1468#ifndef XML_USE_BUFFER_CONTENT
1469 cur->content = xmlStrdup(content);
1470#else
1471 cur->content = xmlBufferCreateSize(0);
1472 xmlBufferSetAllocationScheme(cur->content,
1473 xmlGetBufferAllocationScheme());
1474 xmlBufferAdd(cur->content, content, -1);
1475#endif
1476 }
1477 return(cur);
1478}
1479
1480/**
1481 * xmlNewTextChild:
1482 * @parent: the parent node
1483 * @ns: a namespace if any
1484 * @name: the name of the child
1485 * @content: the text content of the child if any.
1486 *
1487 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001488 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001489 * a child TEXT node will be created containing the string content.
1490 *
1491 * Returns a pointer to the new node object.
1492 */
1493xmlNodePtr
1494xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1495 const xmlChar *name, const xmlChar *content) {
1496 xmlNodePtr cur, prev;
1497
1498 if (parent == NULL) {
1499#ifdef DEBUG_TREE
1500 xmlGenericError(xmlGenericErrorContext,
1501 "xmlNewTextChild : parent == NULL\n");
1502#endif
1503 return(NULL);
1504 }
1505
1506 if (name == NULL) {
1507#ifdef DEBUG_TREE
1508 xmlGenericError(xmlGenericErrorContext,
1509 "xmlNewTextChild : name == NULL\n");
1510#endif
1511 return(NULL);
1512 }
1513
1514 /*
1515 * Allocate a new node
1516 */
1517 if (ns == NULL)
1518 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1519 else
1520 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1521 if (cur == NULL) return(NULL);
1522
1523 /*
1524 * add the new element at the end of the children list.
1525 */
1526 cur->type = XML_ELEMENT_NODE;
1527 cur->parent = parent;
1528 cur->doc = parent->doc;
1529 if (parent->children == NULL) {
1530 parent->children = cur;
1531 parent->last = cur;
1532 } else {
1533 prev = parent->last;
1534 prev->next = cur;
1535 cur->prev = prev;
1536 parent->last = cur;
1537 }
1538
1539 return(cur);
1540}
1541
1542/**
1543 * xmlNewCharRef:
1544 * @doc: the document
1545 * @name: the char ref string, starting with # or "&# ... ;"
1546 *
1547 * Creation of a new character reference node.
1548 * Returns a pointer to the new node object.
1549 */
1550xmlNodePtr
1551xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1552 xmlNodePtr cur;
1553
1554 /*
1555 * Allocate a new node and fill the fields.
1556 */
1557 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1558 if (cur == NULL) {
1559 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001560 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001561 return(NULL);
1562 }
1563 memset(cur, 0, sizeof(xmlNode));
1564 cur->type = XML_ENTITY_REF_NODE;
1565
1566 cur->doc = doc;
1567 if (name[0] == '&') {
1568 int len;
1569 name++;
1570 len = xmlStrlen(name);
1571 if (name[len - 1] == ';')
1572 cur->name = xmlStrndup(name, len - 1);
1573 else
1574 cur->name = xmlStrndup(name, len);
1575 } else
1576 cur->name = xmlStrdup(name);
1577 return(cur);
1578}
1579
1580/**
1581 * xmlNewReference:
1582 * @doc: the document
1583 * @name: the reference name, or the reference string with & and ;
1584 *
1585 * Creation of a new reference node.
1586 * Returns a pointer to the new node object.
1587 */
1588xmlNodePtr
1589xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1590 xmlNodePtr cur;
1591 xmlEntityPtr ent;
1592
1593 /*
1594 * Allocate a new node and fill the fields.
1595 */
1596 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1597 if (cur == NULL) {
1598 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001599 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001600 return(NULL);
1601 }
1602 memset(cur, 0, sizeof(xmlNode));
1603 cur->type = XML_ENTITY_REF_NODE;
1604
1605 cur->doc = doc;
1606 if (name[0] == '&') {
1607 int len;
1608 name++;
1609 len = xmlStrlen(name);
1610 if (name[len - 1] == ';')
1611 cur->name = xmlStrndup(name, len - 1);
1612 else
1613 cur->name = xmlStrndup(name, len);
1614 } else
1615 cur->name = xmlStrdup(name);
1616
1617 ent = xmlGetDocEntity(doc, cur->name);
1618 if (ent != NULL) {
1619#ifndef XML_USE_BUFFER_CONTENT
1620 cur->content = ent->content;
1621#else
1622 /*
1623 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1624 * a copy of this pointer. Let's hope we don't manipulate it
1625 * later
1626 */
1627 cur->content = xmlBufferCreateSize(0);
1628 xmlBufferSetAllocationScheme(cur->content,
1629 xmlGetBufferAllocationScheme());
1630 if (ent->content != NULL)
1631 xmlBufferAdd(cur->content, ent->content, -1);
1632#endif
1633 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001634 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001635 * updated. Not sure if this is 100% correct.
1636 * -George
1637 */
1638 cur->children = (xmlNodePtr) ent;
1639 cur->last = (xmlNodePtr) ent;
1640 }
1641 return(cur);
1642}
1643
1644/**
1645 * xmlNewDocText:
1646 * @doc: the document
1647 * @content: the text content
1648 *
1649 * Creation of a new text node within a document.
1650 * Returns a pointer to the new node object.
1651 */
1652xmlNodePtr
1653xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1654 xmlNodePtr cur;
1655
1656 cur = xmlNewText(content);
1657 if (cur != NULL) cur->doc = doc;
1658 return(cur);
1659}
1660
1661/**
1662 * xmlNewTextLen:
1663 * @content: the text content
1664 * @len: the text len.
1665 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001666 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001667 * Returns a pointer to the new node object.
1668 */
1669xmlNodePtr
1670xmlNewTextLen(const xmlChar *content, int len) {
1671 xmlNodePtr cur;
1672
1673 /*
1674 * Allocate a new node and fill the fields.
1675 */
1676 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1677 if (cur == NULL) {
1678 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001679 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001680 return(NULL);
1681 }
1682 memset(cur, 0, sizeof(xmlNode));
1683 cur->type = XML_TEXT_NODE;
1684
1685 cur->name = xmlStringText;
1686 if (content != NULL) {
1687#ifndef XML_USE_BUFFER_CONTENT
1688 cur->content = xmlStrndup(content, len);
1689#else
1690 cur->content = xmlBufferCreateSize(len);
1691 xmlBufferSetAllocationScheme(cur->content,
1692 xmlGetBufferAllocationScheme());
1693 xmlBufferAdd(cur->content, content, len);
1694#endif
1695 }
1696 return(cur);
1697}
1698
1699/**
1700 * xmlNewDocTextLen:
1701 * @doc: the document
1702 * @content: the text content
1703 * @len: the text len.
1704 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001705 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001706 * text node pertain to a given document.
1707 * Returns a pointer to the new node object.
1708 */
1709xmlNodePtr
1710xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1711 xmlNodePtr cur;
1712
1713 cur = xmlNewTextLen(content, len);
1714 if (cur != NULL) cur->doc = doc;
1715 return(cur);
1716}
1717
1718/**
1719 * xmlNewComment:
1720 * @content: the comment content
1721 *
1722 * Creation of a new node containing a comment.
1723 * Returns a pointer to the new node object.
1724 */
1725xmlNodePtr
1726xmlNewComment(const xmlChar *content) {
1727 xmlNodePtr cur;
1728
1729 /*
1730 * Allocate a new node and fill the fields.
1731 */
1732 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1733 if (cur == NULL) {
1734 xmlGenericError(xmlGenericErrorContext,
1735 "xmlNewComment : malloc failed\n");
1736 return(NULL);
1737 }
1738 memset(cur, 0, sizeof(xmlNode));
1739 cur->type = XML_COMMENT_NODE;
1740
1741 cur->name = xmlStringComment;
1742 if (content != NULL) {
1743#ifndef XML_USE_BUFFER_CONTENT
1744 cur->content = xmlStrdup(content);
1745#else
1746 cur->content = xmlBufferCreateSize(0);
1747 xmlBufferSetAllocationScheme(cur->content,
1748 xmlGetBufferAllocationScheme());
1749 xmlBufferAdd(cur->content, content, -1);
1750#endif
1751 }
1752 return(cur);
1753}
1754
1755/**
1756 * xmlNewCDataBlock:
1757 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001758 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001759 * @len: the length of the block
1760 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001761 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001762 * Returns a pointer to the new node object.
1763 */
1764xmlNodePtr
1765xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1766 xmlNodePtr cur;
1767
1768 /*
1769 * Allocate a new node and fill the fields.
1770 */
1771 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1772 if (cur == NULL) {
1773 xmlGenericError(xmlGenericErrorContext,
1774 "xmlNewCDataBlock : malloc failed\n");
1775 return(NULL);
1776 }
1777 memset(cur, 0, sizeof(xmlNode));
1778 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001779 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001780
1781 if (content != NULL) {
1782#ifndef XML_USE_BUFFER_CONTENT
1783 cur->content = xmlStrndup(content, len);
1784#else
1785 cur->content = xmlBufferCreateSize(len);
1786 xmlBufferSetAllocationScheme(cur->content,
1787 xmlGetBufferAllocationScheme());
1788 xmlBufferAdd(cur->content, content, len);
1789#endif
1790 }
1791 return(cur);
1792}
1793
1794/**
1795 * xmlNewDocComment:
1796 * @doc: the document
1797 * @content: the comment content
1798 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001799 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001800 * Returns a pointer to the new node object.
1801 */
1802xmlNodePtr
1803xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1804 xmlNodePtr cur;
1805
1806 cur = xmlNewComment(content);
1807 if (cur != NULL) cur->doc = doc;
1808 return(cur);
1809}
1810
1811/**
1812 * xmlSetTreeDoc:
1813 * @tree: the top element
1814 * @doc: the document
1815 *
1816 * update all nodes under the tree to point to the right document
1817 */
1818void
1819xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001820 xmlAttrPtr prop;
1821
Owen Taylor3473f882001-02-23 17:55:21 +00001822 if (tree == NULL)
1823 return;
1824 if (tree->type == XML_ENTITY_DECL)
1825 return;
1826 if (tree->doc != doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001827 prop = tree->properties;
1828 while (prop != NULL) {
1829 prop->doc = doc;
1830 xmlSetListDoc(prop->children, doc);
1831 prop = prop->next;
1832 }
Owen Taylor3473f882001-02-23 17:55:21 +00001833 if (tree->children != NULL)
1834 xmlSetListDoc(tree->children, doc);
1835 tree->doc = doc;
1836 }
1837}
1838
1839/**
1840 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001841 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001842 * @doc: the document
1843 *
1844 * update all nodes in the list to point to the right document
1845 */
1846void
1847xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1848 xmlNodePtr cur;
1849
1850 if (list == NULL)
1851 return;
1852 cur = list;
1853 while (cur != NULL) {
1854 if (cur->doc != doc)
1855 xmlSetTreeDoc(cur, doc);
1856 cur = cur->next;
1857 }
1858}
1859
1860
1861/**
1862 * xmlNewChild:
1863 * @parent: the parent node
1864 * @ns: a namespace if any
1865 * @name: the name of the child
1866 * @content: the XML content of the child if any.
1867 *
1868 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001869 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001870 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1871 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1872 * references, but XML special chars need to be escaped first by using
1873 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1874 * support is not needed.
1875 *
1876 * Returns a pointer to the new node object.
1877 */
1878xmlNodePtr
1879xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1880 const xmlChar *name, const xmlChar *content) {
1881 xmlNodePtr cur, prev;
1882
1883 if (parent == NULL) {
1884#ifdef DEBUG_TREE
1885 xmlGenericError(xmlGenericErrorContext,
1886 "xmlNewChild : parent == NULL\n");
1887#endif
1888 return(NULL);
1889 }
1890
1891 if (name == NULL) {
1892#ifdef DEBUG_TREE
1893 xmlGenericError(xmlGenericErrorContext,
1894 "xmlNewChild : name == NULL\n");
1895#endif
1896 return(NULL);
1897 }
1898
1899 /*
1900 * Allocate a new node
1901 */
1902 if (ns == NULL)
1903 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1904 else
1905 cur = xmlNewDocNode(parent->doc, ns, name, content);
1906 if (cur == NULL) return(NULL);
1907
1908 /*
1909 * add the new element at the end of the children list.
1910 */
1911 cur->type = XML_ELEMENT_NODE;
1912 cur->parent = parent;
1913 cur->doc = parent->doc;
1914 if (parent->children == NULL) {
1915 parent->children = cur;
1916 parent->last = cur;
1917 } else {
1918 prev = parent->last;
1919 prev->next = cur;
1920 cur->prev = prev;
1921 parent->last = cur;
1922 }
1923
1924 return(cur);
1925}
1926
1927/**
1928 * xmlAddNextSibling:
1929 * @cur: the child node
1930 * @elem: the new node
1931 *
1932 * Add a new element @elem as the next siblings of @cur
1933 * If the new element was already inserted in a document it is
1934 * first unlinked from its existing context.
1935 * As a result of text merging @elem may be freed.
1936 *
1937 * Returns the new element or NULL in case of error.
1938 */
1939xmlNodePtr
1940xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1941 if (cur == NULL) {
1942#ifdef DEBUG_TREE
1943 xmlGenericError(xmlGenericErrorContext,
1944 "xmlAddNextSibling : cur == NULL\n");
1945#endif
1946 return(NULL);
1947 }
1948 if (elem == NULL) {
1949#ifdef DEBUG_TREE
1950 xmlGenericError(xmlGenericErrorContext,
1951 "xmlAddNextSibling : elem == NULL\n");
1952#endif
1953 return(NULL);
1954 }
1955
1956 xmlUnlinkNode(elem);
1957
1958 if (elem->type == XML_TEXT_NODE) {
1959 if (cur->type == XML_TEXT_NODE) {
1960#ifndef XML_USE_BUFFER_CONTENT
1961 xmlNodeAddContent(cur, elem->content);
1962#else
1963 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1964#endif
1965 xmlFreeNode(elem);
1966 return(cur);
1967 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001968 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1969 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001970#ifndef XML_USE_BUFFER_CONTENT
1971 xmlChar *tmp;
1972
1973 tmp = xmlStrdup(elem->content);
1974 tmp = xmlStrcat(tmp, cur->next->content);
1975 xmlNodeSetContent(cur->next, tmp);
1976 xmlFree(tmp);
1977#else
1978 xmlBufferAddHead(cur->next->content,
1979 xmlBufferContent(elem->content),
1980 xmlBufferLength(elem->content));
1981#endif
1982 xmlFreeNode(elem);
1983 return(cur->next);
1984 }
1985 }
1986
1987 if (elem->doc != cur->doc) {
1988 xmlSetTreeDoc(elem, cur->doc);
1989 }
1990 elem->parent = cur->parent;
1991 elem->prev = cur;
1992 elem->next = cur->next;
1993 cur->next = elem;
1994 if (elem->next != NULL)
1995 elem->next->prev = elem;
1996 if ((elem->parent != NULL) && (elem->parent->last == cur))
1997 elem->parent->last = elem;
1998 return(elem);
1999}
2000
2001/**
2002 * xmlAddPrevSibling:
2003 * @cur: the child node
2004 * @elem: the new node
2005 *
2006 * Add a new element @elem as the previous siblings of @cur
2007 * merging adjacent TEXT nodes (@elem may be freed)
2008 * If the new element was already inserted in a document it is
2009 * first unlinked from its existing context.
2010 *
2011 * Returns the new element or NULL in case of error.
2012 */
2013xmlNodePtr
2014xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2015 if (cur == NULL) {
2016#ifdef DEBUG_TREE
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlAddPrevSibling : cur == NULL\n");
2019#endif
2020 return(NULL);
2021 }
2022 if (elem == NULL) {
2023#ifdef DEBUG_TREE
2024 xmlGenericError(xmlGenericErrorContext,
2025 "xmlAddPrevSibling : elem == NULL\n");
2026#endif
2027 return(NULL);
2028 }
2029
2030 xmlUnlinkNode(elem);
2031
2032 if (elem->type == XML_TEXT_NODE) {
2033 if (cur->type == XML_TEXT_NODE) {
2034#ifndef XML_USE_BUFFER_CONTENT
2035 xmlChar *tmp;
2036
2037 tmp = xmlStrdup(elem->content);
2038 tmp = xmlStrcat(tmp, cur->content);
2039 xmlNodeSetContent(cur, tmp);
2040 xmlFree(tmp);
2041#else
2042 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2043 xmlBufferLength(elem->content));
2044#endif
2045 xmlFreeNode(elem);
2046 return(cur);
2047 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002048 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2049 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002050#ifndef XML_USE_BUFFER_CONTENT
2051 xmlNodeAddContent(cur->prev, elem->content);
2052#else
2053 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2054#endif
2055 xmlFreeNode(elem);
2056 return(cur->prev);
2057 }
2058 }
2059
2060 if (elem->doc != cur->doc) {
2061 xmlSetTreeDoc(elem, cur->doc);
2062 }
2063 elem->parent = cur->parent;
2064 elem->next = cur;
2065 elem->prev = cur->prev;
2066 cur->prev = elem;
2067 if (elem->prev != NULL)
2068 elem->prev->next = elem;
2069 if ((elem->parent != NULL) && (elem->parent->children == cur))
2070 elem->parent->children = elem;
2071 return(elem);
2072}
2073
2074/**
2075 * xmlAddSibling:
2076 * @cur: the child node
2077 * @elem: the new node
2078 *
2079 * Add a new element @elem to the list of siblings of @cur
2080 * merging adjacent TEXT nodes (@elem may be freed)
2081 * If the new element was already inserted in a document it is
2082 * first unlinked from its existing context.
2083 *
2084 * Returns the new element or NULL in case of error.
2085 */
2086xmlNodePtr
2087xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2088 xmlNodePtr parent;
2089
2090 if (cur == NULL) {
2091#ifdef DEBUG_TREE
2092 xmlGenericError(xmlGenericErrorContext,
2093 "xmlAddSibling : cur == NULL\n");
2094#endif
2095 return(NULL);
2096 }
2097
2098 if (elem == NULL) {
2099#ifdef DEBUG_TREE
2100 xmlGenericError(xmlGenericErrorContext,
2101 "xmlAddSibling : elem == NULL\n");
2102#endif
2103 return(NULL);
2104 }
2105
2106 /*
2107 * Constant time is we can rely on the ->parent->last to find
2108 * the last sibling.
2109 */
2110 if ((cur->parent != NULL) &&
2111 (cur->parent->children != NULL) &&
2112 (cur->parent->last != NULL) &&
2113 (cur->parent->last->next == NULL)) {
2114 cur = cur->parent->last;
2115 } else {
2116 while (cur->next != NULL) cur = cur->next;
2117 }
2118
2119 xmlUnlinkNode(elem);
2120
2121 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2122#ifndef XML_USE_BUFFER_CONTENT
2123 xmlNodeAddContent(cur, elem->content);
2124#else
2125 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2126#endif
2127 xmlFreeNode(elem);
2128 return(cur);
2129 }
2130
2131 if (elem->doc != cur->doc) {
2132 xmlSetTreeDoc(elem, cur->doc);
2133 }
2134 parent = cur->parent;
2135 elem->prev = cur;
2136 elem->next = NULL;
2137 elem->parent = parent;
2138 cur->next = elem;
2139 if (parent != NULL)
2140 parent->last = elem;
2141
2142 return(elem);
2143}
2144
2145/**
2146 * xmlAddChildList:
2147 * @parent: the parent node
2148 * @cur: the first node in the list
2149 *
2150 * Add a list of node at the end of the child list of the parent
2151 * merging adjacent TEXT nodes (@cur may be freed)
2152 *
2153 * Returns the last child or NULL in case of error.
2154 */
2155xmlNodePtr
2156xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2157 xmlNodePtr prev;
2158
2159 if (parent == NULL) {
2160#ifdef DEBUG_TREE
2161 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002162 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002163#endif
2164 return(NULL);
2165 }
2166
2167 if (cur == NULL) {
2168#ifdef DEBUG_TREE
2169 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002170 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002171#endif
2172 return(NULL);
2173 }
2174
2175 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2176 (cur->doc != parent->doc)) {
2177#ifdef DEBUG_TREE
2178 xmlGenericError(xmlGenericErrorContext,
2179 "Elements moved to a different document\n");
2180#endif
2181 }
2182
2183 /*
2184 * add the first element at the end of the children list.
2185 */
2186 if (parent->children == NULL) {
2187 parent->children = cur;
2188 } else {
2189 /*
2190 * If cur and parent->last both are TEXT nodes, then merge them.
2191 */
2192 if ((cur->type == XML_TEXT_NODE) &&
2193 (parent->last->type == XML_TEXT_NODE) &&
2194 (cur->name == parent->last->name)) {
2195#ifndef XML_USE_BUFFER_CONTENT
2196 xmlNodeAddContent(parent->last, cur->content);
2197#else
2198 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2199#endif
2200 /*
2201 * if it's the only child, nothing more to be done.
2202 */
2203 if (cur->next == NULL) {
2204 xmlFreeNode(cur);
2205 return(parent->last);
2206 }
2207 prev = cur;
2208 cur = cur->next;
2209 xmlFreeNode(prev);
2210 }
2211 prev = parent->last;
2212 prev->next = cur;
2213 cur->prev = prev;
2214 }
2215 while (cur->next != NULL) {
2216 cur->parent = parent;
2217 if (cur->doc != parent->doc) {
2218 xmlSetTreeDoc(cur, parent->doc);
2219 }
2220 cur = cur->next;
2221 }
2222 cur->parent = parent;
2223 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2224 parent->last = cur;
2225
2226 return(cur);
2227}
2228
2229/**
2230 * xmlAddChild:
2231 * @parent: the parent node
2232 * @cur: the child node
2233 *
2234 * Add a new child element, to @parent, at the end of the child list
2235 * merging adjacent TEXT nodes (in which case @cur is freed)
2236 * Returns the child or NULL in case of error.
2237 */
2238xmlNodePtr
2239xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2240 xmlNodePtr prev;
2241
2242 if (parent == NULL) {
2243#ifdef DEBUG_TREE
2244 xmlGenericError(xmlGenericErrorContext,
2245 "xmlAddChild : parent == NULL\n");
2246#endif
2247 return(NULL);
2248 }
2249
2250 if (cur == NULL) {
2251#ifdef DEBUG_TREE
2252 xmlGenericError(xmlGenericErrorContext,
2253 "xmlAddChild : child == NULL\n");
2254#endif
2255 return(NULL);
2256 }
2257
Owen Taylor3473f882001-02-23 17:55:21 +00002258 /*
2259 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002260 * cur is then freed.
2261 */
2262 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002263 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002264 (parent->content != NULL)) {
2265#ifndef XML_USE_BUFFER_CONTENT
2266 xmlNodeAddContent(parent, cur->content);
2267#else
2268 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2269#endif
2270 xmlFreeNode(cur);
2271 return(parent);
2272 }
2273 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2274 (parent->last->name == cur->name)) {
2275#ifndef XML_USE_BUFFER_CONTENT
2276 xmlNodeAddContent(parent->last, cur->content);
2277#else
2278 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2279#endif
2280 xmlFreeNode(cur);
2281 return(parent->last);
2282 }
2283 }
2284
2285 /*
2286 * add the new element at the end of the children list.
2287 */
2288 cur->parent = parent;
2289 if (cur->doc != parent->doc) {
2290 xmlSetTreeDoc(cur, parent->doc);
2291 }
2292
2293 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002294 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002295 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002296 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002297 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002298#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002299 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002300#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002301 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002302#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002303 xmlFreeNode(cur);
2304 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002305 }
2306 if (parent->children == NULL) {
2307 parent->children = cur;
2308 parent->last = cur;
2309 } else {
2310 prev = parent->last;
2311 prev->next = cur;
2312 cur->prev = prev;
2313 parent->last = cur;
2314 }
2315
2316 return(cur);
2317}
2318
2319/**
2320 * xmlGetLastChild:
2321 * @parent: the parent node
2322 *
2323 * Search the last child of a node.
2324 * Returns the last child or NULL if none.
2325 */
2326xmlNodePtr
2327xmlGetLastChild(xmlNodePtr parent) {
2328 if (parent == NULL) {
2329#ifdef DEBUG_TREE
2330 xmlGenericError(xmlGenericErrorContext,
2331 "xmlGetLastChild : parent == NULL\n");
2332#endif
2333 return(NULL);
2334 }
2335 return(parent->last);
2336}
2337
2338/**
2339 * xmlFreeNodeList:
2340 * @cur: the first node in the list
2341 *
2342 * Free a node and all its siblings, this is a recursive behaviour, all
2343 * the children are freed too.
2344 */
2345void
2346xmlFreeNodeList(xmlNodePtr cur) {
2347 xmlNodePtr next;
2348 if (cur == NULL) {
2349#ifdef DEBUG_TREE
2350 xmlGenericError(xmlGenericErrorContext,
2351 "xmlFreeNodeList : node == NULL\n");
2352#endif
2353 return;
2354 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002355 if (cur->type == XML_NAMESPACE_DECL) {
2356 xmlFreeNsList((xmlNsPtr) cur);
2357 return;
2358 }
Owen Taylor3473f882001-02-23 17:55:21 +00002359 while (cur != NULL) {
2360 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002361 /* unroll to speed up freeing the document */
2362 if (cur->type != XML_DTD_NODE) {
2363 if ((cur->children != NULL) &&
2364 (cur->type != XML_ENTITY_REF_NODE))
2365 xmlFreeNodeList(cur->children);
2366 if (cur->properties != NULL)
2367 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002368 if ((cur->type != XML_ELEMENT_NODE) &&
2369 (cur->type != XML_XINCLUDE_START) &&
2370 (cur->type != XML_XINCLUDE_END) &&
2371 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002372#ifndef XML_USE_BUFFER_CONTENT
2373 if (cur->content != NULL) xmlFree(cur->content);
2374#else
2375 if (cur->content != NULL) xmlBufferFree(cur->content);
2376#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002377 }
2378 if (((cur->type == XML_ELEMENT_NODE) ||
2379 (cur->type == XML_XINCLUDE_START) ||
2380 (cur->type == XML_XINCLUDE_END)) &&
2381 (cur->nsDef != NULL))
2382 xmlFreeNsList(cur->nsDef);
2383
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002384 /*
2385 * When a node is a text node or a comment, it uses a global static
2386 * variable for the name of the node.
2387 *
2388 * The xmlStrEqual comparisons need to be done when (happened with
2389 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002390 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002391 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002392 * the string addresses compare are not sufficient.
2393 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002394 if ((cur->name != NULL) &&
2395 (cur->name != xmlStringText) &&
2396 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002397 (cur->name != xmlStringComment)) {
2398 if (cur->type == XML_TEXT_NODE) {
2399 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2400 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2401 xmlFree((char *) cur->name);
2402 } else if (cur->type == XML_COMMENT_NODE) {
2403 if (!xmlStrEqual(cur->name, xmlStringComment))
2404 xmlFree((char *) cur->name);
2405 } else
2406 xmlFree((char *) cur->name);
2407 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002408 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002409 xmlFree(cur);
2410 }
Owen Taylor3473f882001-02-23 17:55:21 +00002411 cur = next;
2412 }
2413}
2414
2415/**
2416 * xmlFreeNode:
2417 * @cur: the node
2418 *
2419 * Free a node, this is a recursive behaviour, all the children are freed too.
2420 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2421 */
2422void
2423xmlFreeNode(xmlNodePtr cur) {
2424 if (cur == NULL) {
2425#ifdef DEBUG_TREE
2426 xmlGenericError(xmlGenericErrorContext,
2427 "xmlFreeNode : node == NULL\n");
2428#endif
2429 return;
2430 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002431 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002432 if (cur->type == XML_DTD_NODE) {
2433 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002434 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002435 }
2436 if (cur->type == XML_NAMESPACE_DECL) {
2437 xmlFreeNs((xmlNsPtr) cur);
2438 return;
2439 }
Owen Taylor3473f882001-02-23 17:55:21 +00002440 if ((cur->children != NULL) &&
2441 (cur->type != XML_ENTITY_REF_NODE))
2442 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002443 if (cur->properties != NULL)
2444 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002445 if ((cur->type != XML_ELEMENT_NODE) &&
2446 (cur->content != NULL) &&
2447 (cur->type != XML_ENTITY_REF_NODE) &&
2448 (cur->type != XML_XINCLUDE_END) &&
2449 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002450#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002451 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002452#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002453 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002454#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002455 }
2456
Daniel Veillardacd370f2001-06-09 17:17:51 +00002457 /*
2458 * When a node is a text node or a comment, it uses a global static
2459 * variable for the name of the node.
2460 *
2461 * The xmlStrEqual comparisons need to be done when (happened with
2462 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002463 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002464 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002465 * are not sufficient.
2466 */
Owen Taylor3473f882001-02-23 17:55:21 +00002467 if ((cur->name != NULL) &&
2468 (cur->name != xmlStringText) &&
2469 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002470 (cur->name != xmlStringComment)) {
2471 if (cur->type == XML_TEXT_NODE) {
2472 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2473 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2474 xmlFree((char *) cur->name);
2475 } else if (cur->type == XML_COMMENT_NODE) {
2476 if (!xmlStrEqual(cur->name, xmlStringComment))
2477 xmlFree((char *) cur->name);
2478 } else
2479 xmlFree((char *) cur->name);
2480 }
2481
Owen Taylor3473f882001-02-23 17:55:21 +00002482 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002483 xmlFree(cur);
2484}
2485
2486/**
2487 * xmlUnlinkNode:
2488 * @cur: the node
2489 *
2490 * Unlink a node from it's current context, the node is not freed
2491 */
2492void
2493xmlUnlinkNode(xmlNodePtr cur) {
2494 if (cur == NULL) {
2495#ifdef DEBUG_TREE
2496 xmlGenericError(xmlGenericErrorContext,
2497 "xmlUnlinkNode : node == NULL\n");
2498#endif
2499 return;
2500 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002501 if (cur->type == XML_DTD_NODE) {
2502 xmlDocPtr doc;
2503 doc = cur->doc;
2504 if (doc->intSubset == (xmlDtdPtr) cur)
2505 doc->intSubset = NULL;
2506 if (doc->extSubset == (xmlDtdPtr) cur)
2507 doc->extSubset = NULL;
2508 }
Owen Taylor3473f882001-02-23 17:55:21 +00002509 if ((cur->parent != NULL) && (cur->parent->children == cur))
2510 cur->parent->children = cur->next;
2511 if ((cur->parent != NULL) && (cur->parent->last == cur))
2512 cur->parent->last = cur->prev;
2513 if (cur->next != NULL)
2514 cur->next->prev = cur->prev;
2515 if (cur->prev != NULL)
2516 cur->prev->next = cur->next;
2517 cur->next = cur->prev = NULL;
2518 cur->parent = NULL;
2519}
2520
2521/**
2522 * xmlReplaceNode:
2523 * @old: the old node
2524 * @cur: the node
2525 *
2526 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002527 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002528 * first unlinked from its existing context.
2529 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002530 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002531 */
2532xmlNodePtr
2533xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2534 if (old == NULL) {
2535#ifdef DEBUG_TREE
2536 xmlGenericError(xmlGenericErrorContext,
2537 "xmlReplaceNode : old == NULL\n");
2538#endif
2539 return(NULL);
2540 }
2541 if (cur == NULL) {
2542 xmlUnlinkNode(old);
2543 return(old);
2544 }
2545 if (cur == old) {
2546 return(old);
2547 }
2548 xmlUnlinkNode(cur);
2549 cur->doc = old->doc;
2550 cur->parent = old->parent;
2551 cur->next = old->next;
2552 if (cur->next != NULL)
2553 cur->next->prev = cur;
2554 cur->prev = old->prev;
2555 if (cur->prev != NULL)
2556 cur->prev->next = cur;
2557 if (cur->parent != NULL) {
2558 if (cur->parent->children == old)
2559 cur->parent->children = cur;
2560 if (cur->parent->last == old)
2561 cur->parent->last = cur;
2562 }
2563 old->next = old->prev = NULL;
2564 old->parent = NULL;
2565 return(old);
2566}
2567
2568/************************************************************************
2569 * *
2570 * Copy operations *
2571 * *
2572 ************************************************************************/
2573
2574/**
2575 * xmlCopyNamespace:
2576 * @cur: the namespace
2577 *
2578 * Do a copy of the namespace.
2579 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002580 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002581 */
2582xmlNsPtr
2583xmlCopyNamespace(xmlNsPtr cur) {
2584 xmlNsPtr ret;
2585
2586 if (cur == NULL) return(NULL);
2587 switch (cur->type) {
2588 case XML_LOCAL_NAMESPACE:
2589 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2590 break;
2591 default:
2592#ifdef DEBUG_TREE
2593 xmlGenericError(xmlGenericErrorContext,
2594 "xmlCopyNamespace: invalid type %d\n", cur->type);
2595#endif
2596 return(NULL);
2597 }
2598 return(ret);
2599}
2600
2601/**
2602 * xmlCopyNamespaceList:
2603 * @cur: the first namespace
2604 *
2605 * Do a copy of an namespace list.
2606 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002607 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002608 */
2609xmlNsPtr
2610xmlCopyNamespaceList(xmlNsPtr cur) {
2611 xmlNsPtr ret = NULL;
2612 xmlNsPtr p = NULL,q;
2613
2614 while (cur != NULL) {
2615 q = xmlCopyNamespace(cur);
2616 if (p == NULL) {
2617 ret = p = q;
2618 } else {
2619 p->next = q;
2620 p = q;
2621 }
2622 cur = cur->next;
2623 }
2624 return(ret);
2625}
2626
2627static xmlNodePtr
2628xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2629/**
2630 * xmlCopyProp:
2631 * @target: the element where the attribute will be grafted
2632 * @cur: the attribute
2633 *
2634 * Do a copy of the attribute.
2635 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002636 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002637 */
2638xmlAttrPtr
2639xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2640 xmlAttrPtr ret;
2641
2642 if (cur == NULL) return(NULL);
2643 if (target != NULL)
2644 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2645 else if (cur->parent != NULL)
2646 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2647 else if (cur->children != NULL)
2648 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2649 else
2650 ret = xmlNewDocProp(NULL, cur->name, NULL);
2651 if (ret == NULL) return(NULL);
2652 ret->parent = target;
2653
2654 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002655 xmlNsPtr ns;
2656 if (target->doc)
Owen Taylor3473f882001-02-23 17:55:21 +00002657 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
Daniel Veillard8107a222002-01-13 14:10:10 +00002658 else if (cur->doc) /* target may not yet have a doc : KPI */
2659 ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2660 else
2661 ns = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002662 ret->ns = ns;
2663 } else
2664 ret->ns = NULL;
2665
2666 if (cur->children != NULL) {
2667 xmlNodePtr tmp;
2668
2669 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2670 ret->last = NULL;
2671 tmp = ret->children;
2672 while (tmp != NULL) {
2673 /* tmp->parent = (xmlNodePtr)ret; */
2674 if (tmp->next == NULL)
2675 ret->last = tmp;
2676 tmp = tmp->next;
2677 }
2678 }
2679 return(ret);
2680}
2681
2682/**
2683 * xmlCopyPropList:
2684 * @target: the element where the attributes will be grafted
2685 * @cur: the first attribute
2686 *
2687 * Do a copy of an attribute list.
2688 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002689 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002690 */
2691xmlAttrPtr
2692xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2693 xmlAttrPtr ret = NULL;
2694 xmlAttrPtr p = NULL,q;
2695
2696 while (cur != NULL) {
2697 q = xmlCopyProp(target, cur);
2698 if (p == NULL) {
2699 ret = p = q;
2700 } else {
2701 p->next = q;
2702 q->prev = p;
2703 p = q;
2704 }
2705 cur = cur->next;
2706 }
2707 return(ret);
2708}
2709
2710/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002711 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002712 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002713 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002714 * tricky reason: namespaces. Doing a direct copy of a node
2715 * say RPM:Copyright without changing the namespace pointer to
2716 * something else can produce stale links. One way to do it is
2717 * to keep a reference counter but this doesn't work as soon
2718 * as one move the element or the subtree out of the scope of
2719 * the existing namespace. The actual solution seems to add
2720 * a copy of the namespace at the top of the copied tree if
2721 * not available in the subtree.
2722 * Hence two functions, the public front-end call the inner ones
2723 */
2724
2725static xmlNodePtr
2726xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2727
2728static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002729xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002730 int recursive) {
2731 xmlNodePtr ret;
2732
2733 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002734 switch (node->type) {
2735 case XML_TEXT_NODE:
2736 case XML_CDATA_SECTION_NODE:
2737 case XML_ELEMENT_NODE:
2738 case XML_ENTITY_REF_NODE:
2739 case XML_ENTITY_NODE:
2740 case XML_PI_NODE:
2741 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002742 case XML_XINCLUDE_START:
2743 case XML_XINCLUDE_END:
2744 break;
2745 case XML_ATTRIBUTE_NODE:
2746 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2747 case XML_NAMESPACE_DECL:
2748 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2749
Daniel Veillard39196eb2001-06-19 18:09:42 +00002750 case XML_DOCUMENT_NODE:
2751 case XML_HTML_DOCUMENT_NODE:
2752#ifdef LIBXML_DOCB_ENABLED
2753 case XML_DOCB_DOCUMENT_NODE:
2754#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002755 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002756 case XML_DOCUMENT_TYPE_NODE:
2757 case XML_DOCUMENT_FRAG_NODE:
2758 case XML_NOTATION_NODE:
2759 case XML_DTD_NODE:
2760 case XML_ELEMENT_DECL:
2761 case XML_ATTRIBUTE_DECL:
2762 case XML_ENTITY_DECL:
2763 return(NULL);
2764 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002765
Owen Taylor3473f882001-02-23 17:55:21 +00002766 /*
2767 * Allocate a new node and fill the fields.
2768 */
2769 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2770 if (ret == NULL) {
2771 xmlGenericError(xmlGenericErrorContext,
2772 "xmlStaticCopyNode : malloc failed\n");
2773 return(NULL);
2774 }
2775 memset(ret, 0, sizeof(xmlNode));
2776 ret->type = node->type;
2777
2778 ret->doc = doc;
2779 ret->parent = parent;
2780 if (node->name == xmlStringText)
2781 ret->name = xmlStringText;
2782 else if (node->name == xmlStringTextNoenc)
2783 ret->name = xmlStringTextNoenc;
2784 else if (node->name == xmlStringComment)
2785 ret->name = xmlStringComment;
2786 else if (node->name != NULL)
2787 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002788 if ((node->type != XML_ELEMENT_NODE) &&
2789 (node->content != NULL) &&
2790 (node->type != XML_ENTITY_REF_NODE) &&
2791 (node->type != XML_XINCLUDE_END) &&
2792 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002793#ifndef XML_USE_BUFFER_CONTENT
2794 ret->content = xmlStrdup(node->content);
2795#else
2796 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2797 xmlBufferSetAllocationScheme(ret->content,
2798 xmlGetBufferAllocationScheme());
2799 xmlBufferAdd(ret->content,
2800 xmlBufferContent(node->content),
2801 xmlBufferLength(node->content));
2802#endif
Daniel Veillard8107a222002-01-13 14:10:10 +00002803 }else{
2804 if (node->type == XML_ELEMENT_NODE)
2805 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002806 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002807 if (parent != NULL) {
2808 xmlNodePtr tmp;
2809
2810 tmp = xmlAddChild(parent, ret);
2811 /* node could have coalesced */
2812 if (tmp != ret)
2813 return(tmp);
2814 }
Owen Taylor3473f882001-02-23 17:55:21 +00002815
2816 if (!recursive) return(ret);
2817 if (node->nsDef != NULL)
2818 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2819
2820 if (node->ns != NULL) {
2821 xmlNsPtr ns;
2822
2823 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2824 if (ns == NULL) {
2825 /*
2826 * Humm, we are copying an element whose namespace is defined
2827 * out of the new tree scope. Search it in the original tree
2828 * and add it at the top of the new tree
2829 */
2830 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2831 if (ns != NULL) {
2832 xmlNodePtr root = ret;
2833
2834 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002835 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002836 }
2837 } else {
2838 /*
2839 * reference the existing namespace definition in our own tree.
2840 */
2841 ret->ns = ns;
2842 }
2843 }
2844 if (node->properties != NULL)
2845 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002846 if (node->type == XML_ENTITY_REF_NODE) {
2847 if ((doc == NULL) || (node->doc != doc)) {
2848 /*
2849 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002850 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002851 * we cannot keep the reference. Try to find it in the
2852 * target document.
2853 */
2854 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2855 } else {
2856 ret->children = node->children;
2857 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002858 ret->last = ret->children;
2859 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002860 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002861 UPDATE_LAST_CHILD_AND_PARENT(ret)
2862 }
Owen Taylor3473f882001-02-23 17:55:21 +00002863 return(ret);
2864}
2865
2866static xmlNodePtr
2867xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2868 xmlNodePtr ret = NULL;
2869 xmlNodePtr p = NULL,q;
2870
2871 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002872 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002873 if (doc == NULL) {
2874 node = node->next;
2875 continue;
2876 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002877 if (doc->intSubset == NULL) {
2878 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2879 q->doc = doc;
2880 q->parent = parent;
2881 doc->intSubset = (xmlDtdPtr) q;
2882 } else {
2883 q = (xmlNodePtr) doc->intSubset;
2884 }
2885 } else
2886 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002887 if (ret == NULL) {
2888 q->prev = NULL;
2889 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002890 } else if (p != q) {
2891 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002892 p->next = q;
2893 q->prev = p;
2894 p = q;
2895 }
2896 node = node->next;
2897 }
2898 return(ret);
2899}
2900
2901/**
2902 * xmlCopyNode:
2903 * @node: the node
2904 * @recursive: if 1 do a recursive copy.
2905 *
2906 * Do a copy of the node.
2907 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002908 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002909 */
2910xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002911xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002912 xmlNodePtr ret;
2913
2914 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2915 return(ret);
2916}
2917
2918/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002919 * xmlDocCopyNode:
2920 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00002921 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00002922 * @recursive: if 1 do a recursive copy.
2923 *
2924 * Do a copy of the node to a given document.
2925 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002926 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00002927 */
2928xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002929xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002930 xmlNodePtr ret;
2931
2932 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2933 return(ret);
2934}
2935
2936/**
Owen Taylor3473f882001-02-23 17:55:21 +00002937 * xmlCopyNodeList:
2938 * @node: the first node in the list.
2939 *
2940 * Do a recursive copy of the node list.
2941 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002942 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002943 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002944xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002945 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2946 return(ret);
2947}
2948
2949/**
Owen Taylor3473f882001-02-23 17:55:21 +00002950 * xmlCopyDtd:
2951 * @dtd: the dtd
2952 *
2953 * Do a copy of the dtd.
2954 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002955 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002956 */
2957xmlDtdPtr
2958xmlCopyDtd(xmlDtdPtr dtd) {
2959 xmlDtdPtr ret;
2960
2961 if (dtd == NULL) return(NULL);
2962 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2963 if (ret == NULL) return(NULL);
2964 if (dtd->entities != NULL)
2965 ret->entities = (void *) xmlCopyEntitiesTable(
2966 (xmlEntitiesTablePtr) dtd->entities);
2967 if (dtd->notations != NULL)
2968 ret->notations = (void *) xmlCopyNotationTable(
2969 (xmlNotationTablePtr) dtd->notations);
2970 if (dtd->elements != NULL)
2971 ret->elements = (void *) xmlCopyElementTable(
2972 (xmlElementTablePtr) dtd->elements);
2973 if (dtd->attributes != NULL)
2974 ret->attributes = (void *) xmlCopyAttributeTable(
2975 (xmlAttributeTablePtr) dtd->attributes);
2976 return(ret);
2977}
2978
2979/**
2980 * xmlCopyDoc:
2981 * @doc: the document
2982 * @recursive: if 1 do a recursive copy.
2983 *
2984 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002985 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00002986 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002987 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002988 */
2989xmlDocPtr
2990xmlCopyDoc(xmlDocPtr doc, int recursive) {
2991 xmlDocPtr ret;
2992
2993 if (doc == NULL) return(NULL);
2994 ret = xmlNewDoc(doc->version);
2995 if (ret == NULL) return(NULL);
2996 if (doc->name != NULL)
2997 ret->name = xmlMemStrdup(doc->name);
2998 if (doc->encoding != NULL)
2999 ret->encoding = xmlStrdup(doc->encoding);
3000 ret->charset = doc->charset;
3001 ret->compression = doc->compression;
3002 ret->standalone = doc->standalone;
3003 if (!recursive) return(ret);
3004
Daniel Veillardb33c2012001-04-25 12:59:04 +00003005 ret->last = NULL;
3006 ret->children = NULL;
3007 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003008 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003009 ret->intSubset->doc = ret;
3010 ret->intSubset->parent = ret;
3011 }
Owen Taylor3473f882001-02-23 17:55:21 +00003012 if (doc->oldNs != NULL)
3013 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3014 if (doc->children != NULL) {
3015 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003016
3017 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3018 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003019 ret->last = NULL;
3020 tmp = ret->children;
3021 while (tmp != NULL) {
3022 if (tmp->next == NULL)
3023 ret->last = tmp;
3024 tmp = tmp->next;
3025 }
3026 }
3027 return(ret);
3028}
3029
3030/************************************************************************
3031 * *
3032 * Content access functions *
3033 * *
3034 ************************************************************************/
3035
3036/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003037 * xmlGetLineNo:
3038 * @node : valid node
3039 *
3040 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003041 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003042 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003043 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003044 */
3045long
3046xmlGetLineNo(xmlNodePtr node)
3047{
3048 long result = -1;
3049
3050 if (!node)
3051 return result;
3052 if (node->type == XML_ELEMENT_NODE)
3053 result = (long) node->content;
3054 else if ((node->prev != NULL) &&
3055 ((node->prev->type == XML_ELEMENT_NODE) ||
3056 (node->prev->type == XML_TEXT_NODE)))
3057 result = xmlGetLineNo(node->prev);
3058 else if ((node->parent != NULL) &&
3059 ((node->parent->type == XML_ELEMENT_NODE) ||
3060 (node->parent->type == XML_TEXT_NODE)))
3061 result = xmlGetLineNo(node->parent);
3062
3063 return result;
3064}
3065
3066/**
3067 * xmlGetNodePath:
3068 * @node: a node
3069 *
3070 * Build a structure based Path for the given node
3071 *
3072 * Returns the new path or NULL in case of error. The caller must free
3073 * the returned string
3074 */
3075xmlChar *
3076xmlGetNodePath(xmlNodePtr node)
3077{
3078 xmlNodePtr cur, tmp, next;
3079 xmlChar *buffer = NULL, *temp;
3080 size_t buf_len;
3081 xmlChar *buf;
3082 char sep;
3083 const char *name;
3084 char nametemp[100];
3085 int occur = 0;
3086
3087 if (node == NULL)
3088 return (NULL);
3089
3090 buf_len = 500;
3091 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3092 if (buffer == NULL)
3093 return (NULL);
3094 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3095 if (buf == NULL) {
3096 xmlFree(buffer);
3097 return (NULL);
3098 }
3099
3100 buffer[0] = 0;
3101 cur = node;
3102 do {
3103 name = "";
3104 sep = '?';
3105 occur = 0;
3106 if ((cur->type == XML_DOCUMENT_NODE) ||
3107 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3108 if (buffer[0] == '/')
3109 break;
3110 sep = '/';
3111 next = NULL;
3112 } else if (cur->type == XML_ELEMENT_NODE) {
3113 sep = '/';
3114 name = (const char *) cur->name;
3115 if (cur->ns) {
3116 snprintf(nametemp, sizeof(nametemp) - 1,
3117 "%s:%s", cur->ns->prefix, cur->name);
3118 nametemp[sizeof(nametemp) - 1] = 0;
3119 name = nametemp;
3120 }
3121 next = cur->parent;
3122
3123 /*
3124 * Thumbler index computation
3125 */
3126 tmp = cur->prev;
3127 while (tmp != NULL) {
3128 if (xmlStrEqual(cur->name, tmp->name))
3129 occur++;
3130 tmp = tmp->prev;
3131 }
3132 if (occur == 0) {
3133 tmp = cur->next;
3134 while (tmp != NULL) {
3135 if (xmlStrEqual(cur->name, tmp->name))
3136 occur++;
3137 tmp = tmp->next;
3138 }
3139 if (occur != 0)
3140 occur = 1;
3141 } else
3142 occur++;
3143 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3144 sep = '@';
3145 name = (const char *) (((xmlAttrPtr) cur)->name);
3146 next = ((xmlAttrPtr) cur)->parent;
3147 } else {
3148 next = cur->parent;
3149 }
3150
3151 /*
3152 * Make sure there is enough room
3153 */
3154 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3155 buf_len =
3156 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3157 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3158 if (temp == NULL) {
3159 xmlFree(buf);
3160 xmlFree(buffer);
3161 return (NULL);
3162 }
3163 buffer = temp;
3164 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3165 if (temp == NULL) {
3166 xmlFree(buf);
3167 xmlFree(buffer);
3168 return (NULL);
3169 }
3170 buf = temp;
3171 }
3172 if (occur == 0)
3173 snprintf((char *) buf, buf_len, "%c%s%s",
3174 sep, name, (char *) buffer);
3175 else
3176 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3177 sep, name, occur, (char *) buffer);
3178 snprintf((char *) buffer, buf_len, "%s", buf);
3179 cur = next;
3180 } while (cur != NULL);
3181 xmlFree(buf);
3182 return (buffer);
3183}
3184
3185/**
Owen Taylor3473f882001-02-23 17:55:21 +00003186 * xmlDocGetRootElement:
3187 * @doc: the document
3188 *
3189 * Get the root element of the document (doc->children is a list
3190 * containing possibly comments, PIs, etc ...).
3191 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003192 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003193 */
3194xmlNodePtr
3195xmlDocGetRootElement(xmlDocPtr doc) {
3196 xmlNodePtr ret;
3197
3198 if (doc == NULL) return(NULL);
3199 ret = doc->children;
3200 while (ret != NULL) {
3201 if (ret->type == XML_ELEMENT_NODE)
3202 return(ret);
3203 ret = ret->next;
3204 }
3205 return(ret);
3206}
3207
3208/**
3209 * xmlDocSetRootElement:
3210 * @doc: the document
3211 * @root: the new document root element
3212 *
3213 * Set the root element of the document (doc->children is a list
3214 * containing possibly comments, PIs, etc ...).
3215 *
3216 * Returns the old root element if any was found
3217 */
3218xmlNodePtr
3219xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3220 xmlNodePtr old = NULL;
3221
3222 if (doc == NULL) return(NULL);
3223 old = doc->children;
3224 while (old != NULL) {
3225 if (old->type == XML_ELEMENT_NODE)
3226 break;
3227 old = old->next;
3228 }
3229 if (old == NULL) {
3230 if (doc->children == NULL) {
3231 doc->children = root;
3232 doc->last = root;
3233 } else {
3234 xmlAddSibling(doc->children, root);
3235 }
3236 } else {
3237 xmlReplaceNode(old, root);
3238 }
3239 return(old);
3240}
3241
3242/**
3243 * xmlNodeSetLang:
3244 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003245 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003246 *
3247 * Set the language of a node, i.e. the values of the xml:lang
3248 * attribute.
3249 */
3250void
3251xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003252 xmlNsPtr ns;
3253
Owen Taylor3473f882001-02-23 17:55:21 +00003254 if (cur == NULL) return;
3255 switch(cur->type) {
3256 case XML_TEXT_NODE:
3257 case XML_CDATA_SECTION_NODE:
3258 case XML_COMMENT_NODE:
3259 case XML_DOCUMENT_NODE:
3260 case XML_DOCUMENT_TYPE_NODE:
3261 case XML_DOCUMENT_FRAG_NODE:
3262 case XML_NOTATION_NODE:
3263 case XML_HTML_DOCUMENT_NODE:
3264 case XML_DTD_NODE:
3265 case XML_ELEMENT_DECL:
3266 case XML_ATTRIBUTE_DECL:
3267 case XML_ENTITY_DECL:
3268 case XML_PI_NODE:
3269 case XML_ENTITY_REF_NODE:
3270 case XML_ENTITY_NODE:
3271 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003272#ifdef LIBXML_DOCB_ENABLED
3273 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003274#endif
3275 case XML_XINCLUDE_START:
3276 case XML_XINCLUDE_END:
3277 return;
3278 case XML_ELEMENT_NODE:
3279 case XML_ATTRIBUTE_NODE:
3280 break;
3281 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003282 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3283 if (ns == NULL)
3284 return;
3285 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003286}
3287
3288/**
3289 * xmlNodeGetLang:
3290 * @cur: the node being checked
3291 *
3292 * Searches the language of a node, i.e. the values of the xml:lang
3293 * attribute or the one carried by the nearest ancestor.
3294 *
3295 * Returns a pointer to the lang value, or NULL if not found
3296 * It's up to the caller to free the memory.
3297 */
3298xmlChar *
3299xmlNodeGetLang(xmlNodePtr cur) {
3300 xmlChar *lang;
3301
3302 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003303 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003304 if (lang != NULL)
3305 return(lang);
3306 cur = cur->parent;
3307 }
3308 return(NULL);
3309}
3310
3311
3312/**
3313 * xmlNodeSetSpacePreserve:
3314 * @cur: the node being changed
3315 * @val: the xml:space value ("0": default, 1: "preserve")
3316 *
3317 * Set (or reset) the space preserving behaviour of a node, i.e. the
3318 * value of the xml:space attribute.
3319 */
3320void
3321xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003322 xmlNsPtr ns;
3323
Owen Taylor3473f882001-02-23 17:55:21 +00003324 if (cur == NULL) return;
3325 switch(cur->type) {
3326 case XML_TEXT_NODE:
3327 case XML_CDATA_SECTION_NODE:
3328 case XML_COMMENT_NODE:
3329 case XML_DOCUMENT_NODE:
3330 case XML_DOCUMENT_TYPE_NODE:
3331 case XML_DOCUMENT_FRAG_NODE:
3332 case XML_NOTATION_NODE:
3333 case XML_HTML_DOCUMENT_NODE:
3334 case XML_DTD_NODE:
3335 case XML_ELEMENT_DECL:
3336 case XML_ATTRIBUTE_DECL:
3337 case XML_ENTITY_DECL:
3338 case XML_PI_NODE:
3339 case XML_ENTITY_REF_NODE:
3340 case XML_ENTITY_NODE:
3341 case XML_NAMESPACE_DECL:
3342 case XML_XINCLUDE_START:
3343 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003344#ifdef LIBXML_DOCB_ENABLED
3345 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003346#endif
3347 return;
3348 case XML_ELEMENT_NODE:
3349 case XML_ATTRIBUTE_NODE:
3350 break;
3351 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003352 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3353 if (ns == NULL)
3354 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003355 switch (val) {
3356 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003357 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003358 break;
3359 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003360 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003361 break;
3362 }
3363}
3364
3365/**
3366 * xmlNodeGetSpacePreserve:
3367 * @cur: the node being checked
3368 *
3369 * Searches the space preserving behaviour of a node, i.e. the values
3370 * of the xml:space attribute or the one carried by the nearest
3371 * ancestor.
3372 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003373 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003374 */
3375int
3376xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3377 xmlChar *space;
3378
3379 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003380 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003381 if (space != NULL) {
3382 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3383 xmlFree(space);
3384 return(1);
3385 }
3386 if (xmlStrEqual(space, BAD_CAST "default")) {
3387 xmlFree(space);
3388 return(0);
3389 }
3390 xmlFree(space);
3391 }
3392 cur = cur->parent;
3393 }
3394 return(-1);
3395}
3396
3397/**
3398 * xmlNodeSetName:
3399 * @cur: the node being changed
3400 * @name: the new tag name
3401 *
3402 * Set (or reset) the name of a node.
3403 */
3404void
3405xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3406 if (cur == NULL) return;
3407 if (name == NULL) return;
3408 switch(cur->type) {
3409 case XML_TEXT_NODE:
3410 case XML_CDATA_SECTION_NODE:
3411 case XML_COMMENT_NODE:
3412 case XML_DOCUMENT_TYPE_NODE:
3413 case XML_DOCUMENT_FRAG_NODE:
3414 case XML_NOTATION_NODE:
3415 case XML_HTML_DOCUMENT_NODE:
3416 case XML_NAMESPACE_DECL:
3417 case XML_XINCLUDE_START:
3418 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003419#ifdef LIBXML_DOCB_ENABLED
3420 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003421#endif
3422 return;
3423 case XML_ELEMENT_NODE:
3424 case XML_ATTRIBUTE_NODE:
3425 case XML_PI_NODE:
3426 case XML_ENTITY_REF_NODE:
3427 case XML_ENTITY_NODE:
3428 case XML_DTD_NODE:
3429 case XML_DOCUMENT_NODE:
3430 case XML_ELEMENT_DECL:
3431 case XML_ATTRIBUTE_DECL:
3432 case XML_ENTITY_DECL:
3433 break;
3434 }
3435 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3436 cur->name = xmlStrdup(name);
3437}
3438
3439/**
3440 * xmlNodeSetBase:
3441 * @cur: the node being changed
3442 * @uri: the new base URI
3443 *
3444 * Set (or reset) the base URI of a node, i.e. the value of the
3445 * xml:base attribute.
3446 */
3447void
3448xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003449 xmlNsPtr ns;
3450
Owen Taylor3473f882001-02-23 17:55:21 +00003451 if (cur == NULL) return;
3452 switch(cur->type) {
3453 case XML_TEXT_NODE:
3454 case XML_CDATA_SECTION_NODE:
3455 case XML_COMMENT_NODE:
3456 case XML_DOCUMENT_NODE:
3457 case XML_DOCUMENT_TYPE_NODE:
3458 case XML_DOCUMENT_FRAG_NODE:
3459 case XML_NOTATION_NODE:
3460 case XML_HTML_DOCUMENT_NODE:
3461 case XML_DTD_NODE:
3462 case XML_ELEMENT_DECL:
3463 case XML_ATTRIBUTE_DECL:
3464 case XML_ENTITY_DECL:
3465 case XML_PI_NODE:
3466 case XML_ENTITY_REF_NODE:
3467 case XML_ENTITY_NODE:
3468 case XML_NAMESPACE_DECL:
3469 case XML_XINCLUDE_START:
3470 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003471#ifdef LIBXML_DOCB_ENABLED
3472 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003473#endif
3474 return;
3475 case XML_ELEMENT_NODE:
3476 case XML_ATTRIBUTE_NODE:
3477 break;
3478 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003479
3480 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3481 if (ns == NULL)
3482 return;
3483 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003484}
3485
3486/**
Owen Taylor3473f882001-02-23 17:55:21 +00003487 * xmlNodeGetBase:
3488 * @doc: the document the node pertains to
3489 * @cur: the node being checked
3490 *
3491 * Searches for the BASE URL. The code should work on both XML
3492 * and HTML document even if base mechanisms are completely different.
3493 * It returns the base as defined in RFC 2396 sections
3494 * 5.1.1. Base URI within Document Content
3495 * and
3496 * 5.1.2. Base URI from the Encapsulating Entity
3497 * However it does not return the document base (5.1.3), use
3498 * xmlDocumentGetBase() for this
3499 *
3500 * Returns a pointer to the base URL, or NULL if not found
3501 * It's up to the caller to free the memory.
3502 */
3503xmlChar *
3504xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003505 xmlChar *oldbase = NULL;
3506 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003507
3508 if ((cur == NULL) && (doc == NULL))
3509 return(NULL);
3510 if (doc == NULL) doc = cur->doc;
3511 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3512 cur = doc->children;
3513 while ((cur != NULL) && (cur->name != NULL)) {
3514 if (cur->type != XML_ELEMENT_NODE) {
3515 cur = cur->next;
3516 continue;
3517 }
3518 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3519 cur = cur->children;
3520 continue;
3521 }
3522 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3523 cur = cur->children;
3524 continue;
3525 }
3526 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3527 return(xmlGetProp(cur, BAD_CAST "href"));
3528 }
3529 cur = cur->next;
3530 }
3531 return(NULL);
3532 }
3533 while (cur != NULL) {
3534 if (cur->type == XML_ENTITY_DECL) {
3535 xmlEntityPtr ent = (xmlEntityPtr) cur;
3536 return(xmlStrdup(ent->URI));
3537 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003538 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003539 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003540 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003541 if (oldbase != NULL) {
3542 newbase = xmlBuildURI(oldbase, base);
3543 if (newbase != NULL) {
3544 xmlFree(oldbase);
3545 xmlFree(base);
3546 oldbase = newbase;
3547 } else {
3548 xmlFree(oldbase);
3549 xmlFree(base);
3550 return(NULL);
3551 }
3552 } else {
3553 oldbase = base;
3554 }
3555 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3556 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3557 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3558 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003559 }
3560 }
Owen Taylor3473f882001-02-23 17:55:21 +00003561 cur = cur->parent;
3562 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003563 if ((doc != NULL) && (doc->URL != NULL)) {
3564 if (oldbase == NULL)
3565 return(xmlStrdup(doc->URL));
3566 newbase = xmlBuildURI(oldbase, doc->URL);
3567 xmlFree(oldbase);
3568 return(newbase);
3569 }
3570 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003571}
3572
3573/**
3574 * xmlNodeGetContent:
3575 * @cur: the node being read
3576 *
3577 * Read the value of a node, this can be either the text carried
3578 * directly by this node if it's a TEXT node or the aggregate string
3579 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003580 * Entity references are substituted.
3581 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003582 * It's up to the caller to free the memory.
3583 */
3584xmlChar *
3585xmlNodeGetContent(xmlNodePtr cur) {
3586 if (cur == NULL) return(NULL);
3587 switch (cur->type) {
3588 case XML_DOCUMENT_FRAG_NODE:
3589 case XML_ELEMENT_NODE: {
3590 xmlNodePtr tmp = cur;
3591 xmlBufferPtr buffer;
3592 xmlChar *ret;
3593
3594 buffer = xmlBufferCreate();
3595 if (buffer == NULL)
3596 return(NULL);
3597 while (tmp != NULL) {
3598 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003599 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003600 case XML_TEXT_NODE:
3601 if (tmp->content != NULL)
3602#ifndef XML_USE_BUFFER_CONTENT
3603 xmlBufferCat(buffer, tmp->content);
3604#else
3605 xmlBufferCat(buffer,
3606 xmlBufferContent(tmp->content));
3607#endif
3608 break;
3609 case XML_ENTITY_REF_NODE: {
3610 xmlEntityPtr ent;
3611
3612 ent = xmlGetDocEntity(cur->doc, tmp->name);
3613 if (ent != NULL)
3614 xmlBufferCat(buffer, ent->content);
3615 }
3616 default:
3617 break;
3618 }
3619 /*
3620 * Skip to next node
3621 */
3622 if (tmp->children != NULL) {
3623 if (tmp->children->type != XML_ENTITY_DECL) {
3624 tmp = tmp->children;
3625 continue;
3626 }
3627 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003628 if (tmp == cur)
3629 break;
3630
Owen Taylor3473f882001-02-23 17:55:21 +00003631 if (tmp->next != NULL) {
3632 tmp = tmp->next;
3633 continue;
3634 }
3635
3636 do {
3637 tmp = tmp->parent;
3638 if (tmp == NULL)
3639 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003640 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003641 tmp = NULL;
3642 break;
3643 }
3644 if (tmp->next != NULL) {
3645 tmp = tmp->next;
3646 break;
3647 }
3648 } while (tmp != NULL);
3649 }
3650 ret = buffer->content;
3651 buffer->content = NULL;
3652 xmlBufferFree(buffer);
3653 return(ret);
3654 }
3655 case XML_ATTRIBUTE_NODE: {
3656 xmlAttrPtr attr = (xmlAttrPtr) cur;
3657 if (attr->parent != NULL)
3658 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3659 else
3660 return(xmlNodeListGetString(NULL, attr->children, 1));
3661 break;
3662 }
3663 case XML_COMMENT_NODE:
3664 case XML_PI_NODE:
3665 if (cur->content != NULL)
3666#ifndef XML_USE_BUFFER_CONTENT
3667 return(xmlStrdup(cur->content));
3668#else
3669 return(xmlStrdup(xmlBufferContent(cur->content)));
3670#endif
3671 return(NULL);
3672 case XML_ENTITY_REF_NODE:
3673 /*
3674 * Locate the entity, and get it's content
3675 * @@@
3676 */
3677 return(NULL);
3678 case XML_ENTITY_NODE:
3679 case XML_DOCUMENT_NODE:
3680 case XML_HTML_DOCUMENT_NODE:
3681 case XML_DOCUMENT_TYPE_NODE:
3682 case XML_NOTATION_NODE:
3683 case XML_DTD_NODE:
3684 case XML_XINCLUDE_START:
3685 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003686#ifdef LIBXML_DOCB_ENABLED
3687 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003688#endif
3689 return(NULL);
3690 case XML_NAMESPACE_DECL:
3691 return(xmlStrdup(((xmlNsPtr)cur)->href));
3692 case XML_ELEMENT_DECL:
3693 /* TODO !!! */
3694 return(NULL);
3695 case XML_ATTRIBUTE_DECL:
3696 /* TODO !!! */
3697 return(NULL);
3698 case XML_ENTITY_DECL:
3699 /* TODO !!! */
3700 return(NULL);
3701 case XML_CDATA_SECTION_NODE:
3702 case XML_TEXT_NODE:
3703 if (cur->content != NULL)
3704#ifndef XML_USE_BUFFER_CONTENT
3705 return(xmlStrdup(cur->content));
3706#else
3707 return(xmlStrdup(xmlBufferContent(cur->content)));
3708#endif
3709 return(NULL);
3710 }
3711 return(NULL);
3712}
3713
3714/**
3715 * xmlNodeSetContent:
3716 * @cur: the node being modified
3717 * @content: the new value of the content
3718 *
3719 * Replace the content of a node.
3720 */
3721void
3722xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3723 if (cur == NULL) {
3724#ifdef DEBUG_TREE
3725 xmlGenericError(xmlGenericErrorContext,
3726 "xmlNodeSetContent : node == NULL\n");
3727#endif
3728 return;
3729 }
3730 switch (cur->type) {
3731 case XML_DOCUMENT_FRAG_NODE:
3732 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003733 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003734 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3735 cur->children = xmlStringGetNodeList(cur->doc, content);
3736 UPDATE_LAST_CHILD_AND_PARENT(cur)
3737 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003738 case XML_TEXT_NODE:
3739 case XML_CDATA_SECTION_NODE:
3740 case XML_ENTITY_REF_NODE:
3741 case XML_ENTITY_NODE:
3742 case XML_PI_NODE:
3743 case XML_COMMENT_NODE:
3744 if (cur->content != NULL) {
3745#ifndef XML_USE_BUFFER_CONTENT
3746 xmlFree(cur->content);
3747#else
3748 xmlBufferFree(cur->content);
3749#endif
3750 }
3751 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3752 cur->last = cur->children = NULL;
3753 if (content != NULL) {
3754#ifndef XML_USE_BUFFER_CONTENT
3755 cur->content = xmlStrdup(content);
3756#else
3757 cur->content = xmlBufferCreateSize(0);
3758 xmlBufferSetAllocationScheme(cur->content,
3759 xmlGetBufferAllocationScheme());
3760 xmlBufferAdd(cur->content, content, -1);
3761#endif
3762 } else
3763 cur->content = NULL;
3764 break;
3765 case XML_DOCUMENT_NODE:
3766 case XML_HTML_DOCUMENT_NODE:
3767 case XML_DOCUMENT_TYPE_NODE:
3768 case XML_XINCLUDE_START:
3769 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003770#ifdef LIBXML_DOCB_ENABLED
3771 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003772#endif
3773 break;
3774 case XML_NOTATION_NODE:
3775 break;
3776 case XML_DTD_NODE:
3777 break;
3778 case XML_NAMESPACE_DECL:
3779 break;
3780 case XML_ELEMENT_DECL:
3781 /* TODO !!! */
3782 break;
3783 case XML_ATTRIBUTE_DECL:
3784 /* TODO !!! */
3785 break;
3786 case XML_ENTITY_DECL:
3787 /* TODO !!! */
3788 break;
3789 }
3790}
3791
3792/**
3793 * xmlNodeSetContentLen:
3794 * @cur: the node being modified
3795 * @content: the new value of the content
3796 * @len: the size of @content
3797 *
3798 * Replace the content of a node.
3799 */
3800void
3801xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3802 if (cur == NULL) {
3803#ifdef DEBUG_TREE
3804 xmlGenericError(xmlGenericErrorContext,
3805 "xmlNodeSetContentLen : node == NULL\n");
3806#endif
3807 return;
3808 }
3809 switch (cur->type) {
3810 case XML_DOCUMENT_FRAG_NODE:
3811 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003812 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003813 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3814 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3815 UPDATE_LAST_CHILD_AND_PARENT(cur)
3816 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003817 case XML_TEXT_NODE:
3818 case XML_CDATA_SECTION_NODE:
3819 case XML_ENTITY_REF_NODE:
3820 case XML_ENTITY_NODE:
3821 case XML_PI_NODE:
3822 case XML_COMMENT_NODE:
3823 case XML_NOTATION_NODE:
3824 if (cur->content != NULL) {
3825#ifndef XML_USE_BUFFER_CONTENT
3826 xmlFree(cur->content);
3827#else
3828 xmlBufferFree(cur->content);
3829#endif
3830 }
3831 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3832 cur->children = cur->last = NULL;
3833 if (content != NULL) {
3834#ifndef XML_USE_BUFFER_CONTENT
3835 cur->content = xmlStrndup(content, len);
3836#else
3837 cur->content = xmlBufferCreateSize(len);
3838 xmlBufferSetAllocationScheme(cur->content,
3839 xmlGetBufferAllocationScheme());
3840 xmlBufferAdd(cur->content, content, len);
3841#endif
3842 } else
3843 cur->content = NULL;
3844 break;
3845 case XML_DOCUMENT_NODE:
3846 case XML_DTD_NODE:
3847 case XML_HTML_DOCUMENT_NODE:
3848 case XML_DOCUMENT_TYPE_NODE:
3849 case XML_NAMESPACE_DECL:
3850 case XML_XINCLUDE_START:
3851 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003852#ifdef LIBXML_DOCB_ENABLED
3853 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003854#endif
3855 break;
3856 case XML_ELEMENT_DECL:
3857 /* TODO !!! */
3858 break;
3859 case XML_ATTRIBUTE_DECL:
3860 /* TODO !!! */
3861 break;
3862 case XML_ENTITY_DECL:
3863 /* TODO !!! */
3864 break;
3865 }
3866}
3867
3868/**
3869 * xmlNodeAddContentLen:
3870 * @cur: the node being modified
3871 * @content: extra content
3872 * @len: the size of @content
3873 *
3874 * Append the extra substring to the node content.
3875 */
3876void
3877xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3878 if (cur == NULL) {
3879#ifdef DEBUG_TREE
3880 xmlGenericError(xmlGenericErrorContext,
3881 "xmlNodeAddContentLen : node == NULL\n");
3882#endif
3883 return;
3884 }
3885 if (len <= 0) return;
3886 switch (cur->type) {
3887 case XML_DOCUMENT_FRAG_NODE:
3888 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003889 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00003890
Daniel Veillard7db37732001-07-12 01:20:08 +00003891 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003892 newNode = xmlNewTextLen(content, len);
3893 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003894 tmp = xmlAddChild(cur, newNode);
3895 if (tmp != newNode)
3896 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003897 if ((last != NULL) && (last->next == newNode)) {
3898 xmlTextMerge(last, newNode);
3899 }
3900 }
3901 break;
3902 }
3903 case XML_ATTRIBUTE_NODE:
3904 break;
3905 case XML_TEXT_NODE:
3906 case XML_CDATA_SECTION_NODE:
3907 case XML_ENTITY_REF_NODE:
3908 case XML_ENTITY_NODE:
3909 case XML_PI_NODE:
3910 case XML_COMMENT_NODE:
3911 case XML_NOTATION_NODE:
3912 if (content != NULL) {
3913#ifndef XML_USE_BUFFER_CONTENT
3914 cur->content = xmlStrncat(cur->content, content, len);
3915#else
3916 xmlBufferAdd(cur->content, content, len);
3917#endif
3918 }
3919 case XML_DOCUMENT_NODE:
3920 case XML_DTD_NODE:
3921 case XML_HTML_DOCUMENT_NODE:
3922 case XML_DOCUMENT_TYPE_NODE:
3923 case XML_NAMESPACE_DECL:
3924 case XML_XINCLUDE_START:
3925 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003926#ifdef LIBXML_DOCB_ENABLED
3927 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003928#endif
3929 break;
3930 case XML_ELEMENT_DECL:
3931 case XML_ATTRIBUTE_DECL:
3932 case XML_ENTITY_DECL:
3933 break;
3934 }
3935}
3936
3937/**
3938 * xmlNodeAddContent:
3939 * @cur: the node being modified
3940 * @content: extra content
3941 *
3942 * Append the extra substring to the node content.
3943 */
3944void
3945xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3946 int len;
3947
3948 if (cur == NULL) {
3949#ifdef DEBUG_TREE
3950 xmlGenericError(xmlGenericErrorContext,
3951 "xmlNodeAddContent : node == NULL\n");
3952#endif
3953 return;
3954 }
3955 if (content == NULL) return;
3956 len = xmlStrlen(content);
3957 xmlNodeAddContentLen(cur, content, len);
3958}
3959
3960/**
3961 * xmlTextMerge:
3962 * @first: the first text node
3963 * @second: the second text node being merged
3964 *
3965 * Merge two text nodes into one
3966 * Returns the first text node augmented
3967 */
3968xmlNodePtr
3969xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3970 if (first == NULL) return(second);
3971 if (second == NULL) return(first);
3972 if (first->type != XML_TEXT_NODE) return(first);
3973 if (second->type != XML_TEXT_NODE) return(first);
3974 if (second->name != first->name)
3975 return(first);
3976#ifndef XML_USE_BUFFER_CONTENT
3977 xmlNodeAddContent(first, second->content);
3978#else
3979 xmlNodeAddContent(first, xmlBufferContent(second->content));
3980#endif
3981 xmlUnlinkNode(second);
3982 xmlFreeNode(second);
3983 return(first);
3984}
3985
3986/**
3987 * xmlGetNsList:
3988 * @doc: the document
3989 * @node: the current node
3990 *
3991 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00003992 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00003993 * that need to be freed by the caller or NULL if no
3994 * namespace if defined
3995 */
3996xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003997xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3998{
Owen Taylor3473f882001-02-23 17:55:21 +00003999 xmlNsPtr cur;
4000 xmlNsPtr *ret = NULL;
4001 int nbns = 0;
4002 int maxns = 10;
4003 int i;
4004
4005 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004006 if (node->type == XML_ELEMENT_NODE) {
4007 cur = node->nsDef;
4008 while (cur != NULL) {
4009 if (ret == NULL) {
4010 ret =
4011 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4012 sizeof(xmlNsPtr));
4013 if (ret == NULL) {
4014 xmlGenericError(xmlGenericErrorContext,
4015 "xmlGetNsList : out of memory!\n");
4016 return (NULL);
4017 }
4018 ret[nbns] = NULL;
4019 }
4020 for (i = 0; i < nbns; i++) {
4021 if ((cur->prefix == ret[i]->prefix) ||
4022 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4023 break;
4024 }
4025 if (i >= nbns) {
4026 if (nbns >= maxns) {
4027 maxns *= 2;
4028 ret = (xmlNsPtr *) xmlRealloc(ret,
4029 (maxns +
4030 1) *
4031 sizeof(xmlNsPtr));
4032 if (ret == NULL) {
4033 xmlGenericError(xmlGenericErrorContext,
4034 "xmlGetNsList : realloc failed!\n");
4035 return (NULL);
4036 }
4037 }
4038 ret[nbns++] = cur;
4039 ret[nbns] = NULL;
4040 }
Owen Taylor3473f882001-02-23 17:55:21 +00004041
Daniel Veillard77044732001-06-29 21:31:07 +00004042 cur = cur->next;
4043 }
4044 }
4045 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004046 }
Daniel Veillard77044732001-06-29 21:31:07 +00004047 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004048}
4049
4050/**
4051 * xmlSearchNs:
4052 * @doc: the document
4053 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004054 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004055 *
4056 * Search a Ns registered under a given name space for a document.
4057 * recurse on the parents until it finds the defined namespace
4058 * or return NULL otherwise.
4059 * @nameSpace can be NULL, this is a search for the default namespace.
4060 * We don't allow to cross entities boundaries. If you don't declare
4061 * the namespace within those you will be in troubles !!! A warning
4062 * is generated to cover this case.
4063 *
4064 * Returns the namespace pointer or NULL.
4065 */
4066xmlNsPtr
4067xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4068 xmlNsPtr cur;
4069
4070 if (node == NULL) return(NULL);
4071 if ((nameSpace != NULL) &&
4072 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004073 if (doc == NULL)
4074 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004075 if (doc->oldNs == NULL) {
4076 /*
4077 * Allocate a new Namespace and fill the fields.
4078 */
4079 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4080 if (doc->oldNs == NULL) {
4081 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004082 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004083 return(NULL);
4084 }
4085 memset(doc->oldNs, 0, sizeof(xmlNs));
4086 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4087
4088 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4089 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4090 }
4091 return(doc->oldNs);
4092 }
4093 while (node != NULL) {
4094 if ((node->type == XML_ENTITY_REF_NODE) ||
4095 (node->type == XML_ENTITY_NODE) ||
4096 (node->type == XML_ENTITY_DECL))
4097 return(NULL);
4098 if (node->type == XML_ELEMENT_NODE) {
4099 cur = node->nsDef;
4100 while (cur != NULL) {
4101 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4102 (cur->href != NULL))
4103 return(cur);
4104 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4105 (cur->href != NULL) &&
4106 (xmlStrEqual(cur->prefix, nameSpace)))
4107 return(cur);
4108 cur = cur->next;
4109 }
4110 }
4111 node = node->parent;
4112 }
4113 return(NULL);
4114}
4115
4116/**
4117 * xmlSearchNsByHref:
4118 * @doc: the document
4119 * @node: the current node
4120 * @href: the namespace value
4121 *
4122 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4123 * the defined namespace or return NULL otherwise.
4124 * Returns the namespace pointer or NULL.
4125 */
4126xmlNsPtr
4127xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4128 xmlNsPtr cur;
4129 xmlNodePtr orig = node;
4130
4131 if ((node == NULL) || (href == NULL)) return(NULL);
4132 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004133 /*
4134 * Only the document can hold the XML spec namespace.
4135 */
4136 if (doc == NULL)
4137 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004138 if (doc->oldNs == NULL) {
4139 /*
4140 * Allocate a new Namespace and fill the fields.
4141 */
4142 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4143 if (doc->oldNs == NULL) {
4144 xmlGenericError(xmlGenericErrorContext,
4145 "xmlSearchNsByHref : malloc failed\n");
4146 return(NULL);
4147 }
4148 memset(doc->oldNs, 0, sizeof(xmlNs));
4149 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4150
4151 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4152 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4153 }
4154 return(doc->oldNs);
4155 }
4156 while (node != NULL) {
4157 cur = node->nsDef;
4158 while (cur != NULL) {
4159 if ((cur->href != NULL) && (href != NULL) &&
4160 (xmlStrEqual(cur->href, href))) {
4161 /*
4162 * Check that the prefix is not shadowed between orig and node
4163 */
4164 xmlNodePtr check = orig;
4165 xmlNsPtr tst;
4166
4167 while (check != node) {
4168 tst = check->nsDef;
4169 while (tst != NULL) {
4170 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4171 goto shadowed;
4172 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4173 (xmlStrEqual(tst->prefix, cur->prefix)))
4174 goto shadowed;
4175 tst = tst->next;
4176 }
4177 check = check->parent;
4178 }
4179 return(cur);
4180 }
4181shadowed:
4182 cur = cur->next;
4183 }
4184 node = node->parent;
4185 }
4186 return(NULL);
4187}
4188
4189/**
4190 * xmlNewReconciliedNs
4191 * @doc: the document
4192 * @tree: a node expected to hold the new namespace
4193 * @ns: the original namespace
4194 *
4195 * This function tries to locate a namespace definition in a tree
4196 * ancestors, or create a new namespace definition node similar to
4197 * @ns trying to reuse the same prefix. However if the given prefix is
4198 * null (default namespace) or reused within the subtree defined by
4199 * @tree or on one of its ancestors then a new prefix is generated.
4200 * Returns the (new) namespace definition or NULL in case of error
4201 */
4202xmlNsPtr
4203xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4204 xmlNsPtr def;
4205 xmlChar prefix[50];
4206 int counter = 1;
4207
4208 if (tree == NULL) {
4209#ifdef DEBUG_TREE
4210 xmlGenericError(xmlGenericErrorContext,
4211 "xmlNewReconciliedNs : tree == NULL\n");
4212#endif
4213 return(NULL);
4214 }
4215 if (ns == NULL) {
4216#ifdef DEBUG_TREE
4217 xmlGenericError(xmlGenericErrorContext,
4218 "xmlNewReconciliedNs : ns == NULL\n");
4219#endif
4220 return(NULL);
4221 }
4222 /*
4223 * Search an existing namespace definition inherited.
4224 */
4225 def = xmlSearchNsByHref(doc, tree, ns->href);
4226 if (def != NULL)
4227 return(def);
4228
4229 /*
4230 * Find a close prefix which is not already in use.
4231 * Let's strip namespace prefixes longer than 20 chars !
4232 */
4233 sprintf((char *) prefix, "%.20s", ns->prefix);
4234 def = xmlSearchNs(doc, tree, prefix);
4235 while (def != NULL) {
4236 if (counter > 1000) return(NULL);
4237 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4238 def = xmlSearchNs(doc, tree, prefix);
4239 }
4240
4241 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004242 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004243 */
4244 def = xmlNewNs(tree, ns->href, prefix);
4245 return(def);
4246}
4247
4248/**
4249 * xmlReconciliateNs
4250 * @doc: the document
4251 * @tree: a node defining the subtree to reconciliate
4252 *
4253 * This function checks that all the namespaces declared within the given
4254 * tree are properly declared. This is needed for example after Copy or Cut
4255 * and then paste operations. The subtree may still hold pointers to
4256 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004257 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004258 * the new environment. If not possible the new namespaces are redeclared
4259 * on @tree at the top of the given subtree.
4260 * Returns the number of namespace declarations created or -1 in case of error.
4261 */
4262int
4263xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4264 xmlNsPtr *oldNs = NULL;
4265 xmlNsPtr *newNs = NULL;
4266 int sizeCache = 0;
4267 int nbCache = 0;
4268
4269 xmlNsPtr n;
4270 xmlNodePtr node = tree;
4271 xmlAttrPtr attr;
4272 int ret = 0, i;
4273
4274 while (node != NULL) {
4275 /*
4276 * Reconciliate the node namespace
4277 */
4278 if (node->ns != NULL) {
4279 /*
4280 * initialize the cache if needed
4281 */
4282 if (sizeCache == 0) {
4283 sizeCache = 10;
4284 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4285 sizeof(xmlNsPtr));
4286 if (oldNs == NULL) {
4287 xmlGenericError(xmlGenericErrorContext,
4288 "xmlReconciliateNs : memory pbm\n");
4289 return(-1);
4290 }
4291 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4292 sizeof(xmlNsPtr));
4293 if (newNs == NULL) {
4294 xmlGenericError(xmlGenericErrorContext,
4295 "xmlReconciliateNs : memory pbm\n");
4296 xmlFree(oldNs);
4297 return(-1);
4298 }
4299 }
4300 for (i = 0;i < nbCache;i++) {
4301 if (oldNs[i] == node->ns) {
4302 node->ns = newNs[i];
4303 break;
4304 }
4305 }
4306 if (i == nbCache) {
4307 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004308 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004309 */
4310 n = xmlNewReconciliedNs(doc, tree, node->ns);
4311 if (n != NULL) { /* :-( what if else ??? */
4312 /*
4313 * check if we need to grow the cache buffers.
4314 */
4315 if (sizeCache <= nbCache) {
4316 sizeCache *= 2;
4317 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4318 sizeof(xmlNsPtr));
4319 if (oldNs == NULL) {
4320 xmlGenericError(xmlGenericErrorContext,
4321 "xmlReconciliateNs : memory pbm\n");
4322 xmlFree(newNs);
4323 return(-1);
4324 }
4325 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4326 sizeof(xmlNsPtr));
4327 if (newNs == NULL) {
4328 xmlGenericError(xmlGenericErrorContext,
4329 "xmlReconciliateNs : memory pbm\n");
4330 xmlFree(oldNs);
4331 return(-1);
4332 }
4333 }
4334 newNs[nbCache] = n;
4335 oldNs[nbCache++] = node->ns;
4336 node->ns = n;
4337 }
4338 }
4339 }
4340 /*
4341 * now check for namespace hold by attributes on the node.
4342 */
4343 attr = node->properties;
4344 while (attr != NULL) {
4345 if (attr->ns != NULL) {
4346 /*
4347 * initialize the cache if needed
4348 */
4349 if (sizeCache == 0) {
4350 sizeCache = 10;
4351 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4352 sizeof(xmlNsPtr));
4353 if (oldNs == NULL) {
4354 xmlGenericError(xmlGenericErrorContext,
4355 "xmlReconciliateNs : memory pbm\n");
4356 return(-1);
4357 }
4358 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4359 sizeof(xmlNsPtr));
4360 if (newNs == NULL) {
4361 xmlGenericError(xmlGenericErrorContext,
4362 "xmlReconciliateNs : memory pbm\n");
4363 xmlFree(oldNs);
4364 return(-1);
4365 }
4366 }
4367 for (i = 0;i < nbCache;i++) {
4368 if (oldNs[i] == attr->ns) {
4369 node->ns = newNs[i];
4370 break;
4371 }
4372 }
4373 if (i == nbCache) {
4374 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004375 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004376 */
4377 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4378 if (n != NULL) { /* :-( what if else ??? */
4379 /*
4380 * check if we need to grow the cache buffers.
4381 */
4382 if (sizeCache <= nbCache) {
4383 sizeCache *= 2;
4384 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4385 sizeof(xmlNsPtr));
4386 if (oldNs == NULL) {
4387 xmlGenericError(xmlGenericErrorContext,
4388 "xmlReconciliateNs : memory pbm\n");
4389 xmlFree(newNs);
4390 return(-1);
4391 }
4392 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4393 sizeof(xmlNsPtr));
4394 if (newNs == NULL) {
4395 xmlGenericError(xmlGenericErrorContext,
4396 "xmlReconciliateNs : memory pbm\n");
4397 xmlFree(oldNs);
4398 return(-1);
4399 }
4400 }
4401 newNs[nbCache] = n;
4402 oldNs[nbCache++] = attr->ns;
4403 attr->ns = n;
4404 }
4405 }
4406 }
4407 attr = attr->next;
4408 }
4409
4410 /*
4411 * Browse the full subtree, deep first
4412 */
4413 if (node->children != NULL) {
4414 /* deep first */
4415 node = node->children;
4416 } else if ((node != tree) && (node->next != NULL)) {
4417 /* then siblings */
4418 node = node->next;
4419 } else if (node != tree) {
4420 /* go up to parents->next if needed */
4421 while (node != tree) {
4422 if (node->parent != NULL)
4423 node = node->parent;
4424 if ((node != tree) && (node->next != NULL)) {
4425 node = node->next;
4426 break;
4427 }
4428 if (node->parent == NULL) {
4429 node = NULL;
4430 break;
4431 }
4432 }
4433 /* exit condition */
4434 if (node == tree)
4435 node = NULL;
4436 }
4437 }
4438 return(ret);
4439}
4440
4441/**
4442 * xmlHasProp:
4443 * @node: the node
4444 * @name: the attribute name
4445 *
4446 * Search an attribute associated to a node
4447 * This function also looks in DTD attribute declaration for #FIXED or
4448 * default declaration values unless DTD use has been turned off.
4449 *
4450 * Returns the attribute or the attribute declaration or NULL if
4451 * neither was found.
4452 */
4453xmlAttrPtr
4454xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4455 xmlAttrPtr prop;
4456 xmlDocPtr doc;
4457
4458 if ((node == NULL) || (name == NULL)) return(NULL);
4459 /*
4460 * Check on the properties attached to the node
4461 */
4462 prop = node->properties;
4463 while (prop != NULL) {
4464 if (xmlStrEqual(prop->name, name)) {
4465 return(prop);
4466 }
4467 prop = prop->next;
4468 }
4469 if (!xmlCheckDTD) return(NULL);
4470
4471 /*
4472 * Check if there is a default declaration in the internal
4473 * or external subsets
4474 */
4475 doc = node->doc;
4476 if (doc != NULL) {
4477 xmlAttributePtr attrDecl;
4478 if (doc->intSubset != NULL) {
4479 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4480 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4481 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4482 if (attrDecl != NULL)
4483 return((xmlAttrPtr) attrDecl);
4484 }
4485 }
4486 return(NULL);
4487}
4488
4489/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004490 * xmlHasNsProp:
4491 * @node: the node
4492 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004493 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004494 *
4495 * Search for an attribute associated to a node
4496 * This attribute has to be anchored in the namespace specified.
4497 * This does the entity substitution.
4498 * This function looks in DTD attribute declaration for #FIXED or
4499 * default declaration values unless DTD use has been turned off.
4500 *
4501 * Returns the attribute or the attribute declaration or NULL
4502 * if neither was found.
4503 */
4504xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004505xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004506 xmlAttrPtr prop;
4507 xmlDocPtr doc;
4508 xmlNsPtr ns;
4509
4510 if (node == NULL)
4511 return(NULL);
4512
4513 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004514 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004515 return(xmlHasProp(node, name));
4516 while (prop != NULL) {
4517 /*
4518 * One need to have
4519 * - same attribute names
4520 * - and the attribute carrying that namespace
4521 * or
4522 * no namespace on the attribute and the element carrying it
4523 */
4524 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004525 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4526 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004527 }
4528 prop = prop->next;
4529 }
4530 if (!xmlCheckDTD) return(NULL);
4531
4532 /*
4533 * Check if there is a default declaration in the internal
4534 * or external subsets
4535 */
4536 doc = node->doc;
4537 if (doc != NULL) {
4538 if (doc->intSubset != NULL) {
4539 xmlAttributePtr attrDecl;
4540
4541 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4542 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4543 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4544
4545 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4546 /*
4547 * The DTD declaration only allows a prefix search
4548 */
4549 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004550 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004551 return((xmlAttrPtr) attrDecl);
4552 }
4553 }
4554 }
4555 return(NULL);
4556}
4557
4558/**
Owen Taylor3473f882001-02-23 17:55:21 +00004559 * xmlGetProp:
4560 * @node: the node
4561 * @name: the attribute name
4562 *
4563 * Search and get the value of an attribute associated to a node
4564 * This does the entity substitution.
4565 * This function looks in DTD attribute declaration for #FIXED or
4566 * default declaration values unless DTD use has been turned off.
4567 *
4568 * Returns the attribute value or NULL if not found.
4569 * It's up to the caller to free the memory.
4570 */
4571xmlChar *
4572xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4573 xmlAttrPtr prop;
4574 xmlDocPtr doc;
4575
4576 if ((node == NULL) || (name == NULL)) return(NULL);
4577 /*
4578 * Check on the properties attached to the node
4579 */
4580 prop = node->properties;
4581 while (prop != NULL) {
4582 if (xmlStrEqual(prop->name, name)) {
4583 xmlChar *ret;
4584
4585 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4586 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4587 return(ret);
4588 }
4589 prop = prop->next;
4590 }
4591 if (!xmlCheckDTD) return(NULL);
4592
4593 /*
4594 * Check if there is a default declaration in the internal
4595 * or external subsets
4596 */
4597 doc = node->doc;
4598 if (doc != NULL) {
4599 xmlAttributePtr attrDecl;
4600 if (doc->intSubset != NULL) {
4601 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4602 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4603 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4604 if (attrDecl != NULL)
4605 return(xmlStrdup(attrDecl->defaultValue));
4606 }
4607 }
4608 return(NULL);
4609}
4610
4611/**
4612 * xmlGetNsProp:
4613 * @node: the node
4614 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004615 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004616 *
4617 * Search and get the value of an attribute associated to a node
4618 * This attribute has to be anchored in the namespace specified.
4619 * This does the entity substitution.
4620 * This function looks in DTD attribute declaration for #FIXED or
4621 * default declaration values unless DTD use has been turned off.
4622 *
4623 * Returns the attribute value or NULL if not found.
4624 * It's up to the caller to free the memory.
4625 */
4626xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004627xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004628 xmlAttrPtr prop;
4629 xmlDocPtr doc;
4630 xmlNsPtr ns;
4631
4632 if (node == NULL)
4633 return(NULL);
4634
4635 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004636 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004637 return(xmlGetProp(node, name));
4638 while (prop != NULL) {
4639 /*
4640 * One need to have
4641 * - same attribute names
4642 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004643 */
4644 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004645 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004646 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004647 xmlChar *ret;
4648
4649 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4650 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4651 return(ret);
4652 }
4653 prop = prop->next;
4654 }
4655 if (!xmlCheckDTD) return(NULL);
4656
4657 /*
4658 * Check if there is a default declaration in the internal
4659 * or external subsets
4660 */
4661 doc = node->doc;
4662 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004663 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004664 xmlAttributePtr attrDecl;
4665
Owen Taylor3473f882001-02-23 17:55:21 +00004666 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4667 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4668 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4669
4670 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4671 /*
4672 * The DTD declaration only allows a prefix search
4673 */
4674 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004675 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004676 return(xmlStrdup(attrDecl->defaultValue));
4677 }
4678 }
4679 }
4680 return(NULL);
4681}
4682
4683/**
4684 * xmlSetProp:
4685 * @node: the node
4686 * @name: the attribute name
4687 * @value: the attribute value
4688 *
4689 * Set (or reset) an attribute carried by a node.
4690 * Returns the attribute pointer.
4691 */
4692xmlAttrPtr
4693xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004694 xmlAttrPtr prop;
4695 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004696
4697 if ((node == NULL) || (name == NULL))
4698 return(NULL);
4699 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004700 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004701 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004702 if ((xmlStrEqual(prop->name, name)) &&
4703 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004704 xmlNodePtr oldprop = prop->children;
4705
Owen Taylor3473f882001-02-23 17:55:21 +00004706 prop->children = NULL;
4707 prop->last = NULL;
4708 if (value != NULL) {
4709 xmlChar *buffer;
4710 xmlNodePtr tmp;
4711
4712 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4713 prop->children = xmlStringGetNodeList(node->doc, buffer);
4714 prop->last = NULL;
4715 prop->doc = doc;
4716 tmp = prop->children;
4717 while (tmp != NULL) {
4718 tmp->parent = (xmlNodePtr) prop;
4719 tmp->doc = doc;
4720 if (tmp->next == NULL)
4721 prop->last = tmp;
4722 tmp = tmp->next;
4723 }
4724 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004725 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004726 if (oldprop != NULL)
4727 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004728 return(prop);
4729 }
4730 prop = prop->next;
4731 }
4732 prop = xmlNewProp(node, name, value);
4733 return(prop);
4734}
4735
4736/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004737 * xmlUnsetProp:
4738 * @node: the node
4739 * @name: the attribute name
4740 *
4741 * Remove an attribute carried by a node.
4742 * Returns 0 if successful, -1 if not found
4743 */
4744int
4745xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4746 xmlAttrPtr prop = node->properties, prev = NULL;;
4747
4748 if ((node == NULL) || (name == NULL))
4749 return(-1);
4750 while (prop != NULL) {
4751 if ((xmlStrEqual(prop->name, name)) &&
4752 (prop->ns == NULL)) {
4753 if (prev == NULL)
4754 node->properties = prop->next;
4755 else
4756 prev->next = prop->next;
4757 xmlFreeProp(prop);
4758 return(0);
4759 }
4760 prev = prop;
4761 prop = prop->next;
4762 }
4763 return(-1);
4764}
4765
4766/**
Owen Taylor3473f882001-02-23 17:55:21 +00004767 * xmlSetNsProp:
4768 * @node: the node
4769 * @ns: the namespace definition
4770 * @name: the attribute name
4771 * @value: the attribute value
4772 *
4773 * Set (or reset) an attribute carried by a node.
4774 * The ns structure must be in scope, this is not checked.
4775 *
4776 * Returns the attribute pointer.
4777 */
4778xmlAttrPtr
4779xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4780 const xmlChar *value) {
4781 xmlAttrPtr prop;
4782
4783 if ((node == NULL) || (name == NULL))
4784 return(NULL);
4785
4786 if (ns == NULL)
4787 return(xmlSetProp(node, name, value));
4788 if (ns->href == NULL)
4789 return(NULL);
4790 prop = node->properties;
4791
4792 while (prop != NULL) {
4793 /*
4794 * One need to have
4795 * - same attribute names
4796 * - and the attribute carrying that namespace
4797 * or
4798 * no namespace on the attribute and the element carrying it
4799 */
4800 if ((xmlStrEqual(prop->name, name)) &&
4801 (((prop->ns == NULL) && (node->ns != NULL) &&
4802 (xmlStrEqual(node->ns->href, ns->href))) ||
4803 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4804 if (prop->children != NULL)
4805 xmlFreeNodeList(prop->children);
4806 prop->children = NULL;
4807 prop->last = NULL;
4808 prop->ns = ns;
4809 if (value != NULL) {
4810 xmlChar *buffer;
4811 xmlNodePtr tmp;
4812
4813 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4814 prop->children = xmlStringGetNodeList(node->doc, buffer);
4815 prop->last = NULL;
4816 tmp = prop->children;
4817 while (tmp != NULL) {
4818 tmp->parent = (xmlNodePtr) prop;
4819 if (tmp->next == NULL)
4820 prop->last = tmp;
4821 tmp = tmp->next;
4822 }
4823 xmlFree(buffer);
4824 }
4825 return(prop);
4826 }
4827 prop = prop->next;
4828 }
4829 prop = xmlNewNsProp(node, ns, name, value);
4830 return(prop);
4831}
4832
4833/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004834 * xmlUnsetNsProp:
4835 * @node: the node
4836 * @ns: the namespace definition
4837 * @name: the attribute name
4838 *
4839 * Remove an attribute carried by a node.
4840 * Returns 0 if successful, -1 if not found
4841 */
4842int
4843xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4844 xmlAttrPtr prop = node->properties, prev = NULL;;
4845
4846 if ((node == NULL) || (name == NULL))
4847 return(-1);
4848 if (ns == NULL)
4849 return(xmlUnsetProp(node, name));
4850 if (ns->href == NULL)
4851 return(-1);
4852 while (prop != NULL) {
4853 if ((xmlStrEqual(prop->name, name)) &&
4854 (((prop->ns == NULL) && (node->ns != NULL) &&
4855 (xmlStrEqual(node->ns->href, ns->href))) ||
4856 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4857 if (prev == NULL)
4858 node->properties = prop->next;
4859 else
4860 prev->next = prop->next;
4861 xmlFreeProp(prop);
4862 return(0);
4863 }
4864 prev = prop;
4865 prop = prop->next;
4866 }
4867 return(-1);
4868}
4869
4870/**
Owen Taylor3473f882001-02-23 17:55:21 +00004871 * xmlNodeIsText:
4872 * @node: the node
4873 *
4874 * Is this node a Text node ?
4875 * Returns 1 yes, 0 no
4876 */
4877int
4878xmlNodeIsText(xmlNodePtr node) {
4879 if (node == NULL) return(0);
4880
4881 if (node->type == XML_TEXT_NODE) return(1);
4882 return(0);
4883}
4884
4885/**
4886 * xmlIsBlankNode:
4887 * @node: the node
4888 *
4889 * Checks whether this node is an empty or whitespace only
4890 * (and possibly ignorable) text-node.
4891 *
4892 * Returns 1 yes, 0 no
4893 */
4894int
4895xmlIsBlankNode(xmlNodePtr node) {
4896 const xmlChar *cur;
4897 if (node == NULL) return(0);
4898
Daniel Veillard7db37732001-07-12 01:20:08 +00004899 if ((node->type != XML_TEXT_NODE) &&
4900 (node->type != XML_CDATA_SECTION_NODE))
4901 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004902 if (node->content == NULL) return(1);
4903#ifndef XML_USE_BUFFER_CONTENT
4904 cur = node->content;
4905#else
4906 cur = xmlBufferContent(node->content);
4907#endif
4908 while (*cur != 0) {
4909 if (!IS_BLANK(*cur)) return(0);
4910 cur++;
4911 }
4912
4913 return(1);
4914}
4915
4916/**
4917 * xmlTextConcat:
4918 * @node: the node
4919 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00004920 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00004921 *
4922 * Concat the given string at the end of the existing node content
4923 */
4924
4925void
4926xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4927 if (node == NULL) return;
4928
4929 if ((node->type != XML_TEXT_NODE) &&
4930 (node->type != XML_CDATA_SECTION_NODE)) {
4931#ifdef DEBUG_TREE
4932 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004933 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004934#endif
4935 return;
4936 }
4937#ifndef XML_USE_BUFFER_CONTENT
4938 node->content = xmlStrncat(node->content, content, len);
4939#else
4940 xmlBufferAdd(node->content, content, len);
4941#endif
4942}
4943
4944/************************************************************************
4945 * *
4946 * Output : to a FILE or in memory *
4947 * *
4948 ************************************************************************/
4949
Owen Taylor3473f882001-02-23 17:55:21 +00004950/**
4951 * xmlBufferCreate:
4952 *
4953 * routine to create an XML buffer.
4954 * returns the new structure.
4955 */
4956xmlBufferPtr
4957xmlBufferCreate(void) {
4958 xmlBufferPtr ret;
4959
4960 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4961 if (ret == NULL) {
4962 xmlGenericError(xmlGenericErrorContext,
4963 "xmlBufferCreate : out of memory!\n");
4964 return(NULL);
4965 }
4966 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004967 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004968 ret->alloc = xmlBufferAllocScheme;
4969 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4970 if (ret->content == NULL) {
4971 xmlGenericError(xmlGenericErrorContext,
4972 "xmlBufferCreate : out of memory!\n");
4973 xmlFree(ret);
4974 return(NULL);
4975 }
4976 ret->content[0] = 0;
4977 return(ret);
4978}
4979
4980/**
4981 * xmlBufferCreateSize:
4982 * @size: initial size of buffer
4983 *
4984 * routine to create an XML buffer.
4985 * returns the new structure.
4986 */
4987xmlBufferPtr
4988xmlBufferCreateSize(size_t size) {
4989 xmlBufferPtr ret;
4990
4991 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4992 if (ret == NULL) {
4993 xmlGenericError(xmlGenericErrorContext,
4994 "xmlBufferCreate : out of memory!\n");
4995 return(NULL);
4996 }
4997 ret->use = 0;
4998 ret->alloc = xmlBufferAllocScheme;
4999 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5000 if (ret->size){
5001 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5002 if (ret->content == NULL) {
5003 xmlGenericError(xmlGenericErrorContext,
5004 "xmlBufferCreate : out of memory!\n");
5005 xmlFree(ret);
5006 return(NULL);
5007 }
5008 ret->content[0] = 0;
5009 } else
5010 ret->content = NULL;
5011 return(ret);
5012}
5013
5014/**
5015 * xmlBufferSetAllocationScheme:
5016 * @buf: the buffer to free
5017 * @scheme: allocation scheme to use
5018 *
5019 * Sets the allocation scheme for this buffer
5020 */
5021void
5022xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5023 xmlBufferAllocationScheme scheme) {
5024 if (buf == NULL) {
5025#ifdef DEBUG_BUFFER
5026 xmlGenericError(xmlGenericErrorContext,
5027 "xmlBufferSetAllocationScheme: buf == NULL\n");
5028#endif
5029 return;
5030 }
5031
5032 buf->alloc = scheme;
5033}
5034
5035/**
5036 * xmlBufferFree:
5037 * @buf: the buffer to free
5038 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005039 * Frees an XML buffer. It frees both the content and the structure which
5040 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005041 */
5042void
5043xmlBufferFree(xmlBufferPtr buf) {
5044 if (buf == NULL) {
5045#ifdef DEBUG_BUFFER
5046 xmlGenericError(xmlGenericErrorContext,
5047 "xmlBufferFree: buf == NULL\n");
5048#endif
5049 return;
5050 }
5051 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005052 xmlFree(buf->content);
5053 }
Owen Taylor3473f882001-02-23 17:55:21 +00005054 xmlFree(buf);
5055}
5056
5057/**
5058 * xmlBufferEmpty:
5059 * @buf: the buffer
5060 *
5061 * empty a buffer.
5062 */
5063void
5064xmlBufferEmpty(xmlBufferPtr buf) {
5065 if (buf->content == NULL) return;
5066 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005067 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005068}
5069
5070/**
5071 * xmlBufferShrink:
5072 * @buf: the buffer to dump
5073 * @len: the number of xmlChar to remove
5074 *
5075 * Remove the beginning of an XML buffer.
5076 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005077 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005078 */
5079int
5080xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5081 if (len == 0) return(0);
5082 if (len > buf->use) return(-1);
5083
5084 buf->use -= len;
5085 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5086
5087 buf->content[buf->use] = 0;
5088 return(len);
5089}
5090
5091/**
5092 * xmlBufferGrow:
5093 * @buf: the buffer
5094 * @len: the minimum free size to allocate
5095 *
5096 * Grow the available space of an XML buffer.
5097 *
5098 * Returns the new available space or -1 in case of error
5099 */
5100int
5101xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5102 int size;
5103 xmlChar *newbuf;
5104
5105 if (len + buf->use < buf->size) return(0);
5106
5107 size = buf->use + len + 100;
5108
5109 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5110 if (newbuf == NULL) return(-1);
5111 buf->content = newbuf;
5112 buf->size = size;
5113 return(buf->size - buf->use);
5114}
5115
5116/**
5117 * xmlBufferDump:
5118 * @file: the file output
5119 * @buf: the buffer to dump
5120 *
5121 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005122 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005123 */
5124int
5125xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5126 int ret;
5127
5128 if (buf == NULL) {
5129#ifdef DEBUG_BUFFER
5130 xmlGenericError(xmlGenericErrorContext,
5131 "xmlBufferDump: buf == NULL\n");
5132#endif
5133 return(0);
5134 }
5135 if (buf->content == NULL) {
5136#ifdef DEBUG_BUFFER
5137 xmlGenericError(xmlGenericErrorContext,
5138 "xmlBufferDump: buf->content == NULL\n");
5139#endif
5140 return(0);
5141 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005142 if (file == NULL)
5143 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005144 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5145 return(ret);
5146}
5147
5148/**
5149 * xmlBufferContent:
5150 * @buf: the buffer
5151 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005152 * Function to extract the content of a buffer
5153 *
Owen Taylor3473f882001-02-23 17:55:21 +00005154 * Returns the internal content
5155 */
5156
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005157const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005158xmlBufferContent(const xmlBufferPtr buf)
5159{
5160 if(!buf)
5161 return NULL;
5162
5163 return buf->content;
5164}
5165
5166/**
5167 * xmlBufferLength:
5168 * @buf: the buffer
5169 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005170 * Function to get the length of a buffer
5171 *
Owen Taylor3473f882001-02-23 17:55:21 +00005172 * Returns the length of data in the internal content
5173 */
5174
5175int
5176xmlBufferLength(const xmlBufferPtr buf)
5177{
5178 if(!buf)
5179 return 0;
5180
5181 return buf->use;
5182}
5183
5184/**
5185 * xmlBufferResize:
5186 * @buf: the buffer to resize
5187 * @size: the desired size
5188 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005189 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005190 *
5191 * Returns 0 in case of problems, 1 otherwise
5192 */
5193int
5194xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5195{
5196 unsigned int newSize;
5197 xmlChar* rebuf = NULL;
5198
5199 /*take care of empty case*/
5200 newSize = (buf->size ? buf->size*2 : size);
5201
5202 /* Don't resize if we don't have to */
5203 if (size < buf->size)
5204 return 1;
5205
5206 /* figure out new size */
5207 switch (buf->alloc){
5208 case XML_BUFFER_ALLOC_DOUBLEIT:
5209 while (size > newSize) newSize *= 2;
5210 break;
5211 case XML_BUFFER_ALLOC_EXACT:
5212 newSize = size+10;
5213 break;
5214 default:
5215 newSize = size+10;
5216 break;
5217 }
5218
5219 if (buf->content == NULL)
5220 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5221 else
5222 rebuf = (xmlChar *) xmlRealloc(buf->content,
5223 newSize * sizeof(xmlChar));
5224 if (rebuf == NULL) {
5225 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005226 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005227 return 0;
5228 }
5229 buf->content = rebuf;
5230 buf->size = newSize;
5231
5232 return 1;
5233}
5234
5235/**
5236 * xmlBufferAdd:
5237 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005238 * @str: the #xmlChar string
5239 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005240 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005241 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005242 * str is recomputed.
5243 */
5244void
5245xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5246 unsigned int needSize;
5247
5248 if (str == NULL) {
5249#ifdef DEBUG_BUFFER
5250 xmlGenericError(xmlGenericErrorContext,
5251 "xmlBufferAdd: str == NULL\n");
5252#endif
5253 return;
5254 }
5255 if (len < -1) {
5256#ifdef DEBUG_BUFFER
5257 xmlGenericError(xmlGenericErrorContext,
5258 "xmlBufferAdd: len < 0\n");
5259#endif
5260 return;
5261 }
5262 if (len == 0) return;
5263
5264 if (len < 0)
5265 len = xmlStrlen(str);
5266
5267 if (len <= 0) return;
5268
5269 needSize = buf->use + len + 2;
5270 if (needSize > buf->size){
5271 if (!xmlBufferResize(buf, needSize)){
5272 xmlGenericError(xmlGenericErrorContext,
5273 "xmlBufferAdd : out of memory!\n");
5274 return;
5275 }
5276 }
5277
5278 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5279 buf->use += len;
5280 buf->content[buf->use] = 0;
5281}
5282
5283/**
5284 * xmlBufferAddHead:
5285 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005286 * @str: the #xmlChar string
5287 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005288 *
5289 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005290 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005291 */
5292void
5293xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5294 unsigned int needSize;
5295
5296 if (str == NULL) {
5297#ifdef DEBUG_BUFFER
5298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005299 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005300#endif
5301 return;
5302 }
5303 if (len < -1) {
5304#ifdef DEBUG_BUFFER
5305 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005306 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005307#endif
5308 return;
5309 }
5310 if (len == 0) return;
5311
5312 if (len < 0)
5313 len = xmlStrlen(str);
5314
5315 if (len <= 0) return;
5316
5317 needSize = buf->use + len + 2;
5318 if (needSize > buf->size){
5319 if (!xmlBufferResize(buf, needSize)){
5320 xmlGenericError(xmlGenericErrorContext,
5321 "xmlBufferAddHead : out of memory!\n");
5322 return;
5323 }
5324 }
5325
5326 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5327 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5328 buf->use += len;
5329 buf->content[buf->use] = 0;
5330}
5331
5332/**
5333 * xmlBufferCat:
5334 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005335 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005336 *
5337 * Append a zero terminated string to an XML buffer.
5338 */
5339void
5340xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5341 if (str != NULL)
5342 xmlBufferAdd(buf, str, -1);
5343}
5344
5345/**
5346 * xmlBufferCCat:
5347 * @buf: the buffer to dump
5348 * @str: the C char string
5349 *
5350 * Append a zero terminated C string to an XML buffer.
5351 */
5352void
5353xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5354 const char *cur;
5355
5356 if (str == NULL) {
5357#ifdef DEBUG_BUFFER
5358 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005359 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005360#endif
5361 return;
5362 }
5363 for (cur = str;*cur != 0;cur++) {
5364 if (buf->use + 10 >= buf->size) {
5365 if (!xmlBufferResize(buf, buf->use+10)){
5366 xmlGenericError(xmlGenericErrorContext,
5367 "xmlBufferCCat : out of memory!\n");
5368 return;
5369 }
5370 }
5371 buf->content[buf->use++] = *cur;
5372 }
5373 buf->content[buf->use] = 0;
5374}
5375
5376/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005377 * xmlBufferWriteXmlCHAR:
5378 * @buf: the XML buffer
5379 * @string: the string to add
5380 *
5381 * For VMS only.
5382 * routine which manages and grows an output buffer. This one adds
5383 * xmlChars at the end of the buffer.
5384 */
5385/**
Owen Taylor3473f882001-02-23 17:55:21 +00005386 * xmlBufferWriteCHAR:
5387 * @buf: the XML buffer
5388 * @string: the string to add
5389 *
5390 * routine which manages and grows an output buffer. This one adds
5391 * xmlChars at the end of the buffer.
5392 */
5393void
5394#ifdef VMS
5395xmlBufferWriteXmlCHAR
5396#else
5397xmlBufferWriteCHAR
5398#endif
5399(xmlBufferPtr buf, const xmlChar *string) {
5400 xmlBufferCat(buf, string);
5401}
5402
5403/**
5404 * xmlBufferWriteChar:
5405 * @buf: the XML buffer output
5406 * @string: the string to add
5407 *
5408 * routine which manage and grows an output buffer. This one add
5409 * C chars at the end of the array.
5410 */
5411void
5412xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5413 xmlBufferCCat(buf, string);
5414}
5415
5416
5417/**
5418 * xmlBufferWriteQuotedString:
5419 * @buf: the XML buffer output
5420 * @string: the string to add
5421 *
5422 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005423 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005424 * quote or double-quotes internally
5425 */
5426void
5427xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5428 if (xmlStrchr(string, '"')) {
5429 if (xmlStrchr(string, '\'')) {
5430#ifdef DEBUG_BUFFER
5431 xmlGenericError(xmlGenericErrorContext,
5432 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5433#endif
5434 }
5435 xmlBufferCCat(buf, "'");
5436 xmlBufferCat(buf, string);
5437 xmlBufferCCat(buf, "'");
5438 } else {
5439 xmlBufferCCat(buf, "\"");
5440 xmlBufferCat(buf, string);
5441 xmlBufferCCat(buf, "\"");
5442 }
5443}
5444
5445
5446/************************************************************************
5447 * *
5448 * Dumping XML tree content to a simple buffer *
5449 * *
5450 ************************************************************************/
5451
5452void
5453xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5454 int format);
5455static void
5456xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5457 int format);
5458void
5459htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5460
5461/**
5462 * xmlNsDump:
5463 * @buf: the XML buffer output
5464 * @cur: a namespace
5465 *
5466 * Dump a local Namespace definition.
5467 * Should be called in the context of attributes dumps.
5468 */
5469static void
5470xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5471 if (cur == NULL) {
5472#ifdef DEBUG_TREE
5473 xmlGenericError(xmlGenericErrorContext,
5474 "xmlNsDump : Ns == NULL\n");
5475#endif
5476 return;
5477 }
5478 if (cur->type == XML_LOCAL_NAMESPACE) {
5479 /* Within the context of an element attributes */
5480 if (cur->prefix != NULL) {
5481 xmlBufferWriteChar(buf, " xmlns:");
5482 xmlBufferWriteCHAR(buf, cur->prefix);
5483 } else
5484 xmlBufferWriteChar(buf, " xmlns");
5485 xmlBufferWriteChar(buf, "=");
5486 xmlBufferWriteQuotedString(buf, cur->href);
5487 }
5488}
5489
5490/**
5491 * xmlNsListDump:
5492 * @buf: the XML buffer output
5493 * @cur: the first namespace
5494 *
5495 * Dump a list of local Namespace definitions.
5496 * Should be called in the context of attributes dumps.
5497 */
5498static void
5499xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5500 while (cur != NULL) {
5501 xmlNsDump(buf, cur);
5502 cur = cur->next;
5503 }
5504}
5505
5506/**
5507 * xmlDtdDump:
5508 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005509 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005510 *
5511 * Dump the XML document DTD, if any.
5512 */
5513static void
5514xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5515 if (dtd == NULL) {
5516#ifdef DEBUG_TREE
5517 xmlGenericError(xmlGenericErrorContext,
5518 "xmlDtdDump : no internal subset\n");
5519#endif
5520 return;
5521 }
5522 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5523 xmlBufferWriteCHAR(buf, dtd->name);
5524 if (dtd->ExternalID != NULL) {
5525 xmlBufferWriteChar(buf, " PUBLIC ");
5526 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5527 xmlBufferWriteChar(buf, " ");
5528 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5529 } else if (dtd->SystemID != NULL) {
5530 xmlBufferWriteChar(buf, " SYSTEM ");
5531 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5532 }
5533 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5534 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5535 xmlBufferWriteChar(buf, ">");
5536 return;
5537 }
5538 xmlBufferWriteChar(buf, " [\n");
5539 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5540#if 0
5541 if (dtd->entities != NULL)
5542 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5543 if (dtd->notations != NULL)
5544 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5545 if (dtd->elements != NULL)
5546 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5547 if (dtd->attributes != NULL)
5548 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5549#endif
5550 xmlBufferWriteChar(buf, "]>");
5551}
5552
5553/**
5554 * xmlAttrDump:
5555 * @buf: the XML buffer output
5556 * @doc: the document
5557 * @cur: the attribute pointer
5558 *
5559 * Dump an XML attribute
5560 */
5561static void
5562xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5563 xmlChar *value;
5564
5565 if (cur == NULL) {
5566#ifdef DEBUG_TREE
5567 xmlGenericError(xmlGenericErrorContext,
5568 "xmlAttrDump : property == NULL\n");
5569#endif
5570 return;
5571 }
5572 xmlBufferWriteChar(buf, " ");
5573 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5574 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5575 xmlBufferWriteChar(buf, ":");
5576 }
5577 xmlBufferWriteCHAR(buf, cur->name);
5578 value = xmlNodeListGetString(doc, cur->children, 0);
5579 if (value != NULL) {
5580 xmlBufferWriteChar(buf, "=");
5581 xmlBufferWriteQuotedString(buf, value);
5582 xmlFree(value);
5583 } else {
5584 xmlBufferWriteChar(buf, "=\"\"");
5585 }
5586}
5587
5588/**
5589 * xmlAttrListDump:
5590 * @buf: the XML buffer output
5591 * @doc: the document
5592 * @cur: the first attribute pointer
5593 *
5594 * Dump a list of XML attributes
5595 */
5596static void
5597xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5598 if (cur == NULL) {
5599#ifdef DEBUG_TREE
5600 xmlGenericError(xmlGenericErrorContext,
5601 "xmlAttrListDump : property == NULL\n");
5602#endif
5603 return;
5604 }
5605 while (cur != NULL) {
5606 xmlAttrDump(buf, doc, cur);
5607 cur = cur->next;
5608 }
5609}
5610
5611
5612
5613/**
5614 * xmlNodeListDump:
5615 * @buf: the XML buffer output
5616 * @doc: the document
5617 * @cur: the first node
5618 * @level: the imbrication level for indenting
5619 * @format: is formatting allowed
5620 *
5621 * Dump an XML node list, recursive behaviour,children are printed too.
5622 */
5623static void
5624xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5625 int format) {
5626 int i;
5627
5628 if (cur == NULL) {
5629#ifdef DEBUG_TREE
5630 xmlGenericError(xmlGenericErrorContext,
5631 "xmlNodeListDump : node == NULL\n");
5632#endif
5633 return;
5634 }
5635 while (cur != NULL) {
5636 if ((format) && (xmlIndentTreeOutput) &&
5637 (cur->type == XML_ELEMENT_NODE))
5638 for (i = 0;i < level;i++)
5639 xmlBufferWriteChar(buf, " ");
5640 xmlNodeDump(buf, doc, cur, level, format);
5641 if (format) {
5642 xmlBufferWriteChar(buf, "\n");
5643 }
5644 cur = cur->next;
5645 }
5646}
5647
5648/**
5649 * xmlNodeDump:
5650 * @buf: the XML buffer output
5651 * @doc: the document
5652 * @cur: the current node
5653 * @level: the imbrication level for indenting
5654 * @format: is formatting allowed
5655 *
5656 * Dump an XML node, recursive behaviour,children are printed too.
5657 */
5658void
5659xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5660 int format) {
5661 int i;
5662 xmlNodePtr tmp;
5663
5664 if (cur == NULL) {
5665#ifdef DEBUG_TREE
5666 xmlGenericError(xmlGenericErrorContext,
5667 "xmlNodeDump : node == NULL\n");
5668#endif
5669 return;
5670 }
5671 if (cur->type == XML_XINCLUDE_START)
5672 return;
5673 if (cur->type == XML_XINCLUDE_END)
5674 return;
5675 if (cur->type == XML_DTD_NODE) {
5676 xmlDtdDump(buf, (xmlDtdPtr) cur);
5677 return;
5678 }
5679 if (cur->type == XML_ELEMENT_DECL) {
5680 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5681 return;
5682 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005683 if (cur->type == XML_ATTRIBUTE_NODE){
5684 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5685 return;
5686 }
Owen Taylor3473f882001-02-23 17:55:21 +00005687 if (cur->type == XML_ATTRIBUTE_DECL) {
5688 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5689 return;
5690 }
5691 if (cur->type == XML_ENTITY_DECL) {
5692 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5693 return;
5694 }
5695 if (cur->type == XML_TEXT_NODE) {
5696 if (cur->content != NULL) {
5697 if ((cur->name == xmlStringText) ||
5698 (cur->name != xmlStringTextNoenc)) {
5699 xmlChar *buffer;
5700
5701#ifndef XML_USE_BUFFER_CONTENT
5702 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5703#else
5704 buffer = xmlEncodeEntitiesReentrant(doc,
5705 xmlBufferContent(cur->content));
5706#endif
5707 if (buffer != NULL) {
5708 xmlBufferWriteCHAR(buf, buffer);
5709 xmlFree(buffer);
5710 }
5711 } else {
5712 /*
5713 * Disable escaping, needed for XSLT
5714 */
5715#ifndef XML_USE_BUFFER_CONTENT
5716 xmlBufferWriteCHAR(buf, cur->content);
5717#else
5718 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5719#endif
5720 }
5721 }
5722 return;
5723 }
5724 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005725 xmlBufferWriteChar(buf, "<?");
5726 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005727 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005728 xmlBufferWriteChar(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00005729#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard2c748c62002-01-16 15:37:50 +00005730 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005731#else
Daniel Veillard2c748c62002-01-16 15:37:50 +00005732 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00005733#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005734 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00005735 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00005736 return;
5737 }
5738 if (cur->type == XML_COMMENT_NODE) {
5739 if (cur->content != NULL) {
5740 xmlBufferWriteChar(buf, "<!--");
5741#ifndef XML_USE_BUFFER_CONTENT
5742 xmlBufferWriteCHAR(buf, cur->content);
5743#else
5744 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5745#endif
5746 xmlBufferWriteChar(buf, "-->");
5747 }
5748 return;
5749 }
5750 if (cur->type == XML_ENTITY_REF_NODE) {
5751 xmlBufferWriteChar(buf, "&");
5752 xmlBufferWriteCHAR(buf, cur->name);
5753 xmlBufferWriteChar(buf, ";");
5754 return;
5755 }
5756 if (cur->type == XML_CDATA_SECTION_NODE) {
5757 xmlBufferWriteChar(buf, "<![CDATA[");
5758 if (cur->content != NULL)
5759#ifndef XML_USE_BUFFER_CONTENT
5760 xmlBufferWriteCHAR(buf, cur->content);
5761#else
5762 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5763#endif
5764 xmlBufferWriteChar(buf, "]]>");
5765 return;
5766 }
5767
5768 if (format == 1) {
5769 tmp = cur->children;
5770 while (tmp != NULL) {
5771 if ((tmp->type == XML_TEXT_NODE) ||
5772 (tmp->type == XML_ENTITY_REF_NODE)) {
5773 format = 0;
5774 break;
5775 }
5776 tmp = tmp->next;
5777 }
5778 }
5779 xmlBufferWriteChar(buf, "<");
5780 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5781 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5782 xmlBufferWriteChar(buf, ":");
5783 }
5784
5785 xmlBufferWriteCHAR(buf, cur->name);
5786 if (cur->nsDef)
5787 xmlNsListDump(buf, cur->nsDef);
5788 if (cur->properties != NULL)
5789 xmlAttrListDump(buf, doc, cur->properties);
5790
Daniel Veillard7db37732001-07-12 01:20:08 +00005791 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5792 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005793 (!xmlSaveNoEmptyTags)) {
5794 xmlBufferWriteChar(buf, "/>");
5795 return;
5796 }
5797 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005798 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005799 xmlChar *buffer;
5800
5801#ifndef XML_USE_BUFFER_CONTENT
5802 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5803#else
5804 buffer = xmlEncodeEntitiesReentrant(doc,
5805 xmlBufferContent(cur->content));
5806#endif
5807 if (buffer != NULL) {
5808 xmlBufferWriteCHAR(buf, buffer);
5809 xmlFree(buffer);
5810 }
5811 }
5812 if (cur->children != NULL) {
5813 if (format) xmlBufferWriteChar(buf, "\n");
5814 xmlNodeListDump(buf, doc, cur->children,
5815 (level >= 0?level+1:-1), format);
5816 if ((xmlIndentTreeOutput) && (format))
5817 for (i = 0;i < level;i++)
5818 xmlBufferWriteChar(buf, " ");
5819 }
5820 xmlBufferWriteChar(buf, "</");
5821 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5822 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5823 xmlBufferWriteChar(buf, ":");
5824 }
5825
5826 xmlBufferWriteCHAR(buf, cur->name);
5827 xmlBufferWriteChar(buf, ">");
5828}
5829
5830/**
5831 * xmlElemDump:
5832 * @f: the FILE * for the output
5833 * @doc: the document
5834 * @cur: the current node
5835 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005836 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00005837 */
5838void
5839xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5840 xmlBufferPtr buf;
5841
5842 if (cur == NULL) {
5843#ifdef DEBUG_TREE
5844 xmlGenericError(xmlGenericErrorContext,
5845 "xmlElemDump : cur == NULL\n");
5846#endif
5847 return;
5848 }
Owen Taylor3473f882001-02-23 17:55:21 +00005849#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005850 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005851 xmlGenericError(xmlGenericErrorContext,
5852 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005853 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005854#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005855
Owen Taylor3473f882001-02-23 17:55:21 +00005856 buf = xmlBufferCreate();
5857 if (buf == NULL) return;
5858 if ((doc != NULL) &&
5859 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5860#ifdef LIBXML_HTML_ENABLED
5861 htmlNodeDump(buf, doc, cur);
5862#else
5863 xmlGenericError(xmlGenericErrorContext,
5864 "HTML support not compiled in\n");
5865#endif /* LIBXML_HTML_ENABLED */
5866 } else
5867 xmlNodeDump(buf, doc, cur, 0, 1);
5868 xmlBufferDump(f, buf);
5869 xmlBufferFree(buf);
5870}
5871
5872/************************************************************************
5873 * *
5874 * Dumping XML tree content to an I/O output buffer *
5875 * *
5876 ************************************************************************/
5877
5878void
5879xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5880 int level, int format, const char *encoding);
5881static void
5882xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5883 int level, int format, const char *encoding);
5884/**
5885 * xmlNsDumpOutput:
5886 * @buf: the XML buffer output
5887 * @cur: a namespace
5888 *
5889 * Dump a local Namespace definition.
5890 * Should be called in the context of attributes dumps.
5891 */
5892static void
5893xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5894 if (cur == NULL) {
5895#ifdef DEBUG_TREE
5896 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005897 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005898#endif
5899 return;
5900 }
5901 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5902 /* Within the context of an element attributes */
5903 if (cur->prefix != NULL) {
5904 xmlOutputBufferWriteString(buf, " xmlns:");
5905 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5906 } else
5907 xmlOutputBufferWriteString(buf, " xmlns");
5908 xmlOutputBufferWriteString(buf, "=");
5909 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5910 }
5911}
5912
5913/**
5914 * xmlNsListDumpOutput:
5915 * @buf: the XML buffer output
5916 * @cur: the first namespace
5917 *
5918 * Dump a list of local Namespace definitions.
5919 * Should be called in the context of attributes dumps.
5920 */
5921static void
5922xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5923 while (cur != NULL) {
5924 xmlNsDumpOutput(buf, cur);
5925 cur = cur->next;
5926 }
5927}
5928
5929/**
5930 * xmlDtdDumpOutput:
5931 * @buf: the XML buffer output
5932 * @doc: the document
5933 * @encoding: an optional encoding string
5934 *
5935 * Dump the XML document DTD, if any.
5936 */
5937static void
5938xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5939 if (dtd == NULL) {
5940#ifdef DEBUG_TREE
5941 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005942 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005943#endif
5944 return;
5945 }
5946 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5947 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5948 if (dtd->ExternalID != NULL) {
5949 xmlOutputBufferWriteString(buf, " PUBLIC ");
5950 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5951 xmlOutputBufferWriteString(buf, " ");
5952 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5953 } else if (dtd->SystemID != NULL) {
5954 xmlOutputBufferWriteString(buf, " SYSTEM ");
5955 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5956 }
5957 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5958 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5959 xmlOutputBufferWriteString(buf, ">");
5960 return;
5961 }
5962 xmlOutputBufferWriteString(buf, " [\n");
5963 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5964 xmlOutputBufferWriteString(buf, "]>");
5965}
5966
5967/**
5968 * xmlAttrDumpOutput:
5969 * @buf: the XML buffer output
5970 * @doc: the document
5971 * @cur: the attribute pointer
5972 * @encoding: an optional encoding string
5973 *
5974 * Dump an XML attribute
5975 */
5976static void
5977xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005978 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005979 xmlChar *value;
5980
5981 if (cur == NULL) {
5982#ifdef DEBUG_TREE
5983 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005984 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005985#endif
5986 return;
5987 }
5988 xmlOutputBufferWriteString(buf, " ");
5989 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5990 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5991 xmlOutputBufferWriteString(buf, ":");
5992 }
5993 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5994 value = xmlNodeListGetString(doc, cur->children, 0);
5995 if (value) {
5996 xmlOutputBufferWriteString(buf, "=");
5997 xmlBufferWriteQuotedString(buf->buffer, value);
5998 xmlFree(value);
5999 } else {
6000 xmlOutputBufferWriteString(buf, "=\"\"");
6001 }
6002}
6003
6004/**
6005 * xmlAttrListDumpOutput:
6006 * @buf: the XML buffer output
6007 * @doc: the document
6008 * @cur: the first attribute pointer
6009 * @encoding: an optional encoding string
6010 *
6011 * Dump a list of XML attributes
6012 */
6013static void
6014xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6015 xmlAttrPtr cur, const char *encoding) {
6016 if (cur == NULL) {
6017#ifdef DEBUG_TREE
6018 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006019 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006020#endif
6021 return;
6022 }
6023 while (cur != NULL) {
6024 xmlAttrDumpOutput(buf, doc, cur, encoding);
6025 cur = cur->next;
6026 }
6027}
6028
6029
6030
6031/**
6032 * xmlNodeListDumpOutput:
6033 * @buf: the XML buffer output
6034 * @doc: the document
6035 * @cur: the first node
6036 * @level: the imbrication level for indenting
6037 * @format: is formatting allowed
6038 * @encoding: an optional encoding string
6039 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006040 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006041 */
6042static void
6043xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6044 xmlNodePtr cur, int level, int format, const char *encoding) {
6045 int i;
6046
6047 if (cur == NULL) {
6048#ifdef DEBUG_TREE
6049 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006050 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006051#endif
6052 return;
6053 }
6054 while (cur != NULL) {
6055 if ((format) && (xmlIndentTreeOutput) &&
6056 (cur->type == XML_ELEMENT_NODE))
6057 for (i = 0;i < level;i++)
6058 xmlOutputBufferWriteString(buf, " ");
6059 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6060 if (format) {
6061 xmlOutputBufferWriteString(buf, "\n");
6062 }
6063 cur = cur->next;
6064 }
6065}
6066
6067/**
6068 * xmlNodeDumpOutput:
6069 * @buf: the XML buffer output
6070 * @doc: the document
6071 * @cur: the current node
6072 * @level: the imbrication level for indenting
6073 * @format: is formatting allowed
6074 * @encoding: an optional encoding string
6075 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006076 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006077 */
6078void
6079xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6080 int level, int format, const char *encoding) {
6081 int i;
6082 xmlNodePtr tmp;
6083
6084 if (cur == NULL) {
6085#ifdef DEBUG_TREE
6086 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006087 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006088#endif
6089 return;
6090 }
6091 if (cur->type == XML_XINCLUDE_START)
6092 return;
6093 if (cur->type == XML_XINCLUDE_END)
6094 return;
6095 if (cur->type == XML_DTD_NODE) {
6096 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6097 return;
6098 }
6099 if (cur->type == XML_ELEMENT_DECL) {
6100 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6101 return;
6102 }
6103 if (cur->type == XML_ATTRIBUTE_DECL) {
6104 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6105 return;
6106 }
6107 if (cur->type == XML_ENTITY_DECL) {
6108 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6109 return;
6110 }
6111 if (cur->type == XML_TEXT_NODE) {
6112 if (cur->content != NULL) {
6113 if ((cur->name == xmlStringText) ||
6114 (cur->name != xmlStringTextNoenc)) {
6115 xmlChar *buffer;
6116
6117#ifndef XML_USE_BUFFER_CONTENT
6118 if (encoding == NULL)
6119 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6120 else
6121 buffer = xmlEncodeSpecialChars(doc, cur->content);
6122#else
6123 if (encoding == NULL)
6124 buffer = xmlEncodeEntitiesReentrant(doc,
6125 xmlBufferContent(cur->content));
6126 else
6127 buffer = xmlEncodeSpecialChars(doc,
6128 xmlBufferContent(cur->content));
6129#endif
6130 if (buffer != NULL) {
6131 xmlOutputBufferWriteString(buf, (const char *)buffer);
6132 xmlFree(buffer);
6133 }
6134 } else {
6135 /*
6136 * Disable escaping, needed for XSLT
6137 */
6138#ifndef XML_USE_BUFFER_CONTENT
6139 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6140#else
6141 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6142#endif
6143 }
6144 }
6145
6146 return;
6147 }
6148 if (cur->type == XML_PI_NODE) {
6149 if (cur->content != NULL) {
6150 xmlOutputBufferWriteString(buf, "<?");
6151 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6152 if (cur->content != NULL) {
6153 xmlOutputBufferWriteString(buf, " ");
6154#ifndef XML_USE_BUFFER_CONTENT
6155 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6156#else
6157 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6158#endif
6159 }
6160 xmlOutputBufferWriteString(buf, "?>");
6161 } else {
6162 xmlOutputBufferWriteString(buf, "<?");
6163 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6164 xmlOutputBufferWriteString(buf, "?>");
6165 }
6166 return;
6167 }
6168 if (cur->type == XML_COMMENT_NODE) {
6169 if (cur->content != NULL) {
6170 xmlOutputBufferWriteString(buf, "<!--");
6171#ifndef XML_USE_BUFFER_CONTENT
6172 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6173#else
6174 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6175#endif
6176 xmlOutputBufferWriteString(buf, "-->");
6177 }
6178 return;
6179 }
6180 if (cur->type == XML_ENTITY_REF_NODE) {
6181 xmlOutputBufferWriteString(buf, "&");
6182 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6183 xmlOutputBufferWriteString(buf, ";");
6184 return;
6185 }
6186 if (cur->type == XML_CDATA_SECTION_NODE) {
6187 xmlOutputBufferWriteString(buf, "<![CDATA[");
6188 if (cur->content != NULL)
6189#ifndef XML_USE_BUFFER_CONTENT
6190 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6191#else
6192 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6193#endif
6194 xmlOutputBufferWriteString(buf, "]]>");
6195 return;
6196 }
6197
6198 if (format == 1) {
6199 tmp = cur->children;
6200 while (tmp != NULL) {
6201 if ((tmp->type == XML_TEXT_NODE) ||
6202 (tmp->type == XML_ENTITY_REF_NODE)) {
6203 format = 0;
6204 break;
6205 }
6206 tmp = tmp->next;
6207 }
6208 }
6209 xmlOutputBufferWriteString(buf, "<");
6210 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6211 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6212 xmlOutputBufferWriteString(buf, ":");
6213 }
6214
6215 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6216 if (cur->nsDef)
6217 xmlNsListDumpOutput(buf, cur->nsDef);
6218 if (cur->properties != NULL)
6219 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6220
Daniel Veillard7db37732001-07-12 01:20:08 +00006221 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6222 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006223 xmlOutputBufferWriteString(buf, "/>");
6224 return;
6225 }
6226 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006227 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006228 xmlChar *buffer;
6229
6230#ifndef XML_USE_BUFFER_CONTENT
6231 if (encoding == NULL)
6232 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6233 else
6234 buffer = xmlEncodeSpecialChars(doc, cur->content);
6235#else
6236 if (encoding == NULL)
6237 buffer = xmlEncodeEntitiesReentrant(doc,
6238 xmlBufferContent(cur->content));
6239 else
6240 buffer = xmlEncodeSpecialChars(doc,
6241 xmlBufferContent(cur->content));
6242#endif
6243 if (buffer != NULL) {
6244 xmlOutputBufferWriteString(buf, (const char *)buffer);
6245 xmlFree(buffer);
6246 }
6247 }
6248 if (cur->children != NULL) {
6249 if (format) xmlOutputBufferWriteString(buf, "\n");
6250 xmlNodeListDumpOutput(buf, doc, cur->children,
6251 (level >= 0?level+1:-1), format, encoding);
6252 if ((xmlIndentTreeOutput) && (format))
6253 for (i = 0;i < level;i++)
6254 xmlOutputBufferWriteString(buf, " ");
6255 }
6256 xmlOutputBufferWriteString(buf, "</");
6257 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6258 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6259 xmlOutputBufferWriteString(buf, ":");
6260 }
6261
6262 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6263 xmlOutputBufferWriteString(buf, ">");
6264}
6265
6266/**
6267 * xmlDocContentDumpOutput:
6268 * @buf: the XML buffer output
6269 * @cur: the document
6270 * @encoding: an optional encoding string
6271 * @format: should formatting spaces been added
6272 *
6273 * Dump an XML document.
6274 */
6275static void
6276xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6277 const char *encoding, int format) {
6278 xmlOutputBufferWriteString(buf, "<?xml version=");
6279 if (cur->version != NULL)
6280 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6281 else
6282 xmlOutputBufferWriteString(buf, "\"1.0\"");
6283 if (encoding == NULL) {
6284 if (cur->encoding != NULL)
6285 encoding = (const char *) cur->encoding;
6286 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6287 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6288 }
6289 if (encoding != NULL) {
6290 xmlOutputBufferWriteString(buf, " encoding=");
6291 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6292 }
6293 switch (cur->standalone) {
6294 case 0:
6295 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6296 break;
6297 case 1:
6298 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6299 break;
6300 }
6301 xmlOutputBufferWriteString(buf, "?>\n");
6302 if (cur->children != NULL) {
6303 xmlNodePtr child = cur->children;
6304
6305 while (child != NULL) {
6306 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6307 xmlOutputBufferWriteString(buf, "\n");
6308 child = child->next;
6309 }
6310 }
6311}
6312
6313/************************************************************************
6314 * *
6315 * Saving functions front-ends *
6316 * *
6317 ************************************************************************/
6318
6319/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006320 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006321 * @out_doc: Document to generate XML text from
6322 * @doc_txt_ptr: Memory pointer for allocated XML text
6323 * @doc_txt_len: Length of the generated XML text
6324 * @txt_encoding: Character encoding to use when generating XML text
6325 * @format: should formatting spaces been added
6326 *
6327 * Dump the current DOM tree into memory using the character encoding specified
6328 * by the caller. Note it is up to the caller of this function to free the
6329 * allocated memory.
6330 */
6331
6332void
6333xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006334 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006335 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006336 int dummy = 0;
6337
6338 xmlCharEncoding doc_charset;
6339 xmlOutputBufferPtr out_buff = NULL;
6340 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6341
6342 if (doc_txt_len == NULL) {
6343 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6344 }
6345
6346 if (doc_txt_ptr == NULL) {
6347 *doc_txt_len = 0;
6348 xmlGenericError(xmlGenericErrorContext,
6349 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6350 return;
6351 }
6352
6353 *doc_txt_ptr = NULL;
6354 *doc_txt_len = 0;
6355
6356 if (out_doc == NULL) {
6357 /* No document, no output */
6358 xmlGenericError(xmlGenericErrorContext,
6359 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6360 return;
6361 }
6362
6363 /*
6364 * Validate the encoding value, if provided.
6365 * This logic is copied from xmlSaveFileEnc.
6366 */
6367
6368 if (txt_encoding == NULL)
6369 txt_encoding = (const char *) out_doc->encoding;
6370 if (txt_encoding != NULL) {
6371 doc_charset = xmlParseCharEncoding(txt_encoding);
6372
6373 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6374 xmlGenericError(xmlGenericErrorContext,
6375 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6376 return;
6377
6378 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6379 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6380 if ( conv_hdlr == NULL ) {
6381 xmlGenericError(xmlGenericErrorContext,
6382 "%s: %s %s '%s'\n",
6383 "xmlDocDumpFormatMemoryEnc",
6384 "Failed to identify encoding handler for",
6385 "character set",
6386 txt_encoding);
6387 return;
6388 }
6389 }
6390 }
6391
6392 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6393 xmlGenericError(xmlGenericErrorContext,
6394 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6395 return;
6396 }
6397
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006398 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006399 xmlOutputBufferFlush(out_buff);
6400 if (out_buff->conv != NULL) {
6401 *doc_txt_len = out_buff->conv->use;
6402 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6403 } else {
6404 *doc_txt_len = out_buff->buffer->use;
6405 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6406 }
6407 (void)xmlOutputBufferClose(out_buff);
6408
6409 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6410 *doc_txt_len = 0;
6411 xmlGenericError(xmlGenericErrorContext,
6412 "xmlDocDumpFormatMemoryEnc: %s\n",
6413 "Failed to allocate memory for document text representation.");
6414 }
6415
6416 return;
6417}
6418
6419/**
6420 * xmlDocDumpMemory:
6421 * @cur: the document
6422 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006423 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006424 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006425 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006426 * It's up to the caller to free the memory.
6427 */
6428void
6429xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6430 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6431}
6432
6433/**
6434 * xmlDocDumpFormatMemory:
6435 * @cur: the document
6436 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006437 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006438 * @format: should formatting spaces been added
6439 *
6440 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006441 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006442 * It's up to the caller to free the memory.
6443 */
6444void
6445xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6446 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6447}
6448
6449/**
6450 * xmlDocDumpMemoryEnc:
6451 * @out_doc: Document to generate XML text from
6452 * @doc_txt_ptr: Memory pointer for allocated XML text
6453 * @doc_txt_len: Length of the generated XML text
6454 * @txt_encoding: Character encoding to use when generating XML text
6455 *
6456 * Dump the current DOM tree into memory using the character encoding specified
6457 * by the caller. Note it is up to the caller of this function to free the
6458 * allocated memory.
6459 */
6460
6461void
6462xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6463 int * doc_txt_len, const char * txt_encoding) {
6464 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006465 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006466}
6467
6468/**
6469 * xmlGetDocCompressMode:
6470 * @doc: the document
6471 *
6472 * get the compression ratio for a document, ZLIB based
6473 * Returns 0 (uncompressed) to 9 (max compression)
6474 */
6475int
6476xmlGetDocCompressMode (xmlDocPtr doc) {
6477 if (doc == NULL) return(-1);
6478 return(doc->compression);
6479}
6480
6481/**
6482 * xmlSetDocCompressMode:
6483 * @doc: the document
6484 * @mode: the compression ratio
6485 *
6486 * set the compression ratio for a document, ZLIB based
6487 * Correct values: 0 (uncompressed) to 9 (max compression)
6488 */
6489void
6490xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6491 if (doc == NULL) return;
6492 if (mode < 0) doc->compression = 0;
6493 else if (mode > 9) doc->compression = 9;
6494 else doc->compression = mode;
6495}
6496
6497/**
6498 * xmlGetCompressMode:
6499 *
6500 * get the default compression mode used, ZLIB based.
6501 * Returns 0 (uncompressed) to 9 (max compression)
6502 */
6503int
6504 xmlGetCompressMode(void) {
6505 return(xmlCompressMode);
6506}
6507
6508/**
6509 * xmlSetCompressMode:
6510 * @mode: the compression ratio
6511 *
6512 * set the default compression mode used, ZLIB based
6513 * Correct values: 0 (uncompressed) to 9 (max compression)
6514 */
6515void
6516xmlSetCompressMode(int mode) {
6517 if (mode < 0) xmlCompressMode = 0;
6518 else if (mode > 9) xmlCompressMode = 9;
6519 else xmlCompressMode = mode;
6520}
6521
6522/**
6523 * xmlDocDump:
6524 * @f: the FILE*
6525 * @cur: the document
6526 *
6527 * Dump an XML document to an open FILE.
6528 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006529 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006530 */
6531int
6532xmlDocDump(FILE *f, xmlDocPtr cur) {
6533 xmlOutputBufferPtr buf;
6534 const char * encoding;
6535 xmlCharEncodingHandlerPtr handler = NULL;
6536 int ret;
6537
6538 if (cur == NULL) {
6539#ifdef DEBUG_TREE
6540 xmlGenericError(xmlGenericErrorContext,
6541 "xmlDocDump : document == NULL\n");
6542#endif
6543 return(-1);
6544 }
6545 encoding = (const char *) cur->encoding;
6546
6547 if (encoding != NULL) {
6548 xmlCharEncoding enc;
6549
6550 enc = xmlParseCharEncoding(encoding);
6551
6552 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6553 xmlGenericError(xmlGenericErrorContext,
6554 "xmlDocDump: document not in UTF8\n");
6555 return(-1);
6556 }
6557 if (enc != XML_CHAR_ENCODING_UTF8) {
6558 handler = xmlFindCharEncodingHandler(encoding);
6559 if (handler == NULL) {
6560 xmlFree((char *) cur->encoding);
6561 cur->encoding = NULL;
6562 }
6563 }
6564 }
6565 buf = xmlOutputBufferCreateFile(f, handler);
6566 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006567 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006568
6569 ret = xmlOutputBufferClose(buf);
6570 return(ret);
6571}
6572
6573/**
6574 * xmlSaveFileTo:
6575 * @buf: an output I/O buffer
6576 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006577 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006578 *
6579 * Dump an XML document to an I/O buffer.
6580 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006581 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006582 */
6583int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006584xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006585 int ret;
6586
6587 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006588 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006589 ret = xmlOutputBufferClose(buf);
6590 return(ret);
6591}
6592
6593/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006594 * xmlSaveFormatFileTo:
6595 * @buf: an output I/O buffer
6596 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006597 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006598 * @format: should formatting spaces been added
6599 *
6600 * Dump an XML document to an I/O buffer.
6601 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006602 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006603 */
6604int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006605xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006606 int ret;
6607
6608 if (buf == NULL) return(0);
6609 xmlDocContentDumpOutput(buf, cur, encoding, format);
6610 ret = xmlOutputBufferClose(buf);
6611 return(ret);
6612}
6613
6614/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006615 * xmlSaveFormatFileEnc
6616 * @filename: the filename or URL to output
6617 * @cur: the document being saved
6618 * @encoding: the name of the encoding to use or NULL.
6619 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006620 *
6621 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006622 */
6623int
Daniel Veillardf012a642001-07-23 19:10:52 +00006624xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6625 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006626 xmlOutputBufferPtr buf;
6627 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006628 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006629 int ret;
6630
Daniel Veillardfb25a512002-01-13 20:32:08 +00006631 if (encoding == NULL)
6632 encoding = (const char *) cur->encoding;
6633
Owen Taylor3473f882001-02-23 17:55:21 +00006634 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006635
6636 enc = xmlParseCharEncoding(encoding);
6637 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6638 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006639 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006640 return(-1);
6641 }
6642 if (enc != XML_CHAR_ENCODING_UTF8) {
6643 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006644 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006645 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006646 }
6647 }
6648
Daniel Veillardf012a642001-07-23 19:10:52 +00006649#ifdef HAVE_ZLIB_H
6650 if (cur->compression < 0) cur->compression = xmlCompressMode;
6651#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006652 /*
6653 * save the content to a temp buffer.
6654 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006655 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006656 if (buf == NULL) return(-1);
6657
Daniel Veillardf012a642001-07-23 19:10:52 +00006658 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006659
6660 ret = xmlOutputBufferClose(buf);
6661 return(ret);
6662}
6663
Daniel Veillardf012a642001-07-23 19:10:52 +00006664
6665/**
6666 * xmlSaveFileEnc:
6667 * @filename: the filename (or URL)
6668 * @cur: the document
6669 * @encoding: the name of an encoding (or NULL)
6670 *
6671 * Dump an XML document, converting it to the given encoding
6672 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006673 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006674 */
6675int
6676xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6677 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6678}
6679
Owen Taylor3473f882001-02-23 17:55:21 +00006680/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006681 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006682 * @filename: the filename (or URL)
6683 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006684 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006685 *
6686 * Dump an XML document to a file. Will use compression if
6687 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006688 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006689 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006690 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006691 */
6692int
Daniel Veillard67fee942001-04-26 18:59:03 +00006693xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006694 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006695}
6696
Daniel Veillard67fee942001-04-26 18:59:03 +00006697/**
6698 * xmlSaveFile:
6699 * @filename: the filename (or URL)
6700 * @cur: the document
6701 *
6702 * Dump an XML document to a file. Will use compression if
6703 * compiled in and enabled. If @filename is "-" the stdout file is
6704 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006705 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006706 */
6707int
6708xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006709 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006710}
6711