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