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