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