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