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