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