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