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