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