blob: 12cc9a47ecfbec5902f9f9ac32bf3f79f25f4ad0 [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);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000216 MEM_CLEANUP(cur, sizeof(xmlNs));
Owen Taylor3473f882001-02-23 17:55:21 +0000217 xmlFree(cur);
218}
219
220/**
221 * xmlFreeNsList:
222 * @cur: the first namespace pointer
223 *
224 * Free up all the structures associated to the chained namespaces.
225 */
226void
227xmlFreeNsList(xmlNsPtr cur) {
228 xmlNsPtr next;
229 if (cur == NULL) {
230#ifdef DEBUG_TREE
231 xmlGenericError(xmlGenericErrorContext,
232 "xmlFreeNsList : ns == NULL\n");
233#endif
234 return;
235 }
236 while (cur != NULL) {
237 next = cur->next;
238 xmlFreeNs(cur);
239 cur = next;
240 }
241}
242
243/**
244 * xmlNewDtd:
245 * @doc: the document pointer
246 * @name: the DTD name
247 * @ExternalID: the external ID
248 * @SystemID: the system ID
249 *
250 * Creation of a new DTD for the external subset. To create an
251 * internal subset, use xmlCreateIntSubset().
252 *
253 * Returns a pointer to the new DTD structure
254 */
255xmlDtdPtr
256xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
257 const xmlChar *ExternalID, const xmlChar *SystemID) {
258 xmlDtdPtr cur;
259
260 if ((doc != NULL) && (doc->extSubset != NULL)) {
261#ifdef DEBUG_TREE
262 xmlGenericError(xmlGenericErrorContext,
263 "xmlNewDtd(%s): document %s already have a DTD %s\n",
264 /* !!! */ (char *) name, doc->name,
265 /* !!! */ (char *)doc->extSubset->name);
266#endif
267 return(NULL);
268 }
269
270 /*
271 * Allocate a new DTD and fill the fields.
272 */
273 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
274 if (cur == NULL) {
275 xmlGenericError(xmlGenericErrorContext,
276 "xmlNewDtd : malloc failed\n");
277 return(NULL);
278 }
279 memset(cur, 0 , sizeof(xmlDtd));
280 cur->type = XML_DTD_NODE;
281
282 if (name != NULL)
283 cur->name = xmlStrdup(name);
284 if (ExternalID != NULL)
285 cur->ExternalID = xmlStrdup(ExternalID);
286 if (SystemID != NULL)
287 cur->SystemID = xmlStrdup(SystemID);
288 if (doc != NULL)
289 doc->extSubset = cur;
290 cur->doc = doc;
291
292 return(cur);
293}
294
295/**
296 * xmlGetIntSubset:
297 * @doc: the document pointer
298 *
299 * Get the internal subset of a document
300 * Returns a pointer to the DTD structure or NULL if not found
301 */
302
303xmlDtdPtr
304xmlGetIntSubset(xmlDocPtr doc) {
305 xmlNodePtr cur;
306
307 if (doc == NULL)
308 return(NULL);
309 cur = doc->children;
310 while (cur != NULL) {
311 if (cur->type == XML_DTD_NODE)
312 return((xmlDtdPtr) cur);
313 cur = cur->next;
314 }
315 return((xmlDtdPtr) doc->intSubset);
316}
317
318/**
319 * xmlCreateIntSubset:
320 * @doc: the document pointer
321 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000322 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000323 * @SystemID: the system ID
324 *
325 * Create the internal subset of a document
326 * Returns a pointer to the new DTD structure
327 */
328xmlDtdPtr
329xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
330 const xmlChar *ExternalID, const xmlChar *SystemID) {
331 xmlDtdPtr cur;
332
333 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
334#ifdef DEBUG_TREE
335 xmlGenericError(xmlGenericErrorContext,
336
337 "xmlCreateIntSubset(): document %s already have an internal subset\n",
338 doc->name);
339#endif
340 return(NULL);
341 }
342
343 /*
344 * Allocate a new DTD and fill the fields.
345 */
346 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
347 if (cur == NULL) {
348 xmlGenericError(xmlGenericErrorContext,
349 "xmlNewDtd : malloc failed\n");
350 return(NULL);
351 }
352 memset(cur, 0, sizeof(xmlDtd));
353 cur->type = XML_DTD_NODE;
354
355 if (name != NULL)
356 cur->name = xmlStrdup(name);
357 if (ExternalID != NULL)
358 cur->ExternalID = xmlStrdup(ExternalID);
359 if (SystemID != NULL)
360 cur->SystemID = xmlStrdup(SystemID);
361 if (doc != NULL) {
362 doc->intSubset = cur;
363 cur->parent = doc;
364 cur->doc = doc;
365 if (doc->children == NULL) {
366 doc->children = (xmlNodePtr) cur;
367 doc->last = (xmlNodePtr) cur;
368 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000369 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000370 xmlNodePtr prev;
371
Owen Taylor3473f882001-02-23 17:55:21 +0000372 prev = doc->children;
373 prev->prev = (xmlNodePtr) cur;
374 cur->next = prev;
375 doc->children = (xmlNodePtr) cur;
376 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000377 xmlNodePtr next;
378
379 next = doc->children;
380 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
381 next = next->next;
382 if (next == NULL) {
383 cur->prev = doc->last;
384 cur->prev->next = (xmlNodePtr) cur;
385 cur->next = NULL;
386 doc->last = (xmlNodePtr) cur;
387 } else {
388 cur->next = next;
389 cur->prev = next->prev;
390 if (cur->prev == NULL)
391 doc->children = (xmlNodePtr) cur;
392 else
393 cur->prev->next = (xmlNodePtr) cur;
394 next->prev = (xmlNodePtr) cur;
395 }
Owen Taylor3473f882001-02-23 17:55:21 +0000396 }
397 }
398 }
399 return(cur);
400}
401
402/**
403 * xmlFreeDtd:
404 * @cur: the DTD structure to free up
405 *
406 * Free a DTD structure.
407 */
408void
409xmlFreeDtd(xmlDtdPtr cur) {
410 if (cur == NULL) {
411#ifdef DEBUG_TREE
412 xmlGenericError(xmlGenericErrorContext,
413 "xmlFreeDtd : DTD == NULL\n");
414#endif
415 return;
416 }
417 if (cur->children != NULL) {
418 xmlNodePtr next, c = cur->children;
419
420 /*
421 * Cleanup all the DTD comments they are not in the Dtd
422 * indexes.
423 */
424 while (c != NULL) {
425 next = c->next;
426 if (c->type == XML_COMMENT_NODE) {
427 xmlUnlinkNode(c);
428 xmlFreeNode(c);
429 }
430 c = next;
431 }
432 }
433 if (cur->name != NULL) xmlFree((char *) cur->name);
434 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
435 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
436 /* TODO !!! */
437 if (cur->notations != NULL)
438 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
439
440 if (cur->elements != NULL)
441 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
442 if (cur->attributes != NULL)
443 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
444 if (cur->entities != NULL)
445 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
446 if (cur->pentities != NULL)
447 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
448
Daniel Veillard48b2f892001-02-25 16:11:03 +0000449 MEM_CLEANUP(cur, sizeof(xmlDtd));
Owen Taylor3473f882001-02-23 17:55:21 +0000450 xmlFree(cur);
451}
452
453/**
454 * xmlNewDoc:
455 * @version: xmlChar string giving the version of XML "1.0"
456 *
457 * Returns a new document
458 */
459xmlDocPtr
460xmlNewDoc(const xmlChar *version) {
461 xmlDocPtr cur;
462
463 if (version == NULL)
464 version = (const xmlChar *) "1.0";
465
466 /*
467 * Allocate a new document and fill the fields.
468 */
469 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
470 if (cur == NULL) {
471 xmlGenericError(xmlGenericErrorContext,
472 "xmlNewDoc : malloc failed\n");
473 return(NULL);
474 }
475 memset(cur, 0, sizeof(xmlDoc));
476 cur->type = XML_DOCUMENT_NODE;
477
478 cur->version = xmlStrdup(version);
479 cur->standalone = -1;
480 cur->compression = -1; /* not initialized */
481 cur->doc = cur;
482 return(cur);
483}
484
485/**
486 * xmlFreeDoc:
487 * @cur: pointer to the document
488 * @:
489 *
490 * Free up all the structures used by a document, tree included.
491 */
492void
493xmlFreeDoc(xmlDocPtr cur) {
494 if (cur == NULL) {
495#ifdef DEBUG_TREE
496 xmlGenericError(xmlGenericErrorContext,
497 "xmlFreeDoc : document == NULL\n");
498#endif
499 return;
500 }
501 if (cur->version != NULL) xmlFree((char *) cur->version);
502 if (cur->name != NULL) xmlFree((char *) cur->name);
503 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
504 if (cur->children != NULL) xmlFreeNodeList(cur->children);
505 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
506 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
507 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
508 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
509 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
510 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000511 MEM_CLEANUP(cur, sizeof(xmlDoc));
Owen Taylor3473f882001-02-23 17:55:21 +0000512 xmlFree(cur);
513}
514
515/**
516 * xmlStringLenGetNodeList:
517 * @doc: the document
518 * @value: the value of the text
519 * @len: the length of the string value
520 *
521 * Parse the value string and build the node list associated. Should
522 * produce a flat tree with only TEXTs and ENTITY_REFs.
523 * Returns a pointer to the first child
524 */
525xmlNodePtr
526xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
527 xmlNodePtr ret = NULL, last = NULL;
528 xmlNodePtr node;
529 xmlChar *val;
530 const xmlChar *cur = value;
531 const xmlChar *q;
532 xmlEntityPtr ent;
533
534 if (value == NULL) return(NULL);
535
536 q = cur;
537 while ((*cur != 0) && (cur - value < len)) {
538 if (*cur == '&') {
539 /*
540 * Save the current text.
541 */
542 if (cur != q) {
543 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
544 xmlNodeAddContentLen(last, q, cur - q);
545 } else {
546 node = xmlNewDocTextLen(doc, q, cur - q);
547 if (node == NULL) return(ret);
548 if (last == NULL)
549 last = ret = node;
550 else {
551 last->next = node;
552 node->prev = last;
553 last = node;
554 }
555 }
556 }
557 /*
558 * Read the entity string
559 */
560 cur++;
561 q = cur;
562 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
563 if ((*cur == 0) || (cur - value >= len)) {
564#ifdef DEBUG_TREE
565 xmlGenericError(xmlGenericErrorContext,
566 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
567#endif
568 return(ret);
569 }
570 if (cur != q) {
571 /*
572 * Predefined entities don't generate nodes
573 */
574 val = xmlStrndup(q, cur - q);
575 ent = xmlGetDocEntity(doc, val);
576 if ((ent != NULL) &&
577 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
578 if (last == NULL) {
579 node = xmlNewDocText(doc, ent->content);
580 last = ret = node;
581 } else
582 xmlNodeAddContent(last, ent->content);
583
584 } else {
585 /*
586 * Create a new REFERENCE_REF node
587 */
588 node = xmlNewReference(doc, val);
589 if (node == NULL) {
590 if (val != NULL) xmlFree(val);
591 return(ret);
592 }
593 if (last == NULL)
594 last = ret = node;
595 else {
596 last->next = node;
597 node->prev = last;
598 last = node;
599 }
600 }
601 xmlFree(val);
602 }
603 cur++;
604 q = cur;
605 } else
606 cur++;
607 }
608 if (cur != q) {
609 /*
610 * Handle the last piece of text.
611 */
612 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
613 xmlNodeAddContentLen(last, q, cur - q);
614 } else {
615 node = xmlNewDocTextLen(doc, q, cur - q);
616 if (node == NULL) return(ret);
617 if (last == NULL)
618 last = ret = node;
619 else {
620 last->next = node;
621 node->prev = last;
622 last = node;
623 }
624 }
625 }
626 return(ret);
627}
628
629/**
630 * xmlStringGetNodeList:
631 * @doc: the document
632 * @value: the value of the attribute
633 *
634 * Parse the value string and build the node list associated. Should
635 * produce a flat tree with only TEXTs and ENTITY_REFs.
636 * Returns a pointer to the first child
637 */
638xmlNodePtr
639xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
640 xmlNodePtr ret = NULL, last = NULL;
641 xmlNodePtr node;
642 xmlChar *val;
643 const xmlChar *cur = value;
644 const xmlChar *q;
645 xmlEntityPtr ent;
646
647 if (value == NULL) return(NULL);
648
649 q = cur;
650 while (*cur != 0) {
651 if (*cur == '&') {
652 /*
653 * Save the current text.
654 */
655 if (cur != q) {
656 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
657 xmlNodeAddContentLen(last, q, cur - q);
658 } else {
659 node = xmlNewDocTextLen(doc, q, cur - q);
660 if (node == NULL) return(ret);
661 if (last == NULL)
662 last = ret = node;
663 else {
664 last->next = node;
665 node->prev = last;
666 last = node;
667 }
668 }
669 }
670 /*
671 * Read the entity string
672 */
673 cur++;
674 q = cur;
675 while ((*cur != 0) && (*cur != ';')) cur++;
676 if (*cur == 0) {
677#ifdef DEBUG_TREE
678 xmlGenericError(xmlGenericErrorContext,
679 "xmlStringGetNodeList: unterminated entity %30s\n", q);
680#endif
681 return(ret);
682 }
683 if (cur != q) {
684 /*
685 * Predefined entities don't generate nodes
686 */
687 val = xmlStrndup(q, cur - q);
688 ent = xmlGetDocEntity(doc, val);
689 if ((ent != NULL) &&
690 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
691 if (last == NULL) {
692 node = xmlNewDocText(doc, ent->content);
693 last = ret = node;
694 } else
695 xmlNodeAddContent(last, ent->content);
696
697 } else {
698 /*
699 * Create a new REFERENCE_REF node
700 */
701 node = xmlNewReference(doc, val);
702 if (node == NULL) {
703 if (val != NULL) xmlFree(val);
704 return(ret);
705 }
706 if (last == NULL)
707 last = ret = node;
708 else {
709 last->next = node;
710 node->prev = last;
711 last = node;
712 }
713 }
714 xmlFree(val);
715 }
716 cur++;
717 q = cur;
718 } else
719 cur++;
720 }
721 if (cur != q) {
722 /*
723 * Handle the last piece of text.
724 */
725 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
726 xmlNodeAddContentLen(last, q, cur - q);
727 } else {
728 node = xmlNewDocTextLen(doc, q, cur - q);
729 if (node == NULL) return(ret);
730 if (last == NULL)
731 last = ret = node;
732 else {
733 last->next = node;
734 node->prev = last;
735 last = node;
736 }
737 }
738 }
739 return(ret);
740}
741
742/**
743 * xmlNodeListGetString:
744 * @doc: the document
745 * @list: a Node list
746 * @inLine: should we replace entity contents or show their external form
747 *
748 * Returns the string equivalent to the text contained in the Node list
749 * made of TEXTs and ENTITY_REFs
750 * Returns a pointer to the string copy, the calller must free it.
751 */
752xmlChar *
753xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
754 xmlNodePtr node = list;
755 xmlChar *ret = NULL;
756 xmlEntityPtr ent;
757
758 if (list == NULL) return(NULL);
759
760 while (node != NULL) {
761 if ((node->type == XML_TEXT_NODE) ||
762 (node->type == XML_CDATA_SECTION_NODE)) {
763 if (inLine) {
764#ifndef XML_USE_BUFFER_CONTENT
765 ret = xmlStrcat(ret, node->content);
766#else
767 ret = xmlStrcat(ret, xmlBufferContent(node->content));
768#endif
769 } else {
770 xmlChar *buffer;
771
772#ifndef XML_USE_BUFFER_CONTENT
773 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
774#else
775 buffer = xmlEncodeEntitiesReentrant(doc,
776 xmlBufferContent(node->content));
777#endif
778 if (buffer != NULL) {
779 ret = xmlStrcat(ret, buffer);
780 xmlFree(buffer);
781 }
782 }
783 } else if (node->type == XML_ENTITY_REF_NODE) {
784 if (inLine) {
785 ent = xmlGetDocEntity(doc, node->name);
786 if (ent != NULL)
787 ret = xmlStrcat(ret, ent->content);
788 else {
789#ifndef XML_USE_BUFFER_CONTENT
790 ret = xmlStrcat(ret, node->content);
791#else
792 ret = xmlStrcat(ret, xmlBufferContent(node->content));
793#endif
794 }
795 } else {
796 xmlChar buf[2];
797 buf[0] = '&'; buf[1] = 0;
798 ret = xmlStrncat(ret, buf, 1);
799 ret = xmlStrcat(ret, node->name);
800 buf[0] = ';'; buf[1] = 0;
801 ret = xmlStrncat(ret, buf, 1);
802 }
803 }
804#if 0
805 else {
806 xmlGenericError(xmlGenericErrorContext,
807 "xmlGetNodeListString : invalide node type %d\n",
808 node->type);
809 }
810#endif
811 node = node->next;
812 }
813 return(ret);
814}
815
816/**
817 * xmlNodeListGetRawString:
818 * @doc: the document
819 * @list: a Node list
820 * @inLine: should we replace entity contents or show their external form
821 *
822 * Returns the string equivalent to the text contained in the Node list
823 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
824 * this function doesn't do any character encoding handling.
825 *
826 * Returns a pointer to the string copy, the calller must free it.
827 */
828xmlChar *
829xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
830 xmlNodePtr node = list;
831 xmlChar *ret = NULL;
832 xmlEntityPtr ent;
833
834 if (list == NULL) return(NULL);
835
836 while (node != NULL) {
837 if (node->type == XML_TEXT_NODE) {
838 if (inLine) {
839#ifndef XML_USE_BUFFER_CONTENT
840 ret = xmlStrcat(ret, node->content);
841#else
842 ret = xmlStrcat(ret, xmlBufferContent(node->content));
843#endif
844 } else {
845 xmlChar *buffer;
846
847#ifndef XML_USE_BUFFER_CONTENT
848 buffer = xmlEncodeSpecialChars(doc, node->content);
849#else
850 buffer = xmlEncodeSpecialChars(doc,
851 xmlBufferContent(node->content));
852#endif
853 if (buffer != NULL) {
854 ret = xmlStrcat(ret, buffer);
855 xmlFree(buffer);
856 }
857 }
858 } else if (node->type == XML_ENTITY_REF_NODE) {
859 if (inLine) {
860 ent = xmlGetDocEntity(doc, node->name);
861 if (ent != NULL)
862 ret = xmlStrcat(ret, ent->content);
863 else {
864#ifndef XML_USE_BUFFER_CONTENT
865 ret = xmlStrcat(ret, node->content);
866#else
867 ret = xmlStrcat(ret, xmlBufferContent(node->content));
868#endif
869 }
870 } else {
871 xmlChar buf[2];
872 buf[0] = '&'; buf[1] = 0;
873 ret = xmlStrncat(ret, buf, 1);
874 ret = xmlStrcat(ret, node->name);
875 buf[0] = ';'; buf[1] = 0;
876 ret = xmlStrncat(ret, buf, 1);
877 }
878 }
879#if 0
880 else {
881 xmlGenericError(xmlGenericErrorContext,
882 "xmlGetNodeListString : invalide node type %d\n",
883 node->type);
884 }
885#endif
886 node = node->next;
887 }
888 return(ret);
889}
890
891/**
892 * xmlNewProp:
893 * @node: the holding node
894 * @name: the name of the attribute
895 * @value: the value of the attribute
896 *
897 * Create a new property carried by a node.
898 * Returns a pointer to the attribute
899 */
900xmlAttrPtr
901xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
902 xmlAttrPtr cur;
903 xmlDocPtr doc = NULL;
904
905 if (name == NULL) {
906#ifdef DEBUG_TREE
907 xmlGenericError(xmlGenericErrorContext,
908 "xmlNewProp : name == NULL\n");
909#endif
910 return(NULL);
911 }
912
913 /*
914 * Allocate a new property and fill the fields.
915 */
916 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
917 if (cur == NULL) {
918 xmlGenericError(xmlGenericErrorContext,
919 "xmlNewProp : malloc failed\n");
920 return(NULL);
921 }
922 memset(cur, 0, sizeof(xmlAttr));
923 cur->type = XML_ATTRIBUTE_NODE;
924
925 cur->parent = node;
926 if (node != NULL) {
927 doc = node->doc;
928 cur->doc = doc;
929 }
930 cur->name = xmlStrdup(name);
931 if (value != NULL) {
932 xmlChar *buffer;
933 xmlNodePtr tmp;
934
935 buffer = xmlEncodeEntitiesReentrant(doc, value);
936 cur->children = xmlStringGetNodeList(doc, buffer);
937 cur->last = NULL;
938 tmp = cur->children;
939 while (tmp != NULL) {
940 tmp->parent = (xmlNodePtr) cur;
941 tmp->doc = doc;
942 if (tmp->next == NULL)
943 cur->last = tmp;
944 tmp = tmp->next;
945 }
946 xmlFree(buffer);
947 }
948
949 /*
950 * Add it at the end to preserve parsing order ...
951 */
952 if (node != NULL) {
953 if (node->properties == NULL) {
954 node->properties = cur;
955 } else {
956 xmlAttrPtr prev = node->properties;
957
958 while (prev->next != NULL) prev = prev->next;
959 prev->next = cur;
960 cur->prev = prev;
961 }
962 }
963 return(cur);
964}
965
966/**
967 * xmlNewNsProp:
968 * @node: the holding node
969 * @ns: the namespace
970 * @name: the name of the attribute
971 * @value: the value of the attribute
972 *
973 * Create a new property tagged with a namespace and carried by a node.
974 * Returns a pointer to the attribute
975 */
976xmlAttrPtr
977xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
978 const xmlChar *value) {
979 xmlAttrPtr cur;
980
981 if (name == NULL) {
982#ifdef DEBUG_TREE
983 xmlGenericError(xmlGenericErrorContext,
984 "xmlNewProp : name == NULL\n");
985#endif
986 return(NULL);
987 }
988
989 /*
990 * Allocate a new property and fill the fields.
991 */
992 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
993 if (cur == NULL) {
994 xmlGenericError(xmlGenericErrorContext,
995 "xmlNewProp : malloc failed\n");
996 return(NULL);
997 }
998 memset(cur, 0, sizeof(xmlAttr));
999 cur->type = XML_ATTRIBUTE_NODE;
1000
1001 cur->parent = node;
1002 if (node != NULL)
1003 cur->doc = node->doc;
1004 cur->ns = ns;
1005 cur->name = xmlStrdup(name);
1006 if (value != NULL) {
1007 xmlChar *buffer;
1008 xmlNodePtr tmp;
1009
1010 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
1011 cur->children = xmlStringGetNodeList(node->doc, buffer);
1012 cur->last = NULL;
1013 tmp = cur->children;
1014 while (tmp != NULL) {
1015 tmp->parent = (xmlNodePtr) cur;
1016 if (tmp->next == NULL)
1017 cur->last = tmp;
1018 tmp = tmp->next;
1019 }
1020 xmlFree(buffer);
1021 }
1022
1023 /*
1024 * Add it at the end to preserve parsing order ...
1025 */
1026 if (node != NULL) {
1027 if (node->properties == NULL) {
1028 node->properties = cur;
1029 } else {
1030 xmlAttrPtr prev = node->properties;
1031
1032 while (prev->next != NULL) prev = prev->next;
1033 prev->next = cur;
1034 cur->prev = prev;
1035 }
1036 }
1037 return(cur);
1038}
1039
1040/**
1041 * xmlNewDocProp:
1042 * @doc: the document
1043 * @name: the name of the attribute
1044 * @value: the value of the attribute
1045 *
1046 * Create a new property carried by a document.
1047 * Returns a pointer to the attribute
1048 */
1049xmlAttrPtr
1050xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1051 xmlAttrPtr cur;
1052
1053 if (name == NULL) {
1054#ifdef DEBUG_TREE
1055 xmlGenericError(xmlGenericErrorContext,
1056 "xmlNewProp : name == NULL\n");
1057#endif
1058 return(NULL);
1059 }
1060
1061 /*
1062 * Allocate a new property and fill the fields.
1063 */
1064 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1065 if (cur == NULL) {
1066 xmlGenericError(xmlGenericErrorContext,
1067 "xmlNewProp : malloc failed\n");
1068 return(NULL);
1069 }
1070 memset(cur, 0, sizeof(xmlAttr));
1071 cur->type = XML_ATTRIBUTE_NODE;
1072
1073 cur->name = xmlStrdup(name);
1074 cur->doc = doc;
1075 if (value != NULL) {
1076 xmlNodePtr tmp;
1077
1078 cur->children = xmlStringGetNodeList(doc, value);
1079 cur->last = NULL;
1080
1081 tmp = cur->children;
1082 while (tmp != NULL) {
1083 tmp->parent = (xmlNodePtr) cur;
1084 if (tmp->next == NULL)
1085 cur->last = tmp;
1086 tmp = tmp->next;
1087 }
1088 }
1089 return(cur);
1090}
1091
1092/**
1093 * xmlFreePropList:
1094 * @cur: the first property in the list
1095 *
1096 * Free a property and all its siblings, all the children are freed too.
1097 */
1098void
1099xmlFreePropList(xmlAttrPtr cur) {
1100 xmlAttrPtr next;
1101 if (cur == NULL) {
1102#ifdef DEBUG_TREE
1103 xmlGenericError(xmlGenericErrorContext,
1104 "xmlFreePropList : property == NULL\n");
1105#endif
1106 return;
1107 }
1108 while (cur != NULL) {
1109 next = cur->next;
1110 xmlFreeProp(cur);
1111 cur = next;
1112 }
1113}
1114
1115/**
1116 * xmlFreeProp:
1117 * @cur: an attribute
1118 *
1119 * Free one attribute, all the content is freed too
1120 */
1121void
1122xmlFreeProp(xmlAttrPtr cur) {
1123 if (cur == NULL) {
1124#ifdef DEBUG_TREE
1125 xmlGenericError(xmlGenericErrorContext,
1126 "xmlFreeProp : property == NULL\n");
1127#endif
1128 return;
1129 }
1130 /* Check for ID removal -> leading to invalid references ! */
1131 if ((cur->parent != NULL) &&
1132 (xmlIsID(cur->parent->doc, cur->parent, cur)))
1133 xmlRemoveID(cur->parent->doc, cur);
1134 if (cur->name != NULL) xmlFree((char *) cur->name);
1135 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard48b2f892001-02-25 16:11:03 +00001136 MEM_CLEANUP(cur, sizeof(xmlAttr));
Owen Taylor3473f882001-02-23 17:55:21 +00001137 xmlFree(cur);
1138}
1139
1140/**
1141 * xmlRemoveProp:
1142 * @cur: an attribute
1143 *
1144 * Unlink and free one attribute, all the content is freed too
1145 * Note this doesn't work for namespace definition attributes
1146 *
1147 * Returns 0 if success and -1 in case of error.
1148 */
1149int
1150xmlRemoveProp(xmlAttrPtr cur) {
1151 xmlAttrPtr tmp;
1152 if (cur == NULL) {
1153#ifdef DEBUG_TREE
1154 xmlGenericError(xmlGenericErrorContext,
1155 "xmlRemoveProp : cur == NULL\n");
1156#endif
1157 return(-1);
1158 }
1159 if (cur->parent == NULL) {
1160#ifdef DEBUG_TREE
1161 xmlGenericError(xmlGenericErrorContext,
1162 "xmlRemoveProp : cur->parent == NULL\n");
1163#endif
1164 return(-1);
1165 }
1166 tmp = cur->parent->properties;
1167 if (tmp == cur) {
1168 cur->parent->properties = cur->next;
1169 xmlFreeProp(cur);
1170 return(0);
1171 }
1172 while (tmp != NULL) {
1173 if (tmp->next == cur) {
1174 tmp->next = cur->next;
1175 if (tmp->next != NULL)
1176 tmp->next->prev = tmp;
1177 xmlFreeProp(cur);
1178 return(0);
1179 }
1180 tmp = tmp->next;
1181 }
1182#ifdef DEBUG_TREE
1183 xmlGenericError(xmlGenericErrorContext,
1184 "xmlRemoveProp : attribute not owned by its node\n");
1185#endif
1186 return(-1);
1187}
1188
1189/**
1190 * xmlNewPI:
1191 * @name: the processing instruction name
1192 * @content: the PI content
1193 *
1194 * Creation of a processing instruction element.
1195 * Returns a pointer to the new node object.
1196 */
1197xmlNodePtr
1198xmlNewPI(const xmlChar *name, const xmlChar *content) {
1199 xmlNodePtr cur;
1200
1201 if (name == NULL) {
1202#ifdef DEBUG_TREE
1203 xmlGenericError(xmlGenericErrorContext,
1204 "xmlNewPI : name == NULL\n");
1205#endif
1206 return(NULL);
1207 }
1208
1209 /*
1210 * Allocate a new node and fill the fields.
1211 */
1212 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1213 if (cur == NULL) {
1214 xmlGenericError(xmlGenericErrorContext,
1215 "xmlNewPI : malloc failed\n");
1216 return(NULL);
1217 }
1218 memset(cur, 0, sizeof(xmlNode));
1219 cur->type = XML_PI_NODE;
1220
1221 cur->name = xmlStrdup(name);
1222 if (content != NULL) {
1223#ifndef XML_USE_BUFFER_CONTENT
1224 cur->content = xmlStrdup(content);
1225#else
1226 cur->content = xmlBufferCreateSize(0);
1227 xmlBufferSetAllocationScheme(cur->content,
1228 xmlGetBufferAllocationScheme());
1229 xmlBufferAdd(cur->content, content, -1);
1230#endif
1231 }
1232 return(cur);
1233}
1234
1235/**
1236 * xmlNewNode:
1237 * @ns: namespace if any
1238 * @name: the node name
1239 *
1240 * Creation of a new node element. @ns is optionnal (NULL).
1241 *
1242 * Returns a pointer to the new node object.
1243 */
1244xmlNodePtr
1245xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1246 xmlNodePtr cur;
1247
1248 if (name == NULL) {
1249#ifdef DEBUG_TREE
1250 xmlGenericError(xmlGenericErrorContext,
1251 "xmlNewNode : name == NULL\n");
1252#endif
1253 return(NULL);
1254 }
1255
1256 /*
1257 * Allocate a new node and fill the fields.
1258 */
1259 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1260 if (cur == NULL) {
1261 xmlGenericError(xmlGenericErrorContext,
1262 "xmlNewNode : malloc failed\n");
1263 return(NULL);
1264 }
1265 memset(cur, 0, sizeof(xmlNode));
1266 cur->type = XML_ELEMENT_NODE;
1267
1268 cur->name = xmlStrdup(name);
1269 cur->ns = ns;
1270 return(cur);
1271}
1272
1273/**
1274 * xmlNewDocNode:
1275 * @doc: the document
1276 * @ns: namespace if any
1277 * @name: the node name
1278 * @content: the XML text content if any
1279 *
1280 * Creation of a new node element within a document. @ns and @content
1281 * are optionnal (NULL).
1282 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1283 * references, but XML special chars need to be escaped first by using
1284 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1285 * need entities support.
1286 *
1287 * Returns a pointer to the new node object.
1288 */
1289xmlNodePtr
1290xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1291 const xmlChar *name, const xmlChar *content) {
1292 xmlNodePtr cur;
1293
1294 cur = xmlNewNode(ns, name);
1295 if (cur != NULL) {
1296 cur->doc = doc;
1297 if (content != NULL) {
1298 cur->children = xmlStringGetNodeList(doc, content);
1299 UPDATE_LAST_CHILD_AND_PARENT(cur)
1300 }
1301 }
1302 return(cur);
1303}
1304
1305
1306/**
1307 * xmlNewDocRawNode:
1308 * @doc: the document
1309 * @ns: namespace if any
1310 * @name: the node name
1311 * @content: the text content if any
1312 *
1313 * Creation of a new node element within a document. @ns and @content
1314 * are optionnal (NULL).
1315 *
1316 * Returns a pointer to the new node object.
1317 */
1318xmlNodePtr
1319xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1320 const xmlChar *name, const xmlChar *content) {
1321 xmlNodePtr cur;
1322
1323 cur = xmlNewNode(ns, name);
1324 if (cur != NULL) {
1325 cur->doc = doc;
1326 if (content != NULL) {
1327 cur->children = xmlNewDocText(doc, content);
1328 UPDATE_LAST_CHILD_AND_PARENT(cur)
1329 }
1330 }
1331 return(cur);
1332}
1333
1334/**
1335 * xmlNewDocFragment:
1336 * @doc: the document owning the fragment
1337 *
1338 * Creation of a new Fragment node.
1339 * Returns a pointer to the new node object.
1340 */
1341xmlNodePtr
1342xmlNewDocFragment(xmlDocPtr doc) {
1343 xmlNodePtr cur;
1344
1345 /*
1346 * Allocate a new DocumentFragment node and fill the fields.
1347 */
1348 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1349 if (cur == NULL) {
1350 xmlGenericError(xmlGenericErrorContext,
1351 "xmlNewDocFragment : malloc failed\n");
1352 return(NULL);
1353 }
1354 memset(cur, 0, sizeof(xmlNode));
1355 cur->type = XML_DOCUMENT_FRAG_NODE;
1356
1357 cur->doc = doc;
1358 return(cur);
1359}
1360
1361/**
1362 * xmlNewText:
1363 * @content: the text content
1364 *
1365 * Creation of a new text node.
1366 * Returns a pointer to the new node object.
1367 */
1368xmlNodePtr
1369xmlNewText(const xmlChar *content) {
1370 xmlNodePtr cur;
1371
1372 /*
1373 * Allocate a new node and fill the fields.
1374 */
1375 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1376 if (cur == NULL) {
1377 xmlGenericError(xmlGenericErrorContext,
1378 "xmlNewText : malloc failed\n");
1379 return(NULL);
1380 }
1381 memset(cur, 0, sizeof(xmlNode));
1382 cur->type = XML_TEXT_NODE;
1383
1384 cur->name = xmlStringText;
1385 if (content != NULL) {
1386#ifndef XML_USE_BUFFER_CONTENT
1387 cur->content = xmlStrdup(content);
1388#else
1389 cur->content = xmlBufferCreateSize(0);
1390 xmlBufferSetAllocationScheme(cur->content,
1391 xmlGetBufferAllocationScheme());
1392 xmlBufferAdd(cur->content, content, -1);
1393#endif
1394 }
1395 return(cur);
1396}
1397
1398/**
1399 * xmlNewTextChild:
1400 * @parent: the parent node
1401 * @ns: a namespace if any
1402 * @name: the name of the child
1403 * @content: the text content of the child if any.
1404 *
1405 * Creation of a new child element, added at the end of @parent children list.
1406 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1407 * a child TEXT node will be created containing the string content.
1408 *
1409 * Returns a pointer to the new node object.
1410 */
1411xmlNodePtr
1412xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1413 const xmlChar *name, const xmlChar *content) {
1414 xmlNodePtr cur, prev;
1415
1416 if (parent == NULL) {
1417#ifdef DEBUG_TREE
1418 xmlGenericError(xmlGenericErrorContext,
1419 "xmlNewTextChild : parent == NULL\n");
1420#endif
1421 return(NULL);
1422 }
1423
1424 if (name == NULL) {
1425#ifdef DEBUG_TREE
1426 xmlGenericError(xmlGenericErrorContext,
1427 "xmlNewTextChild : name == NULL\n");
1428#endif
1429 return(NULL);
1430 }
1431
1432 /*
1433 * Allocate a new node
1434 */
1435 if (ns == NULL)
1436 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1437 else
1438 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1439 if (cur == NULL) return(NULL);
1440
1441 /*
1442 * add the new element at the end of the children list.
1443 */
1444 cur->type = XML_ELEMENT_NODE;
1445 cur->parent = parent;
1446 cur->doc = parent->doc;
1447 if (parent->children == NULL) {
1448 parent->children = cur;
1449 parent->last = cur;
1450 } else {
1451 prev = parent->last;
1452 prev->next = cur;
1453 cur->prev = prev;
1454 parent->last = cur;
1455 }
1456
1457 return(cur);
1458}
1459
1460/**
1461 * xmlNewCharRef:
1462 * @doc: the document
1463 * @name: the char ref string, starting with # or "&# ... ;"
1464 *
1465 * Creation of a new character reference node.
1466 * Returns a pointer to the new node object.
1467 */
1468xmlNodePtr
1469xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1470 xmlNodePtr cur;
1471
1472 /*
1473 * Allocate a new node and fill the fields.
1474 */
1475 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1476 if (cur == NULL) {
1477 xmlGenericError(xmlGenericErrorContext,
1478 "xmlNewText : malloc failed\n");
1479 return(NULL);
1480 }
1481 memset(cur, 0, sizeof(xmlNode));
1482 cur->type = XML_ENTITY_REF_NODE;
1483
1484 cur->doc = doc;
1485 if (name[0] == '&') {
1486 int len;
1487 name++;
1488 len = xmlStrlen(name);
1489 if (name[len - 1] == ';')
1490 cur->name = xmlStrndup(name, len - 1);
1491 else
1492 cur->name = xmlStrndup(name, len);
1493 } else
1494 cur->name = xmlStrdup(name);
1495 return(cur);
1496}
1497
1498/**
1499 * xmlNewReference:
1500 * @doc: the document
1501 * @name: the reference name, or the reference string with & and ;
1502 *
1503 * Creation of a new reference node.
1504 * Returns a pointer to the new node object.
1505 */
1506xmlNodePtr
1507xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1508 xmlNodePtr cur;
1509 xmlEntityPtr ent;
1510
1511 /*
1512 * Allocate a new node and fill the fields.
1513 */
1514 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1515 if (cur == NULL) {
1516 xmlGenericError(xmlGenericErrorContext,
1517 "xmlNewText : malloc failed\n");
1518 return(NULL);
1519 }
1520 memset(cur, 0, sizeof(xmlNode));
1521 cur->type = XML_ENTITY_REF_NODE;
1522
1523 cur->doc = doc;
1524 if (name[0] == '&') {
1525 int len;
1526 name++;
1527 len = xmlStrlen(name);
1528 if (name[len - 1] == ';')
1529 cur->name = xmlStrndup(name, len - 1);
1530 else
1531 cur->name = xmlStrndup(name, len);
1532 } else
1533 cur->name = xmlStrdup(name);
1534
1535 ent = xmlGetDocEntity(doc, cur->name);
1536 if (ent != NULL) {
1537#ifndef XML_USE_BUFFER_CONTENT
1538 cur->content = ent->content;
1539#else
1540 /*
1541 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1542 * a copy of this pointer. Let's hope we don't manipulate it
1543 * later
1544 */
1545 cur->content = xmlBufferCreateSize(0);
1546 xmlBufferSetAllocationScheme(cur->content,
1547 xmlGetBufferAllocationScheme());
1548 if (ent->content != NULL)
1549 xmlBufferAdd(cur->content, ent->content, -1);
1550#endif
1551 /*
1552 * The parent pointer in entity is a Dtd pointer and thus is NOT
1553 * updated. Not sure if this is 100% correct.
1554 * -George
1555 */
1556 cur->children = (xmlNodePtr) ent;
1557 cur->last = (xmlNodePtr) ent;
1558 }
1559 return(cur);
1560}
1561
1562/**
1563 * xmlNewDocText:
1564 * @doc: the document
1565 * @content: the text content
1566 *
1567 * Creation of a new text node within a document.
1568 * Returns a pointer to the new node object.
1569 */
1570xmlNodePtr
1571xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1572 xmlNodePtr cur;
1573
1574 cur = xmlNewText(content);
1575 if (cur != NULL) cur->doc = doc;
1576 return(cur);
1577}
1578
1579/**
1580 * xmlNewTextLen:
1581 * @content: the text content
1582 * @len: the text len.
1583 *
1584 * Creation of a new text node with an extra parameter for the content's lenght
1585 * Returns a pointer to the new node object.
1586 */
1587xmlNodePtr
1588xmlNewTextLen(const xmlChar *content, int len) {
1589 xmlNodePtr cur;
1590
1591 /*
1592 * Allocate a new node and fill the fields.
1593 */
1594 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1595 if (cur == NULL) {
1596 xmlGenericError(xmlGenericErrorContext,
1597 "xmlNewText : malloc failed\n");
1598 return(NULL);
1599 }
1600 memset(cur, 0, sizeof(xmlNode));
1601 cur->type = XML_TEXT_NODE;
1602
1603 cur->name = xmlStringText;
1604 if (content != NULL) {
1605#ifndef XML_USE_BUFFER_CONTENT
1606 cur->content = xmlStrndup(content, len);
1607#else
1608 cur->content = xmlBufferCreateSize(len);
1609 xmlBufferSetAllocationScheme(cur->content,
1610 xmlGetBufferAllocationScheme());
1611 xmlBufferAdd(cur->content, content, len);
1612#endif
1613 }
1614 return(cur);
1615}
1616
1617/**
1618 * xmlNewDocTextLen:
1619 * @doc: the document
1620 * @content: the text content
1621 * @len: the text len.
1622 *
1623 * Creation of a new text node with an extra content lenght parameter. The
1624 * text node pertain to a given document.
1625 * Returns a pointer to the new node object.
1626 */
1627xmlNodePtr
1628xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1629 xmlNodePtr cur;
1630
1631 cur = xmlNewTextLen(content, len);
1632 if (cur != NULL) cur->doc = doc;
1633 return(cur);
1634}
1635
1636/**
1637 * xmlNewComment:
1638 * @content: the comment content
1639 *
1640 * Creation of a new node containing a comment.
1641 * Returns a pointer to the new node object.
1642 */
1643xmlNodePtr
1644xmlNewComment(const xmlChar *content) {
1645 xmlNodePtr cur;
1646
1647 /*
1648 * Allocate a new node and fill the fields.
1649 */
1650 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1651 if (cur == NULL) {
1652 xmlGenericError(xmlGenericErrorContext,
1653 "xmlNewComment : malloc failed\n");
1654 return(NULL);
1655 }
1656 memset(cur, 0, sizeof(xmlNode));
1657 cur->type = XML_COMMENT_NODE;
1658
1659 cur->name = xmlStringComment;
1660 if (content != NULL) {
1661#ifndef XML_USE_BUFFER_CONTENT
1662 cur->content = xmlStrdup(content);
1663#else
1664 cur->content = xmlBufferCreateSize(0);
1665 xmlBufferSetAllocationScheme(cur->content,
1666 xmlGetBufferAllocationScheme());
1667 xmlBufferAdd(cur->content, content, -1);
1668#endif
1669 }
1670 return(cur);
1671}
1672
1673/**
1674 * xmlNewCDataBlock:
1675 * @doc: the document
1676 * @content: the CData block content content
1677 * @len: the length of the block
1678 *
1679 * Creation of a new node containing a CData block.
1680 * Returns a pointer to the new node object.
1681 */
1682xmlNodePtr
1683xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1684 xmlNodePtr cur;
1685
1686 /*
1687 * Allocate a new node and fill the fields.
1688 */
1689 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1690 if (cur == NULL) {
1691 xmlGenericError(xmlGenericErrorContext,
1692 "xmlNewCDataBlock : malloc failed\n");
1693 return(NULL);
1694 }
1695 memset(cur, 0, sizeof(xmlNode));
1696 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001697 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001698
1699 if (content != NULL) {
1700#ifndef XML_USE_BUFFER_CONTENT
1701 cur->content = xmlStrndup(content, len);
1702#else
1703 cur->content = xmlBufferCreateSize(len);
1704 xmlBufferSetAllocationScheme(cur->content,
1705 xmlGetBufferAllocationScheme());
1706 xmlBufferAdd(cur->content, content, len);
1707#endif
1708 }
1709 return(cur);
1710}
1711
1712/**
1713 * xmlNewDocComment:
1714 * @doc: the document
1715 * @content: the comment content
1716 *
1717 * Creation of a new node containing a commentwithin a document.
1718 * Returns a pointer to the new node object.
1719 */
1720xmlNodePtr
1721xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1722 xmlNodePtr cur;
1723
1724 cur = xmlNewComment(content);
1725 if (cur != NULL) cur->doc = doc;
1726 return(cur);
1727}
1728
1729/**
1730 * xmlSetTreeDoc:
1731 * @tree: the top element
1732 * @doc: the document
1733 *
1734 * update all nodes under the tree to point to the right document
1735 */
1736void
1737xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
1738 if (tree == NULL)
1739 return;
1740 if (tree->type == XML_ENTITY_DECL)
1741 return;
1742 if (tree->doc != doc) {
1743 if (tree->children != NULL)
1744 xmlSetListDoc(tree->children, doc);
1745 tree->doc = doc;
1746 }
1747}
1748
1749/**
1750 * xmlSetListDoc:
1751 * @tree: the first element
1752 * @doc: the document
1753 *
1754 * update all nodes in the list to point to the right document
1755 */
1756void
1757xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1758 xmlNodePtr cur;
1759
1760 if (list == NULL)
1761 return;
1762 cur = list;
1763 while (cur != NULL) {
1764 if (cur->doc != doc)
1765 xmlSetTreeDoc(cur, doc);
1766 cur = cur->next;
1767 }
1768}
1769
1770
1771/**
1772 * xmlNewChild:
1773 * @parent: the parent node
1774 * @ns: a namespace if any
1775 * @name: the name of the child
1776 * @content: the XML content of the child if any.
1777 *
1778 * Creation of a new child element, added at the end of @parent children list.
1779 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1780 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1781 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1782 * references, but XML special chars need to be escaped first by using
1783 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1784 * support is not needed.
1785 *
1786 * Returns a pointer to the new node object.
1787 */
1788xmlNodePtr
1789xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1790 const xmlChar *name, const xmlChar *content) {
1791 xmlNodePtr cur, prev;
1792
1793 if (parent == NULL) {
1794#ifdef DEBUG_TREE
1795 xmlGenericError(xmlGenericErrorContext,
1796 "xmlNewChild : parent == NULL\n");
1797#endif
1798 return(NULL);
1799 }
1800
1801 if (name == NULL) {
1802#ifdef DEBUG_TREE
1803 xmlGenericError(xmlGenericErrorContext,
1804 "xmlNewChild : name == NULL\n");
1805#endif
1806 return(NULL);
1807 }
1808
1809 /*
1810 * Allocate a new node
1811 */
1812 if (ns == NULL)
1813 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1814 else
1815 cur = xmlNewDocNode(parent->doc, ns, name, content);
1816 if (cur == NULL) return(NULL);
1817
1818 /*
1819 * add the new element at the end of the children list.
1820 */
1821 cur->type = XML_ELEMENT_NODE;
1822 cur->parent = parent;
1823 cur->doc = parent->doc;
1824 if (parent->children == NULL) {
1825 parent->children = cur;
1826 parent->last = cur;
1827 } else {
1828 prev = parent->last;
1829 prev->next = cur;
1830 cur->prev = prev;
1831 parent->last = cur;
1832 }
1833
1834 return(cur);
1835}
1836
1837/**
1838 * xmlAddNextSibling:
1839 * @cur: the child node
1840 * @elem: the new node
1841 *
1842 * Add a new element @elem as the next siblings of @cur
1843 * If the new element was already inserted in a document it is
1844 * first unlinked from its existing context.
1845 * As a result of text merging @elem may be freed.
1846 *
1847 * Returns the new element or NULL in case of error.
1848 */
1849xmlNodePtr
1850xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1851 if (cur == NULL) {
1852#ifdef DEBUG_TREE
1853 xmlGenericError(xmlGenericErrorContext,
1854 "xmlAddNextSibling : cur == NULL\n");
1855#endif
1856 return(NULL);
1857 }
1858 if (elem == NULL) {
1859#ifdef DEBUG_TREE
1860 xmlGenericError(xmlGenericErrorContext,
1861 "xmlAddNextSibling : elem == NULL\n");
1862#endif
1863 return(NULL);
1864 }
1865
1866 xmlUnlinkNode(elem);
1867
1868 if (elem->type == XML_TEXT_NODE) {
1869 if (cur->type == XML_TEXT_NODE) {
1870#ifndef XML_USE_BUFFER_CONTENT
1871 xmlNodeAddContent(cur, elem->content);
1872#else
1873 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1874#endif
1875 xmlFreeNode(elem);
1876 return(cur);
1877 }
1878 if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
1879#ifndef XML_USE_BUFFER_CONTENT
1880 xmlChar *tmp;
1881
1882 tmp = xmlStrdup(elem->content);
1883 tmp = xmlStrcat(tmp, cur->next->content);
1884 xmlNodeSetContent(cur->next, tmp);
1885 xmlFree(tmp);
1886#else
1887 xmlBufferAddHead(cur->next->content,
1888 xmlBufferContent(elem->content),
1889 xmlBufferLength(elem->content));
1890#endif
1891 xmlFreeNode(elem);
1892 return(cur->next);
1893 }
1894 }
1895
1896 if (elem->doc != cur->doc) {
1897 xmlSetTreeDoc(elem, cur->doc);
1898 }
1899 elem->parent = cur->parent;
1900 elem->prev = cur;
1901 elem->next = cur->next;
1902 cur->next = elem;
1903 if (elem->next != NULL)
1904 elem->next->prev = elem;
1905 if ((elem->parent != NULL) && (elem->parent->last == cur))
1906 elem->parent->last = elem;
1907 return(elem);
1908}
1909
1910/**
1911 * xmlAddPrevSibling:
1912 * @cur: the child node
1913 * @elem: the new node
1914 *
1915 * Add a new element @elem as the previous siblings of @cur
1916 * merging adjacent TEXT nodes (@elem may be freed)
1917 * If the new element was already inserted in a document it is
1918 * first unlinked from its existing context.
1919 *
1920 * Returns the new element or NULL in case of error.
1921 */
1922xmlNodePtr
1923xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
1924 if (cur == NULL) {
1925#ifdef DEBUG_TREE
1926 xmlGenericError(xmlGenericErrorContext,
1927 "xmlAddPrevSibling : cur == NULL\n");
1928#endif
1929 return(NULL);
1930 }
1931 if (elem == NULL) {
1932#ifdef DEBUG_TREE
1933 xmlGenericError(xmlGenericErrorContext,
1934 "xmlAddPrevSibling : elem == NULL\n");
1935#endif
1936 return(NULL);
1937 }
1938
1939 xmlUnlinkNode(elem);
1940
1941 if (elem->type == XML_TEXT_NODE) {
1942 if (cur->type == XML_TEXT_NODE) {
1943#ifndef XML_USE_BUFFER_CONTENT
1944 xmlChar *tmp;
1945
1946 tmp = xmlStrdup(elem->content);
1947 tmp = xmlStrcat(tmp, cur->content);
1948 xmlNodeSetContent(cur, tmp);
1949 xmlFree(tmp);
1950#else
1951 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
1952 xmlBufferLength(elem->content));
1953#endif
1954 xmlFreeNode(elem);
1955 return(cur);
1956 }
1957 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
1958#ifndef XML_USE_BUFFER_CONTENT
1959 xmlNodeAddContent(cur->prev, elem->content);
1960#else
1961 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
1962#endif
1963 xmlFreeNode(elem);
1964 return(cur->prev);
1965 }
1966 }
1967
1968 if (elem->doc != cur->doc) {
1969 xmlSetTreeDoc(elem, cur->doc);
1970 }
1971 elem->parent = cur->parent;
1972 elem->next = cur;
1973 elem->prev = cur->prev;
1974 cur->prev = elem;
1975 if (elem->prev != NULL)
1976 elem->prev->next = elem;
1977 if ((elem->parent != NULL) && (elem->parent->children == cur))
1978 elem->parent->children = elem;
1979 return(elem);
1980}
1981
1982/**
1983 * xmlAddSibling:
1984 * @cur: the child node
1985 * @elem: the new node
1986 *
1987 * Add a new element @elem to the list of siblings of @cur
1988 * merging adjacent TEXT nodes (@elem may be freed)
1989 * If the new element was already inserted in a document it is
1990 * first unlinked from its existing context.
1991 *
1992 * Returns the new element or NULL in case of error.
1993 */
1994xmlNodePtr
1995xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
1996 xmlNodePtr parent;
1997
1998 if (cur == NULL) {
1999#ifdef DEBUG_TREE
2000 xmlGenericError(xmlGenericErrorContext,
2001 "xmlAddSibling : cur == NULL\n");
2002#endif
2003 return(NULL);
2004 }
2005
2006 if (elem == NULL) {
2007#ifdef DEBUG_TREE
2008 xmlGenericError(xmlGenericErrorContext,
2009 "xmlAddSibling : elem == NULL\n");
2010#endif
2011 return(NULL);
2012 }
2013
2014 /*
2015 * Constant time is we can rely on the ->parent->last to find
2016 * the last sibling.
2017 */
2018 if ((cur->parent != NULL) &&
2019 (cur->parent->children != NULL) &&
2020 (cur->parent->last != NULL) &&
2021 (cur->parent->last->next == NULL)) {
2022 cur = cur->parent->last;
2023 } else {
2024 while (cur->next != NULL) cur = cur->next;
2025 }
2026
2027 xmlUnlinkNode(elem);
2028
2029 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2030#ifndef XML_USE_BUFFER_CONTENT
2031 xmlNodeAddContent(cur, elem->content);
2032#else
2033 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2034#endif
2035 xmlFreeNode(elem);
2036 return(cur);
2037 }
2038
2039 if (elem->doc != cur->doc) {
2040 xmlSetTreeDoc(elem, cur->doc);
2041 }
2042 parent = cur->parent;
2043 elem->prev = cur;
2044 elem->next = NULL;
2045 elem->parent = parent;
2046 cur->next = elem;
2047 if (parent != NULL)
2048 parent->last = elem;
2049
2050 return(elem);
2051}
2052
2053/**
2054 * xmlAddChildList:
2055 * @parent: the parent node
2056 * @cur: the first node in the list
2057 *
2058 * Add a list of node at the end of the child list of the parent
2059 * merging adjacent TEXT nodes (@cur may be freed)
2060 *
2061 * Returns the last child or NULL in case of error.
2062 */
2063xmlNodePtr
2064xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2065 xmlNodePtr prev;
2066
2067 if (parent == NULL) {
2068#ifdef DEBUG_TREE
2069 xmlGenericError(xmlGenericErrorContext,
2070 "xmlAddChild : parent == NULL\n");
2071#endif
2072 return(NULL);
2073 }
2074
2075 if (cur == NULL) {
2076#ifdef DEBUG_TREE
2077 xmlGenericError(xmlGenericErrorContext,
2078 "xmlAddChild : child == NULL\n");
2079#endif
2080 return(NULL);
2081 }
2082
2083 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2084 (cur->doc != parent->doc)) {
2085#ifdef DEBUG_TREE
2086 xmlGenericError(xmlGenericErrorContext,
2087 "Elements moved to a different document\n");
2088#endif
2089 }
2090
2091 /*
2092 * add the first element at the end of the children list.
2093 */
2094 if (parent->children == NULL) {
2095 parent->children = cur;
2096 } else {
2097 /*
2098 * If cur and parent->last both are TEXT nodes, then merge them.
2099 */
2100 if ((cur->type == XML_TEXT_NODE) &&
2101 (parent->last->type == XML_TEXT_NODE) &&
2102 (cur->name == parent->last->name)) {
2103#ifndef XML_USE_BUFFER_CONTENT
2104 xmlNodeAddContent(parent->last, cur->content);
2105#else
2106 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2107#endif
2108 /*
2109 * if it's the only child, nothing more to be done.
2110 */
2111 if (cur->next == NULL) {
2112 xmlFreeNode(cur);
2113 return(parent->last);
2114 }
2115 prev = cur;
2116 cur = cur->next;
2117 xmlFreeNode(prev);
2118 }
2119 prev = parent->last;
2120 prev->next = cur;
2121 cur->prev = prev;
2122 }
2123 while (cur->next != NULL) {
2124 cur->parent = parent;
2125 if (cur->doc != parent->doc) {
2126 xmlSetTreeDoc(cur, parent->doc);
2127 }
2128 cur = cur->next;
2129 }
2130 cur->parent = parent;
2131 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2132 parent->last = cur;
2133
2134 return(cur);
2135}
2136
2137/**
2138 * xmlAddChild:
2139 * @parent: the parent node
2140 * @cur: the child node
2141 *
2142 * Add a new child element, to @parent, at the end of the child list
2143 * merging adjacent TEXT nodes (in which case @cur is freed)
2144 * Returns the child or NULL in case of error.
2145 */
2146xmlNodePtr
2147xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2148 xmlNodePtr prev;
2149
2150 if (parent == NULL) {
2151#ifdef DEBUG_TREE
2152 xmlGenericError(xmlGenericErrorContext,
2153 "xmlAddChild : parent == NULL\n");
2154#endif
2155 return(NULL);
2156 }
2157
2158 if (cur == NULL) {
2159#ifdef DEBUG_TREE
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlAddChild : child == NULL\n");
2162#endif
2163 return(NULL);
2164 }
2165
2166 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2167 (cur->doc != parent->doc)) {
2168#ifdef DEBUG_TREE
2169 xmlGenericError(xmlGenericErrorContext,
2170 "Elements moved to a different document\n");
2171#endif
2172 }
2173
2174 /*
2175 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
2176 * or with parent->content if parent->content != NULL.
2177 * cur is then freed.
2178 */
2179 if (cur->type == XML_TEXT_NODE) {
2180 if (((parent->type == XML_ELEMENT_NODE) ||
2181 (parent->type == XML_TEXT_NODE)) &&
2182 (parent->content != NULL)) {
2183#ifndef XML_USE_BUFFER_CONTENT
2184 xmlNodeAddContent(parent, cur->content);
2185#else
2186 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2187#endif
2188 xmlFreeNode(cur);
2189 return(parent);
2190 }
2191 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2192 (parent->last->name == cur->name)) {
2193#ifndef XML_USE_BUFFER_CONTENT
2194 xmlNodeAddContent(parent->last, cur->content);
2195#else
2196 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2197#endif
2198 xmlFreeNode(cur);
2199 return(parent->last);
2200 }
2201 }
2202
2203 /*
2204 * add the new element at the end of the children list.
2205 */
2206 cur->parent = parent;
2207 if (cur->doc != parent->doc) {
2208 xmlSetTreeDoc(cur, parent->doc);
2209 }
2210
2211 /*
2212 * Handle the case where parent->content != NULL, in that case it will
2213 * create a intermediate TEXT node.
2214 */
2215 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2216 (parent->content != NULL)) {
2217 xmlNodePtr text;
2218
2219#ifndef XML_USE_BUFFER_CONTENT
2220 text = xmlNewDocText(parent->doc, parent->content);
2221#else
2222 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2223#endif
2224 if (text != NULL) {
2225 text->next = parent->children;
2226 if (text->next != NULL)
2227 text->next->prev = text;
2228 parent->children = text;
2229 UPDATE_LAST_CHILD_AND_PARENT(parent)
2230#ifndef XML_USE_BUFFER_CONTENT
2231 xmlFree(parent->content);
2232#else
2233 xmlBufferFree(parent->content);
2234#endif
2235 parent->content = NULL;
2236 }
2237 }
2238 if (parent->children == NULL) {
2239 parent->children = cur;
2240 parent->last = cur;
2241 } else {
2242 prev = parent->last;
2243 prev->next = cur;
2244 cur->prev = prev;
2245 parent->last = cur;
2246 }
2247
2248 return(cur);
2249}
2250
2251/**
2252 * xmlGetLastChild:
2253 * @parent: the parent node
2254 *
2255 * Search the last child of a node.
2256 * Returns the last child or NULL if none.
2257 */
2258xmlNodePtr
2259xmlGetLastChild(xmlNodePtr parent) {
2260 if (parent == NULL) {
2261#ifdef DEBUG_TREE
2262 xmlGenericError(xmlGenericErrorContext,
2263 "xmlGetLastChild : parent == NULL\n");
2264#endif
2265 return(NULL);
2266 }
2267 return(parent->last);
2268}
2269
2270/**
2271 * xmlFreeNodeList:
2272 * @cur: the first node in the list
2273 *
2274 * Free a node and all its siblings, this is a recursive behaviour, all
2275 * the children are freed too.
2276 */
2277void
2278xmlFreeNodeList(xmlNodePtr cur) {
2279 xmlNodePtr next;
2280 if (cur == NULL) {
2281#ifdef DEBUG_TREE
2282 xmlGenericError(xmlGenericErrorContext,
2283 "xmlFreeNodeList : node == NULL\n");
2284#endif
2285 return;
2286 }
2287 while (cur != NULL) {
2288 next = cur->next;
2289 xmlFreeNode(cur);
2290 cur = next;
2291 }
2292}
2293
2294/**
2295 * xmlFreeNode:
2296 * @cur: the node
2297 *
2298 * Free a node, this is a recursive behaviour, all the children are freed too.
2299 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2300 */
2301void
2302xmlFreeNode(xmlNodePtr cur) {
2303 if (cur == NULL) {
2304#ifdef DEBUG_TREE
2305 xmlGenericError(xmlGenericErrorContext,
2306 "xmlFreeNode : node == NULL\n");
2307#endif
2308 return;
2309 }
2310 if (cur->type == XML_DTD_NODE)
2311 return;
2312 cur->doc = NULL;
2313 cur->parent = NULL;
2314 cur->next = NULL;
2315 cur->prev = NULL;
2316 if ((cur->children != NULL) &&
2317 (cur->type != XML_ENTITY_REF_NODE))
2318 xmlFreeNodeList(cur->children);
2319 if (cur->properties != NULL) xmlFreePropList(cur->properties);
2320 if (cur->type != XML_ENTITY_REF_NODE)
2321#ifndef XML_USE_BUFFER_CONTENT
2322 if (cur->content != NULL) xmlFree(cur->content);
2323#else
2324 if (cur->content != NULL) xmlBufferFree(cur->content);
2325#endif
2326 if ((cur->name != NULL) &&
2327 (cur->name != xmlStringText) &&
2328 (cur->name != xmlStringTextNoenc) &&
2329 (cur->name != xmlStringComment))
2330 xmlFree((char *) cur->name);
2331 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Daniel Veillard48b2f892001-02-25 16:11:03 +00002332 MEM_CLEANUP(cur, sizeof(xmlNode));
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) {
4514#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard48b2f892001-02-25 16:11:03 +00004515 MEM_CLEANUP(buf->content, BASE_BUFFER_SIZE);
Owen Taylor3473f882001-02-23 17:55:21 +00004516#else
Daniel Veillard48b2f892001-02-25 16:11:03 +00004517 MEM_CLEANUP(buf->content, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004518#endif
4519 xmlFree(buf->content);
4520 }
Daniel Veillard48b2f892001-02-25 16:11:03 +00004521 MEM_CLEANUP(buf, sizeof(xmlBuffer));
Owen Taylor3473f882001-02-23 17:55:21 +00004522 xmlFree(buf);
4523}
4524
4525/**
4526 * xmlBufferEmpty:
4527 * @buf: the buffer
4528 *
4529 * empty a buffer.
4530 */
4531void
4532xmlBufferEmpty(xmlBufferPtr buf) {
4533 if (buf->content == NULL) return;
4534 buf->use = 0;
Daniel Veillard48b2f892001-02-25 16:11:03 +00004535 MEM_CLEANUP(buf->content, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004536}
4537
4538/**
4539 * xmlBufferShrink:
4540 * @buf: the buffer to dump
4541 * @len: the number of xmlChar to remove
4542 *
4543 * Remove the beginning of an XML buffer.
4544 *
4545 * Returns the number of xmlChar removed, or -1 in case of failure.
4546 */
4547int
4548xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
4549 if (len == 0) return(0);
4550 if (len > buf->use) return(-1);
4551
4552 buf->use -= len;
4553 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
4554
4555 buf->content[buf->use] = 0;
4556 return(len);
4557}
4558
4559/**
4560 * xmlBufferGrow:
4561 * @buf: the buffer
4562 * @len: the minimum free size to allocate
4563 *
4564 * Grow the available space of an XML buffer.
4565 *
4566 * Returns the new available space or -1 in case of error
4567 */
4568int
4569xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
4570 int size;
4571 xmlChar *newbuf;
4572
4573 if (len + buf->use < buf->size) return(0);
4574
4575 size = buf->use + len + 100;
4576
4577 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
4578 if (newbuf == NULL) return(-1);
4579 buf->content = newbuf;
4580 buf->size = size;
4581 return(buf->size - buf->use);
4582}
4583
4584/**
4585 * xmlBufferDump:
4586 * @file: the file output
4587 * @buf: the buffer to dump
4588 *
4589 * Dumps an XML buffer to a FILE *.
4590 * Returns the number of xmlChar written
4591 */
4592int
4593xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4594 int ret;
4595
4596 if (buf == NULL) {
4597#ifdef DEBUG_BUFFER
4598 xmlGenericError(xmlGenericErrorContext,
4599 "xmlBufferDump: buf == NULL\n");
4600#endif
4601 return(0);
4602 }
4603 if (buf->content == NULL) {
4604#ifdef DEBUG_BUFFER
4605 xmlGenericError(xmlGenericErrorContext,
4606 "xmlBufferDump: buf->content == NULL\n");
4607#endif
4608 return(0);
4609 }
4610 if (file == NULL) file = stdout;
4611 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
4612 return(ret);
4613}
4614
4615/**
4616 * xmlBufferContent:
4617 * @buf: the buffer
4618 *
4619 * Returns the internal content
4620 */
4621
4622const xmlChar*
4623xmlBufferContent(const xmlBufferPtr buf)
4624{
4625 if(!buf)
4626 return NULL;
4627
4628 return buf->content;
4629}
4630
4631/**
4632 * xmlBufferLength:
4633 * @buf: the buffer
4634 *
4635 * Returns the length of data in the internal content
4636 */
4637
4638int
4639xmlBufferLength(const xmlBufferPtr buf)
4640{
4641 if(!buf)
4642 return 0;
4643
4644 return buf->use;
4645}
4646
4647/**
4648 * xmlBufferResize:
4649 * @buf: the buffer to resize
4650 * @size: the desired size
4651 *
4652 * Resize a buffer to accomodate minimum size of @size.
4653 *
4654 * Returns 0 in case of problems, 1 otherwise
4655 */
4656int
4657xmlBufferResize(xmlBufferPtr buf, unsigned int size)
4658{
4659 unsigned int newSize;
4660 xmlChar* rebuf = NULL;
4661
4662 /*take care of empty case*/
4663 newSize = (buf->size ? buf->size*2 : size);
4664
4665 /* Don't resize if we don't have to */
4666 if (size < buf->size)
4667 return 1;
4668
4669 /* figure out new size */
4670 switch (buf->alloc){
4671 case XML_BUFFER_ALLOC_DOUBLEIT:
4672 while (size > newSize) newSize *= 2;
4673 break;
4674 case XML_BUFFER_ALLOC_EXACT:
4675 newSize = size+10;
4676 break;
4677 default:
4678 newSize = size+10;
4679 break;
4680 }
4681
4682 if (buf->content == NULL)
4683 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4684 else
4685 rebuf = (xmlChar *) xmlRealloc(buf->content,
4686 newSize * sizeof(xmlChar));
4687 if (rebuf == NULL) {
4688 xmlGenericError(xmlGenericErrorContext,
4689 "xmlBufferAdd : out of memory!\n");
4690 return 0;
4691 }
4692 buf->content = rebuf;
4693 buf->size = newSize;
4694
4695 return 1;
4696}
4697
4698/**
4699 * xmlBufferAdd:
4700 * @buf: the buffer to dump
4701 * @str: the xmlChar string
4702 * @len: the number of xmlChar to add
4703 *
4704 * Add a string range to an XML buffer. if len == -1, the lenght of
4705 * str is recomputed.
4706 */
4707void
4708xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
4709 unsigned int needSize;
4710
4711 if (str == NULL) {
4712#ifdef DEBUG_BUFFER
4713 xmlGenericError(xmlGenericErrorContext,
4714 "xmlBufferAdd: str == NULL\n");
4715#endif
4716 return;
4717 }
4718 if (len < -1) {
4719#ifdef DEBUG_BUFFER
4720 xmlGenericError(xmlGenericErrorContext,
4721 "xmlBufferAdd: len < 0\n");
4722#endif
4723 return;
4724 }
4725 if (len == 0) return;
4726
4727 if (len < 0)
4728 len = xmlStrlen(str);
4729
4730 if (len <= 0) return;
4731
4732 needSize = buf->use + len + 2;
4733 if (needSize > buf->size){
4734 if (!xmlBufferResize(buf, needSize)){
4735 xmlGenericError(xmlGenericErrorContext,
4736 "xmlBufferAdd : out of memory!\n");
4737 return;
4738 }
4739 }
4740
4741 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
4742 buf->use += len;
4743 buf->content[buf->use] = 0;
4744}
4745
4746/**
4747 * xmlBufferAddHead:
4748 * @buf: the buffer
4749 * @str: the xmlChar string
4750 * @len: the number of xmlChar to add
4751 *
4752 * Add a string range to the beginning of an XML buffer.
4753 * if len == -1, the lenght of @str is recomputed.
4754 */
4755void
4756xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
4757 unsigned int needSize;
4758
4759 if (str == NULL) {
4760#ifdef DEBUG_BUFFER
4761 xmlGenericError(xmlGenericErrorContext,
4762 "xmlBufferAdd: str == NULL\n");
4763#endif
4764 return;
4765 }
4766 if (len < -1) {
4767#ifdef DEBUG_BUFFER
4768 xmlGenericError(xmlGenericErrorContext,
4769 "xmlBufferAdd: len < 0\n");
4770#endif
4771 return;
4772 }
4773 if (len == 0) return;
4774
4775 if (len < 0)
4776 len = xmlStrlen(str);
4777
4778 if (len <= 0) return;
4779
4780 needSize = buf->use + len + 2;
4781 if (needSize > buf->size){
4782 if (!xmlBufferResize(buf, needSize)){
4783 xmlGenericError(xmlGenericErrorContext,
4784 "xmlBufferAddHead : out of memory!\n");
4785 return;
4786 }
4787 }
4788
4789 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4790 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4791 buf->use += len;
4792 buf->content[buf->use] = 0;
4793}
4794
4795/**
4796 * xmlBufferCat:
4797 * @buf: the buffer to dump
4798 * @str: the xmlChar string
4799 *
4800 * Append a zero terminated string to an XML buffer.
4801 */
4802void
4803xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
4804 if (str != NULL)
4805 xmlBufferAdd(buf, str, -1);
4806}
4807
4808/**
4809 * xmlBufferCCat:
4810 * @buf: the buffer to dump
4811 * @str: the C char string
4812 *
4813 * Append a zero terminated C string to an XML buffer.
4814 */
4815void
4816xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4817 const char *cur;
4818
4819 if (str == NULL) {
4820#ifdef DEBUG_BUFFER
4821 xmlGenericError(xmlGenericErrorContext,
4822 "xmlBufferAdd: str == NULL\n");
4823#endif
4824 return;
4825 }
4826 for (cur = str;*cur != 0;cur++) {
4827 if (buf->use + 10 >= buf->size) {
4828 if (!xmlBufferResize(buf, buf->use+10)){
4829 xmlGenericError(xmlGenericErrorContext,
4830 "xmlBufferCCat : out of memory!\n");
4831 return;
4832 }
4833 }
4834 buf->content[buf->use++] = *cur;
4835 }
4836 buf->content[buf->use] = 0;
4837}
4838
4839/**
4840 * xmlBufferWriteCHAR:
4841 * @buf: the XML buffer
4842 * @string: the string to add
4843 *
4844 * routine which manages and grows an output buffer. This one adds
4845 * xmlChars at the end of the buffer.
4846 */
4847void
4848#ifdef VMS
4849xmlBufferWriteXmlCHAR
4850#else
4851xmlBufferWriteCHAR
4852#endif
4853(xmlBufferPtr buf, const xmlChar *string) {
4854 xmlBufferCat(buf, string);
4855}
4856
4857/**
4858 * xmlBufferWriteChar:
4859 * @buf: the XML buffer output
4860 * @string: the string to add
4861 *
4862 * routine which manage and grows an output buffer. This one add
4863 * C chars at the end of the array.
4864 */
4865void
4866xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4867 xmlBufferCCat(buf, string);
4868}
4869
4870
4871/**
4872 * xmlBufferWriteQuotedString:
4873 * @buf: the XML buffer output
4874 * @string: the string to add
4875 *
4876 * routine which manage and grows an output buffer. This one writes
4877 * a quoted or double quoted xmlChar string, checking first if it holds
4878 * quote or double-quotes internally
4879 */
4880void
4881xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
4882 if (xmlStrchr(string, '"')) {
4883 if (xmlStrchr(string, '\'')) {
4884#ifdef DEBUG_BUFFER
4885 xmlGenericError(xmlGenericErrorContext,
4886 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
4887#endif
4888 }
4889 xmlBufferCCat(buf, "'");
4890 xmlBufferCat(buf, string);
4891 xmlBufferCCat(buf, "'");
4892 } else {
4893 xmlBufferCCat(buf, "\"");
4894 xmlBufferCat(buf, string);
4895 xmlBufferCCat(buf, "\"");
4896 }
4897}
4898
4899
4900/************************************************************************
4901 * *
4902 * Dumping XML tree content to a simple buffer *
4903 * *
4904 ************************************************************************/
4905
4906void
4907xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4908 int format);
4909static void
4910xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4911 int format);
4912void
4913htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4914
4915/**
4916 * xmlNsDump:
4917 * @buf: the XML buffer output
4918 * @cur: a namespace
4919 *
4920 * Dump a local Namespace definition.
4921 * Should be called in the context of attributes dumps.
4922 */
4923static void
4924xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
4925 if (cur == NULL) {
4926#ifdef DEBUG_TREE
4927 xmlGenericError(xmlGenericErrorContext,
4928 "xmlNsDump : Ns == NULL\n");
4929#endif
4930 return;
4931 }
4932 if (cur->type == XML_LOCAL_NAMESPACE) {
4933 /* Within the context of an element attributes */
4934 if (cur->prefix != NULL) {
4935 xmlBufferWriteChar(buf, " xmlns:");
4936 xmlBufferWriteCHAR(buf, cur->prefix);
4937 } else
4938 xmlBufferWriteChar(buf, " xmlns");
4939 xmlBufferWriteChar(buf, "=");
4940 xmlBufferWriteQuotedString(buf, cur->href);
4941 }
4942}
4943
4944/**
4945 * xmlNsListDump:
4946 * @buf: the XML buffer output
4947 * @cur: the first namespace
4948 *
4949 * Dump a list of local Namespace definitions.
4950 * Should be called in the context of attributes dumps.
4951 */
4952static void
4953xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
4954 while (cur != NULL) {
4955 xmlNsDump(buf, cur);
4956 cur = cur->next;
4957 }
4958}
4959
4960/**
4961 * xmlDtdDump:
4962 * @buf: the XML buffer output
4963 * @doc: the document
4964 *
4965 * Dump the XML document DTD, if any.
4966 */
4967static void
4968xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4969 if (dtd == NULL) {
4970#ifdef DEBUG_TREE
4971 xmlGenericError(xmlGenericErrorContext,
4972 "xmlDtdDump : no internal subset\n");
4973#endif
4974 return;
4975 }
4976 xmlBufferWriteChar(buf, "<!DOCTYPE ");
4977 xmlBufferWriteCHAR(buf, dtd->name);
4978 if (dtd->ExternalID != NULL) {
4979 xmlBufferWriteChar(buf, " PUBLIC ");
4980 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
4981 xmlBufferWriteChar(buf, " ");
4982 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4983 } else if (dtd->SystemID != NULL) {
4984 xmlBufferWriteChar(buf, " SYSTEM ");
4985 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4986 }
4987 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4988 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4989 xmlBufferWriteChar(buf, ">");
4990 return;
4991 }
4992 xmlBufferWriteChar(buf, " [\n");
4993 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4994#if 0
4995 if (dtd->entities != NULL)
4996 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4997 if (dtd->notations != NULL)
4998 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4999 if (dtd->elements != NULL)
5000 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5001 if (dtd->attributes != NULL)
5002 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5003#endif
5004 xmlBufferWriteChar(buf, "]>");
5005}
5006
5007/**
5008 * xmlAttrDump:
5009 * @buf: the XML buffer output
5010 * @doc: the document
5011 * @cur: the attribute pointer
5012 *
5013 * Dump an XML attribute
5014 */
5015static void
5016xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5017 xmlChar *value;
5018
5019 if (cur == NULL) {
5020#ifdef DEBUG_TREE
5021 xmlGenericError(xmlGenericErrorContext,
5022 "xmlAttrDump : property == NULL\n");
5023#endif
5024 return;
5025 }
5026 xmlBufferWriteChar(buf, " ");
5027 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5028 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5029 xmlBufferWriteChar(buf, ":");
5030 }
5031 xmlBufferWriteCHAR(buf, cur->name);
5032 value = xmlNodeListGetString(doc, cur->children, 0);
5033 if (value != NULL) {
5034 xmlBufferWriteChar(buf, "=");
5035 xmlBufferWriteQuotedString(buf, value);
5036 xmlFree(value);
5037 } else {
5038 xmlBufferWriteChar(buf, "=\"\"");
5039 }
5040}
5041
5042/**
5043 * xmlAttrListDump:
5044 * @buf: the XML buffer output
5045 * @doc: the document
5046 * @cur: the first attribute pointer
5047 *
5048 * Dump a list of XML attributes
5049 */
5050static void
5051xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5052 if (cur == NULL) {
5053#ifdef DEBUG_TREE
5054 xmlGenericError(xmlGenericErrorContext,
5055 "xmlAttrListDump : property == NULL\n");
5056#endif
5057 return;
5058 }
5059 while (cur != NULL) {
5060 xmlAttrDump(buf, doc, cur);
5061 cur = cur->next;
5062 }
5063}
5064
5065
5066
5067/**
5068 * xmlNodeListDump:
5069 * @buf: the XML buffer output
5070 * @doc: the document
5071 * @cur: the first node
5072 * @level: the imbrication level for indenting
5073 * @format: is formatting allowed
5074 *
5075 * Dump an XML node list, recursive behaviour,children are printed too.
5076 */
5077static void
5078xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5079 int format) {
5080 int i;
5081
5082 if (cur == NULL) {
5083#ifdef DEBUG_TREE
5084 xmlGenericError(xmlGenericErrorContext,
5085 "xmlNodeListDump : node == NULL\n");
5086#endif
5087 return;
5088 }
5089 while (cur != NULL) {
5090 if ((format) && (xmlIndentTreeOutput) &&
5091 (cur->type == XML_ELEMENT_NODE))
5092 for (i = 0;i < level;i++)
5093 xmlBufferWriteChar(buf, " ");
5094 xmlNodeDump(buf, doc, cur, level, format);
5095 if (format) {
5096 xmlBufferWriteChar(buf, "\n");
5097 }
5098 cur = cur->next;
5099 }
5100}
5101
5102/**
5103 * xmlNodeDump:
5104 * @buf: the XML buffer output
5105 * @doc: the document
5106 * @cur: the current node
5107 * @level: the imbrication level for indenting
5108 * @format: is formatting allowed
5109 *
5110 * Dump an XML node, recursive behaviour,children are printed too.
5111 */
5112void
5113xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5114 int format) {
5115 int i;
5116 xmlNodePtr tmp;
5117
5118 if (cur == NULL) {
5119#ifdef DEBUG_TREE
5120 xmlGenericError(xmlGenericErrorContext,
5121 "xmlNodeDump : node == NULL\n");
5122#endif
5123 return;
5124 }
5125 if (cur->type == XML_XINCLUDE_START)
5126 return;
5127 if (cur->type == XML_XINCLUDE_END)
5128 return;
5129 if (cur->type == XML_DTD_NODE) {
5130 xmlDtdDump(buf, (xmlDtdPtr) cur);
5131 return;
5132 }
5133 if (cur->type == XML_ELEMENT_DECL) {
5134 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5135 return;
5136 }
5137 if (cur->type == XML_ATTRIBUTE_DECL) {
5138 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5139 return;
5140 }
5141 if (cur->type == XML_ENTITY_DECL) {
5142 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5143 return;
5144 }
5145 if (cur->type == XML_TEXT_NODE) {
5146 if (cur->content != NULL) {
5147 if ((cur->name == xmlStringText) ||
5148 (cur->name != xmlStringTextNoenc)) {
5149 xmlChar *buffer;
5150
5151#ifndef XML_USE_BUFFER_CONTENT
5152 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5153#else
5154 buffer = xmlEncodeEntitiesReentrant(doc,
5155 xmlBufferContent(cur->content));
5156#endif
5157 if (buffer != NULL) {
5158 xmlBufferWriteCHAR(buf, buffer);
5159 xmlFree(buffer);
5160 }
5161 } else {
5162 /*
5163 * Disable escaping, needed for XSLT
5164 */
5165#ifndef XML_USE_BUFFER_CONTENT
5166 xmlBufferWriteCHAR(buf, cur->content);
5167#else
5168 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5169#endif
5170 }
5171 }
5172 return;
5173 }
5174 if (cur->type == XML_PI_NODE) {
5175 if (cur->content != NULL) {
5176 xmlBufferWriteChar(buf, "<?");
5177 xmlBufferWriteCHAR(buf, cur->name);
5178 if (cur->content != NULL) {
5179 xmlBufferWriteChar(buf, " ");
5180#ifndef XML_USE_BUFFER_CONTENT
5181 xmlBufferWriteCHAR(buf, cur->content);
5182#else
5183 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5184#endif
5185 }
5186 xmlBufferWriteChar(buf, "?>");
5187 } else {
5188 xmlBufferWriteChar(buf, "<?");
5189 xmlBufferWriteCHAR(buf, cur->name);
5190 xmlBufferWriteChar(buf, "?>");
5191 }
5192 return;
5193 }
5194 if (cur->type == XML_COMMENT_NODE) {
5195 if (cur->content != NULL) {
5196 xmlBufferWriteChar(buf, "<!--");
5197#ifndef XML_USE_BUFFER_CONTENT
5198 xmlBufferWriteCHAR(buf, cur->content);
5199#else
5200 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5201#endif
5202 xmlBufferWriteChar(buf, "-->");
5203 }
5204 return;
5205 }
5206 if (cur->type == XML_ENTITY_REF_NODE) {
5207 xmlBufferWriteChar(buf, "&");
5208 xmlBufferWriteCHAR(buf, cur->name);
5209 xmlBufferWriteChar(buf, ";");
5210 return;
5211 }
5212 if (cur->type == XML_CDATA_SECTION_NODE) {
5213 xmlBufferWriteChar(buf, "<![CDATA[");
5214 if (cur->content != NULL)
5215#ifndef XML_USE_BUFFER_CONTENT
5216 xmlBufferWriteCHAR(buf, cur->content);
5217#else
5218 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5219#endif
5220 xmlBufferWriteChar(buf, "]]>");
5221 return;
5222 }
5223
5224 if (format == 1) {
5225 tmp = cur->children;
5226 while (tmp != NULL) {
5227 if ((tmp->type == XML_TEXT_NODE) ||
5228 (tmp->type == XML_ENTITY_REF_NODE)) {
5229 format = 0;
5230 break;
5231 }
5232 tmp = tmp->next;
5233 }
5234 }
5235 xmlBufferWriteChar(buf, "<");
5236 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5237 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5238 xmlBufferWriteChar(buf, ":");
5239 }
5240
5241 xmlBufferWriteCHAR(buf, cur->name);
5242 if (cur->nsDef)
5243 xmlNsListDump(buf, cur->nsDef);
5244 if (cur->properties != NULL)
5245 xmlAttrListDump(buf, doc, cur->properties);
5246
5247 if ((cur->content == NULL) && (cur->children == NULL) &&
5248 (!xmlSaveNoEmptyTags)) {
5249 xmlBufferWriteChar(buf, "/>");
5250 return;
5251 }
5252 xmlBufferWriteChar(buf, ">");
5253 if (cur->content != NULL) {
5254 xmlChar *buffer;
5255
5256#ifndef XML_USE_BUFFER_CONTENT
5257 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5258#else
5259 buffer = xmlEncodeEntitiesReentrant(doc,
5260 xmlBufferContent(cur->content));
5261#endif
5262 if (buffer != NULL) {
5263 xmlBufferWriteCHAR(buf, buffer);
5264 xmlFree(buffer);
5265 }
5266 }
5267 if (cur->children != NULL) {
5268 if (format) xmlBufferWriteChar(buf, "\n");
5269 xmlNodeListDump(buf, doc, cur->children,
5270 (level >= 0?level+1:-1), format);
5271 if ((xmlIndentTreeOutput) && (format))
5272 for (i = 0;i < level;i++)
5273 xmlBufferWriteChar(buf, " ");
5274 }
5275 xmlBufferWriteChar(buf, "</");
5276 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5277 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5278 xmlBufferWriteChar(buf, ":");
5279 }
5280
5281 xmlBufferWriteCHAR(buf, cur->name);
5282 xmlBufferWriteChar(buf, ">");
5283}
5284
5285/**
5286 * xmlElemDump:
5287 * @f: the FILE * for the output
5288 * @doc: the document
5289 * @cur: the current node
5290 *
5291 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5292 */
5293void
5294xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5295 xmlBufferPtr buf;
5296
5297 if (cur == NULL) {
5298#ifdef DEBUG_TREE
5299 xmlGenericError(xmlGenericErrorContext,
5300 "xmlElemDump : cur == NULL\n");
5301#endif
5302 return;
5303 }
5304 if (doc == NULL) {
5305#ifdef DEBUG_TREE
5306 xmlGenericError(xmlGenericErrorContext,
5307 "xmlElemDump : doc == NULL\n");
5308#endif
5309 }
5310 buf = xmlBufferCreate();
5311 if (buf == NULL) return;
5312 if ((doc != NULL) &&
5313 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5314#ifdef LIBXML_HTML_ENABLED
5315 htmlNodeDump(buf, doc, cur);
5316#else
5317 xmlGenericError(xmlGenericErrorContext,
5318 "HTML support not compiled in\n");
5319#endif /* LIBXML_HTML_ENABLED */
5320 } else
5321 xmlNodeDump(buf, doc, cur, 0, 1);
5322 xmlBufferDump(f, buf);
5323 xmlBufferFree(buf);
5324}
5325
5326/************************************************************************
5327 * *
5328 * Dumping XML tree content to an I/O output buffer *
5329 * *
5330 ************************************************************************/
5331
5332void
5333xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5334 int level, int format, const char *encoding);
5335static void
5336xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5337 int level, int format, const char *encoding);
5338/**
5339 * xmlNsDumpOutput:
5340 * @buf: the XML buffer output
5341 * @cur: a namespace
5342 *
5343 * Dump a local Namespace definition.
5344 * Should be called in the context of attributes dumps.
5345 */
5346static void
5347xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5348 if (cur == NULL) {
5349#ifdef DEBUG_TREE
5350 xmlGenericError(xmlGenericErrorContext,
5351 "xmlNsDump : Ns == NULL\n");
5352#endif
5353 return;
5354 }
5355 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5356 /* Within the context of an element attributes */
5357 if (cur->prefix != NULL) {
5358 xmlOutputBufferWriteString(buf, " xmlns:");
5359 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5360 } else
5361 xmlOutputBufferWriteString(buf, " xmlns");
5362 xmlOutputBufferWriteString(buf, "=");
5363 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5364 }
5365}
5366
5367/**
5368 * xmlNsListDumpOutput:
5369 * @buf: the XML buffer output
5370 * @cur: the first namespace
5371 *
5372 * Dump a list of local Namespace definitions.
5373 * Should be called in the context of attributes dumps.
5374 */
5375static void
5376xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5377 while (cur != NULL) {
5378 xmlNsDumpOutput(buf, cur);
5379 cur = cur->next;
5380 }
5381}
5382
5383/**
5384 * xmlDtdDumpOutput:
5385 * @buf: the XML buffer output
5386 * @doc: the document
5387 * @encoding: an optional encoding string
5388 *
5389 * Dump the XML document DTD, if any.
5390 */
5391static void
5392xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5393 if (dtd == NULL) {
5394#ifdef DEBUG_TREE
5395 xmlGenericError(xmlGenericErrorContext,
5396 "xmlDtdDump : no internal subset\n");
5397#endif
5398 return;
5399 }
5400 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5401 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5402 if (dtd->ExternalID != NULL) {
5403 xmlOutputBufferWriteString(buf, " PUBLIC ");
5404 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5405 xmlOutputBufferWriteString(buf, " ");
5406 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5407 } else if (dtd->SystemID != NULL) {
5408 xmlOutputBufferWriteString(buf, " SYSTEM ");
5409 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5410 }
5411 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5412 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5413 xmlOutputBufferWriteString(buf, ">");
5414 return;
5415 }
5416 xmlOutputBufferWriteString(buf, " [\n");
5417 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5418 xmlOutputBufferWriteString(buf, "]>");
5419}
5420
5421/**
5422 * xmlAttrDumpOutput:
5423 * @buf: the XML buffer output
5424 * @doc: the document
5425 * @cur: the attribute pointer
5426 * @encoding: an optional encoding string
5427 *
5428 * Dump an XML attribute
5429 */
5430static void
5431xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005432 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005433 xmlChar *value;
5434
5435 if (cur == NULL) {
5436#ifdef DEBUG_TREE
5437 xmlGenericError(xmlGenericErrorContext,
5438 "xmlAttrDump : property == NULL\n");
5439#endif
5440 return;
5441 }
5442 xmlOutputBufferWriteString(buf, " ");
5443 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5444 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5445 xmlOutputBufferWriteString(buf, ":");
5446 }
5447 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5448 value = xmlNodeListGetString(doc, cur->children, 0);
5449 if (value) {
5450 xmlOutputBufferWriteString(buf, "=");
5451 xmlBufferWriteQuotedString(buf->buffer, value);
5452 xmlFree(value);
5453 } else {
5454 xmlOutputBufferWriteString(buf, "=\"\"");
5455 }
5456}
5457
5458/**
5459 * xmlAttrListDumpOutput:
5460 * @buf: the XML buffer output
5461 * @doc: the document
5462 * @cur: the first attribute pointer
5463 * @encoding: an optional encoding string
5464 *
5465 * Dump a list of XML attributes
5466 */
5467static void
5468xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5469 xmlAttrPtr cur, const char *encoding) {
5470 if (cur == NULL) {
5471#ifdef DEBUG_TREE
5472 xmlGenericError(xmlGenericErrorContext,
5473 "xmlAttrListDump : property == NULL\n");
5474#endif
5475 return;
5476 }
5477 while (cur != NULL) {
5478 xmlAttrDumpOutput(buf, doc, cur, encoding);
5479 cur = cur->next;
5480 }
5481}
5482
5483
5484
5485/**
5486 * xmlNodeListDumpOutput:
5487 * @buf: the XML buffer output
5488 * @doc: the document
5489 * @cur: the first node
5490 * @level: the imbrication level for indenting
5491 * @format: is formatting allowed
5492 * @encoding: an optional encoding string
5493 *
5494 * Dump an XML node list, recursive behaviour,children are printed too.
5495 */
5496static void
5497xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5498 xmlNodePtr cur, int level, int format, const char *encoding) {
5499 int i;
5500
5501 if (cur == NULL) {
5502#ifdef DEBUG_TREE
5503 xmlGenericError(xmlGenericErrorContext,
5504 "xmlNodeListDump : node == NULL\n");
5505#endif
5506 return;
5507 }
5508 while (cur != NULL) {
5509 if ((format) && (xmlIndentTreeOutput) &&
5510 (cur->type == XML_ELEMENT_NODE))
5511 for (i = 0;i < level;i++)
5512 xmlOutputBufferWriteString(buf, " ");
5513 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5514 if (format) {
5515 xmlOutputBufferWriteString(buf, "\n");
5516 }
5517 cur = cur->next;
5518 }
5519}
5520
5521/**
5522 * xmlNodeDumpOutput:
5523 * @buf: the XML buffer output
5524 * @doc: the document
5525 * @cur: the current node
5526 * @level: the imbrication level for indenting
5527 * @format: is formatting allowed
5528 * @encoding: an optional encoding string
5529 *
5530 * Dump an XML node, recursive behaviour,children are printed too.
5531 */
5532void
5533xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5534 int level, int format, const char *encoding) {
5535 int i;
5536 xmlNodePtr tmp;
5537
5538 if (cur == NULL) {
5539#ifdef DEBUG_TREE
5540 xmlGenericError(xmlGenericErrorContext,
5541 "xmlNodeDump : node == NULL\n");
5542#endif
5543 return;
5544 }
5545 if (cur->type == XML_XINCLUDE_START)
5546 return;
5547 if (cur->type == XML_XINCLUDE_END)
5548 return;
5549 if (cur->type == XML_DTD_NODE) {
5550 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5551 return;
5552 }
5553 if (cur->type == XML_ELEMENT_DECL) {
5554 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5555 return;
5556 }
5557 if (cur->type == XML_ATTRIBUTE_DECL) {
5558 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5559 return;
5560 }
5561 if (cur->type == XML_ENTITY_DECL) {
5562 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5563 return;
5564 }
5565 if (cur->type == XML_TEXT_NODE) {
5566 if (cur->content != NULL) {
5567 if ((cur->name == xmlStringText) ||
5568 (cur->name != xmlStringTextNoenc)) {
5569 xmlChar *buffer;
5570
5571#ifndef XML_USE_BUFFER_CONTENT
5572 if (encoding == NULL)
5573 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5574 else
5575 buffer = xmlEncodeSpecialChars(doc, cur->content);
5576#else
5577 if (encoding == NULL)
5578 buffer = xmlEncodeEntitiesReentrant(doc,
5579 xmlBufferContent(cur->content));
5580 else
5581 buffer = xmlEncodeSpecialChars(doc,
5582 xmlBufferContent(cur->content));
5583#endif
5584 if (buffer != NULL) {
5585 xmlOutputBufferWriteString(buf, (const char *)buffer);
5586 xmlFree(buffer);
5587 }
5588 } else {
5589 /*
5590 * Disable escaping, needed for XSLT
5591 */
5592#ifndef XML_USE_BUFFER_CONTENT
5593 xmlOutputBufferWriteString(buf, (const char *) cur->content);
5594#else
5595 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5596#endif
5597 }
5598 }
5599
5600 return;
5601 }
5602 if (cur->type == XML_PI_NODE) {
5603 if (cur->content != NULL) {
5604 xmlOutputBufferWriteString(buf, "<?");
5605 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5606 if (cur->content != NULL) {
5607 xmlOutputBufferWriteString(buf, " ");
5608#ifndef XML_USE_BUFFER_CONTENT
5609 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5610#else
5611 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5612#endif
5613 }
5614 xmlOutputBufferWriteString(buf, "?>");
5615 } else {
5616 xmlOutputBufferWriteString(buf, "<?");
5617 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5618 xmlOutputBufferWriteString(buf, "?>");
5619 }
5620 return;
5621 }
5622 if (cur->type == XML_COMMENT_NODE) {
5623 if (cur->content != NULL) {
5624 xmlOutputBufferWriteString(buf, "<!--");
5625#ifndef XML_USE_BUFFER_CONTENT
5626 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5627#else
5628 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5629#endif
5630 xmlOutputBufferWriteString(buf, "-->");
5631 }
5632 return;
5633 }
5634 if (cur->type == XML_ENTITY_REF_NODE) {
5635 xmlOutputBufferWriteString(buf, "&");
5636 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5637 xmlOutputBufferWriteString(buf, ";");
5638 return;
5639 }
5640 if (cur->type == XML_CDATA_SECTION_NODE) {
5641 xmlOutputBufferWriteString(buf, "<![CDATA[");
5642 if (cur->content != NULL)
5643#ifndef XML_USE_BUFFER_CONTENT
5644 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5645#else
5646 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5647#endif
5648 xmlOutputBufferWriteString(buf, "]]>");
5649 return;
5650 }
5651
5652 if (format == 1) {
5653 tmp = cur->children;
5654 while (tmp != NULL) {
5655 if ((tmp->type == XML_TEXT_NODE) ||
5656 (tmp->type == XML_ENTITY_REF_NODE)) {
5657 format = 0;
5658 break;
5659 }
5660 tmp = tmp->next;
5661 }
5662 }
5663 xmlOutputBufferWriteString(buf, "<");
5664 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5665 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5666 xmlOutputBufferWriteString(buf, ":");
5667 }
5668
5669 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5670 if (cur->nsDef)
5671 xmlNsListDumpOutput(buf, cur->nsDef);
5672 if (cur->properties != NULL)
5673 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5674
5675 if ((cur->content == NULL) && (cur->children == NULL) &&
5676 (!xmlSaveNoEmptyTags)) {
5677 xmlOutputBufferWriteString(buf, "/>");
5678 return;
5679 }
5680 xmlOutputBufferWriteString(buf, ">");
5681 if (cur->content != NULL) {
5682 xmlChar *buffer;
5683
5684#ifndef XML_USE_BUFFER_CONTENT
5685 if (encoding == NULL)
5686 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5687 else
5688 buffer = xmlEncodeSpecialChars(doc, cur->content);
5689#else
5690 if (encoding == NULL)
5691 buffer = xmlEncodeEntitiesReentrant(doc,
5692 xmlBufferContent(cur->content));
5693 else
5694 buffer = xmlEncodeSpecialChars(doc,
5695 xmlBufferContent(cur->content));
5696#endif
5697 if (buffer != NULL) {
5698 xmlOutputBufferWriteString(buf, (const char *)buffer);
5699 xmlFree(buffer);
5700 }
5701 }
5702 if (cur->children != NULL) {
5703 if (format) xmlOutputBufferWriteString(buf, "\n");
5704 xmlNodeListDumpOutput(buf, doc, cur->children,
5705 (level >= 0?level+1:-1), format, encoding);
5706 if ((xmlIndentTreeOutput) && (format))
5707 for (i = 0;i < level;i++)
5708 xmlOutputBufferWriteString(buf, " ");
5709 }
5710 xmlOutputBufferWriteString(buf, "</");
5711 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5712 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5713 xmlOutputBufferWriteString(buf, ":");
5714 }
5715
5716 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5717 xmlOutputBufferWriteString(buf, ">");
5718}
5719
5720/**
5721 * xmlDocContentDumpOutput:
5722 * @buf: the XML buffer output
5723 * @cur: the document
5724 * @encoding: an optional encoding string
5725 * @format: should formatting spaces been added
5726 *
5727 * Dump an XML document.
5728 */
5729static void
5730xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
5731 const char *encoding, int format) {
5732 xmlOutputBufferWriteString(buf, "<?xml version=");
5733 if (cur->version != NULL)
5734 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5735 else
5736 xmlOutputBufferWriteString(buf, "\"1.0\"");
5737 if (encoding == NULL) {
5738 if (cur->encoding != NULL)
5739 encoding = (const char *) cur->encoding;
5740 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
5741 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
5742 }
5743 if (encoding != NULL) {
5744 xmlOutputBufferWriteString(buf, " encoding=");
5745 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5746 }
5747 switch (cur->standalone) {
5748 case 0:
5749 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5750 break;
5751 case 1:
5752 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5753 break;
5754 }
5755 xmlOutputBufferWriteString(buf, "?>\n");
5756 if (cur->children != NULL) {
5757 xmlNodePtr child = cur->children;
5758
5759 while (child != NULL) {
5760 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
5761 xmlOutputBufferWriteString(buf, "\n");
5762 child = child->next;
5763 }
5764 }
5765}
5766
5767/************************************************************************
5768 * *
5769 * Saving functions front-ends *
5770 * *
5771 ************************************************************************/
5772
5773/**
5774 * xmlDocDumpMemoryEnc:
5775 * @out_doc: Document to generate XML text from
5776 * @doc_txt_ptr: Memory pointer for allocated XML text
5777 * @doc_txt_len: Length of the generated XML text
5778 * @txt_encoding: Character encoding to use when generating XML text
5779 * @format: should formatting spaces been added
5780 *
5781 * Dump the current DOM tree into memory using the character encoding specified
5782 * by the caller. Note it is up to the caller of this function to free the
5783 * allocated memory.
5784 */
5785
5786void
5787xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005788 int * doc_txt_len, const char * txt_encoding,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005789 int format ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005790 int dummy = 0;
5791
5792 xmlCharEncoding doc_charset;
5793 xmlOutputBufferPtr out_buff = NULL;
5794 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
5795
5796 if (doc_txt_len == NULL) {
5797 doc_txt_len = &dummy; /* Continue, caller just won't get length */
5798 }
5799
5800 if (doc_txt_ptr == NULL) {
5801 *doc_txt_len = 0;
5802 xmlGenericError(xmlGenericErrorContext,
5803 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
5804 return;
5805 }
5806
5807 *doc_txt_ptr = NULL;
5808 *doc_txt_len = 0;
5809
5810 if (out_doc == NULL) {
5811 /* No document, no output */
5812 xmlGenericError(xmlGenericErrorContext,
5813 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
5814 return;
5815 }
5816
5817 /*
5818 * Validate the encoding value, if provided.
5819 * This logic is copied from xmlSaveFileEnc.
5820 */
5821
5822 if (txt_encoding == NULL)
5823 txt_encoding = (const char *) out_doc->encoding;
5824 if (txt_encoding != NULL) {
5825 doc_charset = xmlParseCharEncoding(txt_encoding);
5826
5827 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
5828 xmlGenericError(xmlGenericErrorContext,
5829 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
5830 return;
5831
5832 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
5833 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
5834 if ( conv_hdlr == NULL ) {
5835 xmlGenericError(xmlGenericErrorContext,
5836 "%s: %s %s '%s'\n",
5837 "xmlDocDumpFormatMemoryEnc",
5838 "Failed to identify encoding handler for",
5839 "character set",
5840 txt_encoding);
5841 return;
5842 }
5843 }
5844 }
5845
5846 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
5847 xmlGenericError(xmlGenericErrorContext,
5848 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
5849 return;
5850 }
5851
5852 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, 1);
5853 xmlOutputBufferFlush(out_buff);
5854 if (out_buff->conv != NULL) {
5855 *doc_txt_len = out_buff->conv->use;
5856 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
5857 } else {
5858 *doc_txt_len = out_buff->buffer->use;
5859 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
5860 }
5861 (void)xmlOutputBufferClose(out_buff);
5862
5863 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
5864 *doc_txt_len = 0;
5865 xmlGenericError(xmlGenericErrorContext,
5866 "xmlDocDumpFormatMemoryEnc: %s\n",
5867 "Failed to allocate memory for document text representation.");
5868 }
5869
5870 return;
5871}
5872
5873/**
5874 * xmlDocDumpMemory:
5875 * @cur: the document
5876 * @mem: OUT: the memory pointer
5877 * @size: OUT: the memory lenght
5878 *
5879 * Dump an XML document in memory and return the xmlChar * and it's size.
5880 * It's up to the caller to free the memory.
5881 */
5882void
5883xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
5884 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
5885}
5886
5887/**
5888 * xmlDocDumpFormatMemory:
5889 * @cur: the document
5890 * @mem: OUT: the memory pointer
5891 * @size: OUT: the memory lenght
5892 * @format: should formatting spaces been added
5893 *
5894 *
5895 * Dump an XML document in memory and return the xmlChar * and it's size.
5896 * It's up to the caller to free the memory.
5897 */
5898void
5899xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
5900 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
5901}
5902
5903/**
5904 * xmlDocDumpMemoryEnc:
5905 * @out_doc: Document to generate XML text from
5906 * @doc_txt_ptr: Memory pointer for allocated XML text
5907 * @doc_txt_len: Length of the generated XML text
5908 * @txt_encoding: Character encoding to use when generating XML text
5909 *
5910 * Dump the current DOM tree into memory using the character encoding specified
5911 * by the caller. Note it is up to the caller of this function to free the
5912 * allocated memory.
5913 */
5914
5915void
5916xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5917 int * doc_txt_len, const char * txt_encoding) {
5918 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
5919 txt_encoding, 1);
5920}
5921
5922/**
5923 * xmlGetDocCompressMode:
5924 * @doc: the document
5925 *
5926 * get the compression ratio for a document, ZLIB based
5927 * Returns 0 (uncompressed) to 9 (max compression)
5928 */
5929int
5930xmlGetDocCompressMode (xmlDocPtr doc) {
5931 if (doc == NULL) return(-1);
5932 return(doc->compression);
5933}
5934
5935/**
5936 * xmlSetDocCompressMode:
5937 * @doc: the document
5938 * @mode: the compression ratio
5939 *
5940 * set the compression ratio for a document, ZLIB based
5941 * Correct values: 0 (uncompressed) to 9 (max compression)
5942 */
5943void
5944xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
5945 if (doc == NULL) return;
5946 if (mode < 0) doc->compression = 0;
5947 else if (mode > 9) doc->compression = 9;
5948 else doc->compression = mode;
5949}
5950
5951/**
5952 * xmlGetCompressMode:
5953 *
5954 * get the default compression mode used, ZLIB based.
5955 * Returns 0 (uncompressed) to 9 (max compression)
5956 */
5957int
5958 xmlGetCompressMode(void) {
5959 return(xmlCompressMode);
5960}
5961
5962/**
5963 * xmlSetCompressMode:
5964 * @mode: the compression ratio
5965 *
5966 * set the default compression mode used, ZLIB based
5967 * Correct values: 0 (uncompressed) to 9 (max compression)
5968 */
5969void
5970xmlSetCompressMode(int mode) {
5971 if (mode < 0) xmlCompressMode = 0;
5972 else if (mode > 9) xmlCompressMode = 9;
5973 else xmlCompressMode = mode;
5974}
5975
5976/**
5977 * xmlDocDump:
5978 * @f: the FILE*
5979 * @cur: the document
5980 *
5981 * Dump an XML document to an open FILE.
5982 *
5983 * returns: the number of byte written or -1 in case of failure.
5984 */
5985int
5986xmlDocDump(FILE *f, xmlDocPtr cur) {
5987 xmlOutputBufferPtr buf;
5988 const char * encoding;
5989 xmlCharEncodingHandlerPtr handler = NULL;
5990 int ret;
5991
5992 if (cur == NULL) {
5993#ifdef DEBUG_TREE
5994 xmlGenericError(xmlGenericErrorContext,
5995 "xmlDocDump : document == NULL\n");
5996#endif
5997 return(-1);
5998 }
5999 encoding = (const char *) cur->encoding;
6000
6001 if (encoding != NULL) {
6002 xmlCharEncoding enc;
6003
6004 enc = xmlParseCharEncoding(encoding);
6005
6006 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6007 xmlGenericError(xmlGenericErrorContext,
6008 "xmlDocDump: document not in UTF8\n");
6009 return(-1);
6010 }
6011 if (enc != XML_CHAR_ENCODING_UTF8) {
6012 handler = xmlFindCharEncodingHandler(encoding);
6013 if (handler == NULL) {
6014 xmlFree((char *) cur->encoding);
6015 cur->encoding = NULL;
6016 }
6017 }
6018 }
6019 buf = xmlOutputBufferCreateFile(f, handler);
6020 if (buf == NULL) return(-1);
6021 xmlDocContentDumpOutput(buf, cur, NULL, 1);
6022
6023 ret = xmlOutputBufferClose(buf);
6024 return(ret);
6025}
6026
6027/**
6028 * xmlSaveFileTo:
6029 * @buf: an output I/O buffer
6030 * @cur: the document
6031 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6032 *
6033 * Dump an XML document to an I/O buffer.
6034 *
6035 * returns: the number of byte written or -1 in case of failure.
6036 */
6037int
6038xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
6039 int ret;
6040
6041 if (buf == NULL) return(0);
6042 xmlDocContentDumpOutput(buf, cur, encoding, 1);
6043 ret = xmlOutputBufferClose(buf);
6044 return(ret);
6045}
6046
6047/**
6048 * xmlSaveFileEnc:
6049 * @filename: the filename (or URL)
6050 * @cur: the document
6051 * @encoding: the name of an encoding (or NULL)
6052 *
6053 * Dump an XML document, converting it to the given encoding
6054 *
6055 * returns: the number of byte written or -1 in case of failure.
6056 */
6057int
6058xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6059 xmlOutputBufferPtr buf;
6060 xmlCharEncodingHandlerPtr handler = NULL;
6061 int ret;
6062
6063 if (encoding != NULL) {
6064 xmlCharEncoding enc;
6065
6066 enc = xmlParseCharEncoding(encoding);
6067 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6068 xmlGenericError(xmlGenericErrorContext,
6069 "xmlSaveFileEnc: document not in UTF8\n");
6070 return(-1);
6071 }
6072 if (enc != XML_CHAR_ENCODING_UTF8) {
6073 handler = xmlFindCharEncodingHandler(encoding);
6074 if (handler == NULL) {
6075 return(-1);
6076 }
6077 }
6078 }
6079
6080 /*
6081 * save the content to a temp buffer.
6082 */
6083 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
6084 if (buf == NULL) return(-1);
6085
6086 xmlDocContentDumpOutput(buf, cur, encoding, 1);
6087
6088 ret = xmlOutputBufferClose(buf);
6089 return(ret);
6090}
6091
6092/**
6093 * xmlSaveFile:
6094 * @filename: the filename (or URL)
6095 * @cur: the document
6096 *
6097 * Dump an XML document to a file. Will use compression if
6098 * compiled in and enabled. If @filename is "-" the stdout file is
6099 * used.
6100 * returns: the number of byte written or -1 in case of failure.
6101 */
6102int
6103xmlSaveFile(const char *filename, xmlDocPtr cur) {
6104 xmlOutputBufferPtr buf;
6105 const char *encoding;
6106 xmlCharEncodingHandlerPtr handler = NULL;
6107 int ret;
6108
6109 if (cur == NULL)
6110 return(-1);
6111 encoding = (const char *) cur->encoding;
6112
6113 /*
6114 * save the content to a temp buffer.
6115 */
6116#ifdef HAVE_ZLIB_H
6117 if (cur->compression < 0) cur->compression = xmlCompressMode;
6118#endif
6119 if (encoding != NULL) {
6120 xmlCharEncoding enc;
6121
6122 enc = xmlParseCharEncoding(encoding);
6123
6124 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6125 xmlGenericError(xmlGenericErrorContext,
6126 "xmlSaveFile: document not in UTF8\n");
6127 return(-1);
6128 }
6129 if (enc != XML_CHAR_ENCODING_UTF8) {
6130 handler = xmlFindCharEncodingHandler(encoding);
6131 if (handler == NULL) {
6132 xmlFree((char *) cur->encoding);
6133 cur->encoding = NULL;
6134 }
6135 }
6136 }
6137
6138 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
6139 if (buf == NULL) return(-1);
6140
6141 xmlDocContentDumpOutput(buf, cur, NULL, 1);
6142
6143 ret = xmlOutputBufferClose(buf);
6144 return(ret);
6145}
6146