blob: e5c7d660ddf2447ae5d351007ae80614862e3730 [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/**
2739 * xmlCopyNodeList:
2740 * @node: the first node in the list.
2741 *
2742 * Do a recursive copy of the node list.
2743 *
2744 * Returns: a new xmlNodePtr, or NULL in case of error.
2745 */
2746xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2747 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2748 return(ret);
2749}
2750
2751/**
2752 * xmlCopyElement:
2753 * @elem: the element
2754 *
2755 * Do a copy of the element definition.
2756 *
2757 * Returns: a new xmlElementPtr, or NULL in case of error.
2758xmlElementPtr
2759xmlCopyElement(xmlElementPtr elem) {
2760 xmlElementPtr ret;
2761
2762 if (elem == NULL) return(NULL);
2763 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2764 if (ret == NULL) return(NULL);
2765 if (!recursive) return(ret);
2766 if (elem->properties != NULL)
2767 ret->properties = xmlCopyPropList(elem->properties);
2768
2769 if (elem->nsDef != NULL)
2770 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
2771 if (elem->children != NULL)
2772 ret->children = xmlCopyElementList(elem->children);
2773 return(ret);
2774}
2775 */
2776
2777/**
2778 * xmlCopyDtd:
2779 * @dtd: the dtd
2780 *
2781 * Do a copy of the dtd.
2782 *
2783 * Returns: a new xmlDtdPtr, or NULL in case of error.
2784 */
2785xmlDtdPtr
2786xmlCopyDtd(xmlDtdPtr dtd) {
2787 xmlDtdPtr ret;
2788
2789 if (dtd == NULL) return(NULL);
2790 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2791 if (ret == NULL) return(NULL);
2792 if (dtd->entities != NULL)
2793 ret->entities = (void *) xmlCopyEntitiesTable(
2794 (xmlEntitiesTablePtr) dtd->entities);
2795 if (dtd->notations != NULL)
2796 ret->notations = (void *) xmlCopyNotationTable(
2797 (xmlNotationTablePtr) dtd->notations);
2798 if (dtd->elements != NULL)
2799 ret->elements = (void *) xmlCopyElementTable(
2800 (xmlElementTablePtr) dtd->elements);
2801 if (dtd->attributes != NULL)
2802 ret->attributes = (void *) xmlCopyAttributeTable(
2803 (xmlAttributeTablePtr) dtd->attributes);
2804 return(ret);
2805}
2806
2807/**
2808 * xmlCopyDoc:
2809 * @doc: the document
2810 * @recursive: if 1 do a recursive copy.
2811 *
2812 * Do a copy of the document info. If recursive, the content tree will
2813 * be copied too as well as Dtd, namespaces and entities.
2814 *
2815 * Returns: a new xmlDocPtr, or NULL in case of error.
2816 */
2817xmlDocPtr
2818xmlCopyDoc(xmlDocPtr doc, int recursive) {
2819 xmlDocPtr ret;
2820
2821 if (doc == NULL) return(NULL);
2822 ret = xmlNewDoc(doc->version);
2823 if (ret == NULL) return(NULL);
2824 if (doc->name != NULL)
2825 ret->name = xmlMemStrdup(doc->name);
2826 if (doc->encoding != NULL)
2827 ret->encoding = xmlStrdup(doc->encoding);
2828 ret->charset = doc->charset;
2829 ret->compression = doc->compression;
2830 ret->standalone = doc->standalone;
2831 if (!recursive) return(ret);
2832
2833 if (doc->intSubset != NULL)
2834 ret->intSubset = xmlCopyDtd(doc->intSubset);
2835 if (doc->oldNs != NULL)
2836 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2837 if (doc->children != NULL) {
2838 xmlNodePtr tmp;
2839 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2840 (xmlNodePtr)ret);
2841 ret->last = NULL;
2842 tmp = ret->children;
2843 while (tmp != NULL) {
2844 if (tmp->next == NULL)
2845 ret->last = tmp;
2846 tmp = tmp->next;
2847 }
2848 }
2849 return(ret);
2850}
2851
2852/************************************************************************
2853 * *
2854 * Content access functions *
2855 * *
2856 ************************************************************************/
2857
2858/**
2859 * xmlDocGetRootElement:
2860 * @doc: the document
2861 *
2862 * Get the root element of the document (doc->children is a list
2863 * containing possibly comments, PIs, etc ...).
2864 *
2865 * Returns the xmlNodePtr for the root or NULL
2866 */
2867xmlNodePtr
2868xmlDocGetRootElement(xmlDocPtr doc) {
2869 xmlNodePtr ret;
2870
2871 if (doc == NULL) return(NULL);
2872 ret = doc->children;
2873 while (ret != NULL) {
2874 if (ret->type == XML_ELEMENT_NODE)
2875 return(ret);
2876 ret = ret->next;
2877 }
2878 return(ret);
2879}
2880
2881/**
2882 * xmlDocSetRootElement:
2883 * @doc: the document
2884 * @root: the new document root element
2885 *
2886 * Set the root element of the document (doc->children is a list
2887 * containing possibly comments, PIs, etc ...).
2888 *
2889 * Returns the old root element if any was found
2890 */
2891xmlNodePtr
2892xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2893 xmlNodePtr old = NULL;
2894
2895 if (doc == NULL) return(NULL);
2896 old = doc->children;
2897 while (old != NULL) {
2898 if (old->type == XML_ELEMENT_NODE)
2899 break;
2900 old = old->next;
2901 }
2902 if (old == NULL) {
2903 if (doc->children == NULL) {
2904 doc->children = root;
2905 doc->last = root;
2906 } else {
2907 xmlAddSibling(doc->children, root);
2908 }
2909 } else {
2910 xmlReplaceNode(old, root);
2911 }
2912 return(old);
2913}
2914
2915/**
2916 * xmlNodeSetLang:
2917 * @cur: the node being changed
2918 * @lang: the langage description
2919 *
2920 * Set the language of a node, i.e. the values of the xml:lang
2921 * attribute.
2922 */
2923void
2924xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
2925 if (cur == NULL) return;
2926 switch(cur->type) {
2927 case XML_TEXT_NODE:
2928 case XML_CDATA_SECTION_NODE:
2929 case XML_COMMENT_NODE:
2930 case XML_DOCUMENT_NODE:
2931 case XML_DOCUMENT_TYPE_NODE:
2932 case XML_DOCUMENT_FRAG_NODE:
2933 case XML_NOTATION_NODE:
2934 case XML_HTML_DOCUMENT_NODE:
2935 case XML_DTD_NODE:
2936 case XML_ELEMENT_DECL:
2937 case XML_ATTRIBUTE_DECL:
2938 case XML_ENTITY_DECL:
2939 case XML_PI_NODE:
2940 case XML_ENTITY_REF_NODE:
2941 case XML_ENTITY_NODE:
2942 case XML_NAMESPACE_DECL:
2943#ifdef LIBXML_SGML_ENABLED
2944 case XML_SGML_DOCUMENT_NODE:
2945#endif
2946 case XML_XINCLUDE_START:
2947 case XML_XINCLUDE_END:
2948 return;
2949 case XML_ELEMENT_NODE:
2950 case XML_ATTRIBUTE_NODE:
2951 break;
2952 }
2953 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
2954}
2955
2956/**
2957 * xmlNodeGetLang:
2958 * @cur: the node being checked
2959 *
2960 * Searches the language of a node, i.e. the values of the xml:lang
2961 * attribute or the one carried by the nearest ancestor.
2962 *
2963 * Returns a pointer to the lang value, or NULL if not found
2964 * It's up to the caller to free the memory.
2965 */
2966xmlChar *
2967xmlNodeGetLang(xmlNodePtr cur) {
2968 xmlChar *lang;
2969
2970 while (cur != NULL) {
2971 lang = xmlGetProp(cur, BAD_CAST "xml:lang");
2972 if (lang != NULL)
2973 return(lang);
2974 cur = cur->parent;
2975 }
2976 return(NULL);
2977}
2978
2979
2980/**
2981 * xmlNodeSetSpacePreserve:
2982 * @cur: the node being changed
2983 * @val: the xml:space value ("0": default, 1: "preserve")
2984 *
2985 * Set (or reset) the space preserving behaviour of a node, i.e. the
2986 * value of the xml:space attribute.
2987 */
2988void
2989xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
2990 if (cur == NULL) return;
2991 switch(cur->type) {
2992 case XML_TEXT_NODE:
2993 case XML_CDATA_SECTION_NODE:
2994 case XML_COMMENT_NODE:
2995 case XML_DOCUMENT_NODE:
2996 case XML_DOCUMENT_TYPE_NODE:
2997 case XML_DOCUMENT_FRAG_NODE:
2998 case XML_NOTATION_NODE:
2999 case XML_HTML_DOCUMENT_NODE:
3000 case XML_DTD_NODE:
3001 case XML_ELEMENT_DECL:
3002 case XML_ATTRIBUTE_DECL:
3003 case XML_ENTITY_DECL:
3004 case XML_PI_NODE:
3005 case XML_ENTITY_REF_NODE:
3006 case XML_ENTITY_NODE:
3007 case XML_NAMESPACE_DECL:
3008 case XML_XINCLUDE_START:
3009 case XML_XINCLUDE_END:
3010#ifdef LIBXML_SGML_ENABLED
3011 case XML_SGML_DOCUMENT_NODE:
3012#endif
3013 return;
3014 case XML_ELEMENT_NODE:
3015 case XML_ATTRIBUTE_NODE:
3016 break;
3017 }
3018 switch (val) {
3019 case 0:
3020 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3021 break;
3022 case 1:
3023 xmlSetProp(cur, BAD_CAST "xml:space",
3024 BAD_CAST "preserve");
3025 break;
3026 }
3027}
3028
3029/**
3030 * xmlNodeGetSpacePreserve:
3031 * @cur: the node being checked
3032 *
3033 * Searches the space preserving behaviour of a node, i.e. the values
3034 * of the xml:space attribute or the one carried by the nearest
3035 * ancestor.
3036 *
3037 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
3038 */
3039int
3040xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3041 xmlChar *space;
3042
3043 while (cur != NULL) {
3044 space = xmlGetProp(cur, BAD_CAST "xml:space");
3045 if (space != NULL) {
3046 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3047 xmlFree(space);
3048 return(1);
3049 }
3050 if (xmlStrEqual(space, BAD_CAST "default")) {
3051 xmlFree(space);
3052 return(0);
3053 }
3054 xmlFree(space);
3055 }
3056 cur = cur->parent;
3057 }
3058 return(-1);
3059}
3060
3061/**
3062 * xmlNodeSetName:
3063 * @cur: the node being changed
3064 * @name: the new tag name
3065 *
3066 * Set (or reset) the name of a node.
3067 */
3068void
3069xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3070 if (cur == NULL) return;
3071 if (name == NULL) return;
3072 switch(cur->type) {
3073 case XML_TEXT_NODE:
3074 case XML_CDATA_SECTION_NODE:
3075 case XML_COMMENT_NODE:
3076 case XML_DOCUMENT_TYPE_NODE:
3077 case XML_DOCUMENT_FRAG_NODE:
3078 case XML_NOTATION_NODE:
3079 case XML_HTML_DOCUMENT_NODE:
3080 case XML_NAMESPACE_DECL:
3081 case XML_XINCLUDE_START:
3082 case XML_XINCLUDE_END:
3083#ifdef LIBXML_SGML_ENABLED
3084 case XML_SGML_DOCUMENT_NODE:
3085#endif
3086 return;
3087 case XML_ELEMENT_NODE:
3088 case XML_ATTRIBUTE_NODE:
3089 case XML_PI_NODE:
3090 case XML_ENTITY_REF_NODE:
3091 case XML_ENTITY_NODE:
3092 case XML_DTD_NODE:
3093 case XML_DOCUMENT_NODE:
3094 case XML_ELEMENT_DECL:
3095 case XML_ATTRIBUTE_DECL:
3096 case XML_ENTITY_DECL:
3097 break;
3098 }
3099 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3100 cur->name = xmlStrdup(name);
3101}
3102
3103/**
3104 * xmlNodeSetBase:
3105 * @cur: the node being changed
3106 * @uri: the new base URI
3107 *
3108 * Set (or reset) the base URI of a node, i.e. the value of the
3109 * xml:base attribute.
3110 */
3111void
3112xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3113 if (cur == NULL) return;
3114 switch(cur->type) {
3115 case XML_TEXT_NODE:
3116 case XML_CDATA_SECTION_NODE:
3117 case XML_COMMENT_NODE:
3118 case XML_DOCUMENT_NODE:
3119 case XML_DOCUMENT_TYPE_NODE:
3120 case XML_DOCUMENT_FRAG_NODE:
3121 case XML_NOTATION_NODE:
3122 case XML_HTML_DOCUMENT_NODE:
3123 case XML_DTD_NODE:
3124 case XML_ELEMENT_DECL:
3125 case XML_ATTRIBUTE_DECL:
3126 case XML_ENTITY_DECL:
3127 case XML_PI_NODE:
3128 case XML_ENTITY_REF_NODE:
3129 case XML_ENTITY_NODE:
3130 case XML_NAMESPACE_DECL:
3131 case XML_XINCLUDE_START:
3132 case XML_XINCLUDE_END:
3133#ifdef LIBXML_SGML_ENABLED
3134 case XML_SGML_DOCUMENT_NODE:
3135#endif
3136 return;
3137 case XML_ELEMENT_NODE:
3138 case XML_ATTRIBUTE_NODE:
3139 break;
3140 }
3141 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3142}
3143
3144/**
Owen Taylor3473f882001-02-23 17:55:21 +00003145 * xmlNodeGetBase:
3146 * @doc: the document the node pertains to
3147 * @cur: the node being checked
3148 *
3149 * Searches for the BASE URL. The code should work on both XML
3150 * and HTML document even if base mechanisms are completely different.
3151 * It returns the base as defined in RFC 2396 sections
3152 * 5.1.1. Base URI within Document Content
3153 * and
3154 * 5.1.2. Base URI from the Encapsulating Entity
3155 * However it does not return the document base (5.1.3), use
3156 * xmlDocumentGetBase() for this
3157 *
3158 * Returns a pointer to the base URL, or NULL if not found
3159 * It's up to the caller to free the memory.
3160 */
3161xmlChar *
3162xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
3163 xmlChar *base;
3164
3165 if ((cur == NULL) && (doc == NULL))
3166 return(NULL);
3167 if (doc == NULL) doc = cur->doc;
3168 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3169 cur = doc->children;
3170 while ((cur != NULL) && (cur->name != NULL)) {
3171 if (cur->type != XML_ELEMENT_NODE) {
3172 cur = cur->next;
3173 continue;
3174 }
3175 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3176 cur = cur->children;
3177 continue;
3178 }
3179 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3180 cur = cur->children;
3181 continue;
3182 }
3183 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3184 return(xmlGetProp(cur, BAD_CAST "href"));
3185 }
3186 cur = cur->next;
3187 }
3188 return(NULL);
3189 }
3190 while (cur != NULL) {
3191 if (cur->type == XML_ENTITY_DECL) {
3192 xmlEntityPtr ent = (xmlEntityPtr) cur;
3193 return(xmlStrdup(ent->URI));
3194 }
3195 base = xmlGetProp(cur, BAD_CAST "xml:base");
3196 if (base != NULL)
3197 return(base);
3198 cur = cur->parent;
3199 }
3200 if ((doc != NULL) && (doc->URL != NULL))
3201 return(xmlStrdup(doc->URL));
3202 return(NULL);
3203}
3204
3205/**
3206 * xmlNodeGetContent:
3207 * @cur: the node being read
3208 *
3209 * Read the value of a node, this can be either the text carried
3210 * directly by this node if it's a TEXT node or the aggregate string
3211 * of the values carried by this node child's (TEXT and ENTITY_REF).
3212 * Entity references are substitued.
3213 * Returns a new xmlChar * or NULL if no content is available.
3214 * It's up to the caller to free the memory.
3215 */
3216xmlChar *
3217xmlNodeGetContent(xmlNodePtr cur) {
3218 if (cur == NULL) return(NULL);
3219 switch (cur->type) {
3220 case XML_DOCUMENT_FRAG_NODE:
3221 case XML_ELEMENT_NODE: {
3222 xmlNodePtr tmp = cur;
3223 xmlBufferPtr buffer;
3224 xmlChar *ret;
3225
3226 buffer = xmlBufferCreate();
3227 if (buffer == NULL)
3228 return(NULL);
3229 while (tmp != NULL) {
3230 switch (tmp->type) {
3231 case XML_ELEMENT_NODE:
3232 case XML_TEXT_NODE:
3233 if (tmp->content != NULL)
3234#ifndef XML_USE_BUFFER_CONTENT
3235 xmlBufferCat(buffer, tmp->content);
3236#else
3237 xmlBufferCat(buffer,
3238 xmlBufferContent(tmp->content));
3239#endif
3240 break;
3241 case XML_ENTITY_REF_NODE: {
3242 xmlEntityPtr ent;
3243
3244 ent = xmlGetDocEntity(cur->doc, tmp->name);
3245 if (ent != NULL)
3246 xmlBufferCat(buffer, ent->content);
3247 }
3248 default:
3249 break;
3250 }
3251 /*
3252 * Skip to next node
3253 */
3254 if (tmp->children != NULL) {
3255 if (tmp->children->type != XML_ENTITY_DECL) {
3256 tmp = tmp->children;
3257 continue;
3258 }
3259 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003260 if (tmp == cur)
3261 break;
3262
Owen Taylor3473f882001-02-23 17:55:21 +00003263 if (tmp->next != NULL) {
3264 tmp = tmp->next;
3265 continue;
3266 }
3267
3268 do {
3269 tmp = tmp->parent;
3270 if (tmp == NULL)
3271 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003272 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003273 tmp = NULL;
3274 break;
3275 }
3276 if (tmp->next != NULL) {
3277 tmp = tmp->next;
3278 break;
3279 }
3280 } while (tmp != NULL);
3281 }
3282 ret = buffer->content;
3283 buffer->content = NULL;
3284 xmlBufferFree(buffer);
3285 return(ret);
3286 }
3287 case XML_ATTRIBUTE_NODE: {
3288 xmlAttrPtr attr = (xmlAttrPtr) cur;
3289 if (attr->parent != NULL)
3290 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3291 else
3292 return(xmlNodeListGetString(NULL, attr->children, 1));
3293 break;
3294 }
3295 case XML_COMMENT_NODE:
3296 case XML_PI_NODE:
3297 if (cur->content != NULL)
3298#ifndef XML_USE_BUFFER_CONTENT
3299 return(xmlStrdup(cur->content));
3300#else
3301 return(xmlStrdup(xmlBufferContent(cur->content)));
3302#endif
3303 return(NULL);
3304 case XML_ENTITY_REF_NODE:
3305 /*
3306 * Locate the entity, and get it's content
3307 * @@@
3308 */
3309 return(NULL);
3310 case XML_ENTITY_NODE:
3311 case XML_DOCUMENT_NODE:
3312 case XML_HTML_DOCUMENT_NODE:
3313 case XML_DOCUMENT_TYPE_NODE:
3314 case XML_NOTATION_NODE:
3315 case XML_DTD_NODE:
3316 case XML_XINCLUDE_START:
3317 case XML_XINCLUDE_END:
3318#ifdef LIBXML_SGML_ENABLED
3319 case XML_SGML_DOCUMENT_NODE:
3320#endif
3321 return(NULL);
3322 case XML_NAMESPACE_DECL:
3323 return(xmlStrdup(((xmlNsPtr)cur)->href));
3324 case XML_ELEMENT_DECL:
3325 /* TODO !!! */
3326 return(NULL);
3327 case XML_ATTRIBUTE_DECL:
3328 /* TODO !!! */
3329 return(NULL);
3330 case XML_ENTITY_DECL:
3331 /* TODO !!! */
3332 return(NULL);
3333 case XML_CDATA_SECTION_NODE:
3334 case XML_TEXT_NODE:
3335 if (cur->content != NULL)
3336#ifndef XML_USE_BUFFER_CONTENT
3337 return(xmlStrdup(cur->content));
3338#else
3339 return(xmlStrdup(xmlBufferContent(cur->content)));
3340#endif
3341 return(NULL);
3342 }
3343 return(NULL);
3344}
3345
3346/**
3347 * xmlNodeSetContent:
3348 * @cur: the node being modified
3349 * @content: the new value of the content
3350 *
3351 * Replace the content of a node.
3352 */
3353void
3354xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3355 if (cur == NULL) {
3356#ifdef DEBUG_TREE
3357 xmlGenericError(xmlGenericErrorContext,
3358 "xmlNodeSetContent : node == NULL\n");
3359#endif
3360 return;
3361 }
3362 switch (cur->type) {
3363 case XML_DOCUMENT_FRAG_NODE:
3364 case XML_ELEMENT_NODE:
3365 if (cur->content != NULL) {
3366#ifndef XML_USE_BUFFER_CONTENT
3367 xmlFree(cur->content);
3368#else
3369 xmlBufferFree(cur->content);
3370#endif
3371 cur->content = NULL;
3372 }
3373 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3374 cur->children = xmlStringGetNodeList(cur->doc, content);
3375 UPDATE_LAST_CHILD_AND_PARENT(cur)
3376 break;
3377 case XML_ATTRIBUTE_NODE:
3378 break;
3379 case XML_TEXT_NODE:
3380 case XML_CDATA_SECTION_NODE:
3381 case XML_ENTITY_REF_NODE:
3382 case XML_ENTITY_NODE:
3383 case XML_PI_NODE:
3384 case XML_COMMENT_NODE:
3385 if (cur->content != NULL) {
3386#ifndef XML_USE_BUFFER_CONTENT
3387 xmlFree(cur->content);
3388#else
3389 xmlBufferFree(cur->content);
3390#endif
3391 }
3392 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3393 cur->last = cur->children = NULL;
3394 if (content != NULL) {
3395#ifndef XML_USE_BUFFER_CONTENT
3396 cur->content = xmlStrdup(content);
3397#else
3398 cur->content = xmlBufferCreateSize(0);
3399 xmlBufferSetAllocationScheme(cur->content,
3400 xmlGetBufferAllocationScheme());
3401 xmlBufferAdd(cur->content, content, -1);
3402#endif
3403 } else
3404 cur->content = NULL;
3405 break;
3406 case XML_DOCUMENT_NODE:
3407 case XML_HTML_DOCUMENT_NODE:
3408 case XML_DOCUMENT_TYPE_NODE:
3409 case XML_XINCLUDE_START:
3410 case XML_XINCLUDE_END:
3411#ifdef LIBXML_SGML_ENABLED
3412 case XML_SGML_DOCUMENT_NODE:
3413#endif
3414 break;
3415 case XML_NOTATION_NODE:
3416 break;
3417 case XML_DTD_NODE:
3418 break;
3419 case XML_NAMESPACE_DECL:
3420 break;
3421 case XML_ELEMENT_DECL:
3422 /* TODO !!! */
3423 break;
3424 case XML_ATTRIBUTE_DECL:
3425 /* TODO !!! */
3426 break;
3427 case XML_ENTITY_DECL:
3428 /* TODO !!! */
3429 break;
3430 }
3431}
3432
3433/**
3434 * xmlNodeSetContentLen:
3435 * @cur: the node being modified
3436 * @content: the new value of the content
3437 * @len: the size of @content
3438 *
3439 * Replace the content of a node.
3440 */
3441void
3442xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3443 if (cur == NULL) {
3444#ifdef DEBUG_TREE
3445 xmlGenericError(xmlGenericErrorContext,
3446 "xmlNodeSetContentLen : node == NULL\n");
3447#endif
3448 return;
3449 }
3450 switch (cur->type) {
3451 case XML_DOCUMENT_FRAG_NODE:
3452 case XML_ELEMENT_NODE:
3453 if (cur->content != NULL) {
3454#ifndef XML_USE_BUFFER_CONTENT
3455 xmlFree(cur->content);
3456#else
3457 xmlBufferFree(cur->content);
3458#endif
3459 cur->content = NULL;
3460 }
3461 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3462 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3463 UPDATE_LAST_CHILD_AND_PARENT(cur)
3464 break;
3465 case XML_ATTRIBUTE_NODE:
3466 break;
3467 case XML_TEXT_NODE:
3468 case XML_CDATA_SECTION_NODE:
3469 case XML_ENTITY_REF_NODE:
3470 case XML_ENTITY_NODE:
3471 case XML_PI_NODE:
3472 case XML_COMMENT_NODE:
3473 case XML_NOTATION_NODE:
3474 if (cur->content != NULL) {
3475#ifndef XML_USE_BUFFER_CONTENT
3476 xmlFree(cur->content);
3477#else
3478 xmlBufferFree(cur->content);
3479#endif
3480 }
3481 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3482 cur->children = cur->last = NULL;
3483 if (content != NULL) {
3484#ifndef XML_USE_BUFFER_CONTENT
3485 cur->content = xmlStrndup(content, len);
3486#else
3487 cur->content = xmlBufferCreateSize(len);
3488 xmlBufferSetAllocationScheme(cur->content,
3489 xmlGetBufferAllocationScheme());
3490 xmlBufferAdd(cur->content, content, len);
3491#endif
3492 } else
3493 cur->content = NULL;
3494 break;
3495 case XML_DOCUMENT_NODE:
3496 case XML_DTD_NODE:
3497 case XML_HTML_DOCUMENT_NODE:
3498 case XML_DOCUMENT_TYPE_NODE:
3499 case XML_NAMESPACE_DECL:
3500 case XML_XINCLUDE_START:
3501 case XML_XINCLUDE_END:
3502#ifdef LIBXML_SGML_ENABLED
3503 case XML_SGML_DOCUMENT_NODE:
3504#endif
3505 break;
3506 case XML_ELEMENT_DECL:
3507 /* TODO !!! */
3508 break;
3509 case XML_ATTRIBUTE_DECL:
3510 /* TODO !!! */
3511 break;
3512 case XML_ENTITY_DECL:
3513 /* TODO !!! */
3514 break;
3515 }
3516}
3517
3518/**
3519 * xmlNodeAddContentLen:
3520 * @cur: the node being modified
3521 * @content: extra content
3522 * @len: the size of @content
3523 *
3524 * Append the extra substring to the node content.
3525 */
3526void
3527xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3528 if (cur == NULL) {
3529#ifdef DEBUG_TREE
3530 xmlGenericError(xmlGenericErrorContext,
3531 "xmlNodeAddContentLen : node == NULL\n");
3532#endif
3533 return;
3534 }
3535 if (len <= 0) return;
3536 switch (cur->type) {
3537 case XML_DOCUMENT_FRAG_NODE:
3538 case XML_ELEMENT_NODE: {
3539 xmlNodePtr last = NULL, newNode;
3540
3541 if (cur->children != NULL) {
3542 last = cur->last;
3543 } else {
3544 if (cur->content != NULL) {
3545#ifndef XML_USE_BUFFER_CONTENT
3546 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
3547#else
3548 cur->children = xmlStringGetNodeList(cur->doc,
3549 xmlBufferContent(cur->content));
3550#endif
3551 UPDATE_LAST_CHILD_AND_PARENT(cur)
3552#ifndef XML_USE_BUFFER_CONTENT
3553 xmlFree(cur->content);
3554#else
3555 xmlBufferFree(cur->content);
3556#endif
3557 cur->content = NULL;
3558 last = cur->last;
3559 }
3560 }
3561 newNode = xmlNewTextLen(content, len);
3562 if (newNode != NULL) {
3563 xmlAddChild(cur, newNode);
3564 if ((last != NULL) && (last->next == newNode)) {
3565 xmlTextMerge(last, newNode);
3566 }
3567 }
3568 break;
3569 }
3570 case XML_ATTRIBUTE_NODE:
3571 break;
3572 case XML_TEXT_NODE:
3573 case XML_CDATA_SECTION_NODE:
3574 case XML_ENTITY_REF_NODE:
3575 case XML_ENTITY_NODE:
3576 case XML_PI_NODE:
3577 case XML_COMMENT_NODE:
3578 case XML_NOTATION_NODE:
3579 if (content != NULL) {
3580#ifndef XML_USE_BUFFER_CONTENT
3581 cur->content = xmlStrncat(cur->content, content, len);
3582#else
3583 xmlBufferAdd(cur->content, content, len);
3584#endif
3585 }
3586 case XML_DOCUMENT_NODE:
3587 case XML_DTD_NODE:
3588 case XML_HTML_DOCUMENT_NODE:
3589 case XML_DOCUMENT_TYPE_NODE:
3590 case XML_NAMESPACE_DECL:
3591 case XML_XINCLUDE_START:
3592 case XML_XINCLUDE_END:
3593#ifdef LIBXML_SGML_ENABLED
3594 case XML_SGML_DOCUMENT_NODE:
3595#endif
3596 break;
3597 case XML_ELEMENT_DECL:
3598 case XML_ATTRIBUTE_DECL:
3599 case XML_ENTITY_DECL:
3600 break;
3601 }
3602}
3603
3604/**
3605 * xmlNodeAddContent:
3606 * @cur: the node being modified
3607 * @content: extra content
3608 *
3609 * Append the extra substring to the node content.
3610 */
3611void
3612xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3613 int len;
3614
3615 if (cur == NULL) {
3616#ifdef DEBUG_TREE
3617 xmlGenericError(xmlGenericErrorContext,
3618 "xmlNodeAddContent : node == NULL\n");
3619#endif
3620 return;
3621 }
3622 if (content == NULL) return;
3623 len = xmlStrlen(content);
3624 xmlNodeAddContentLen(cur, content, len);
3625}
3626
3627/**
3628 * xmlTextMerge:
3629 * @first: the first text node
3630 * @second: the second text node being merged
3631 *
3632 * Merge two text nodes into one
3633 * Returns the first text node augmented
3634 */
3635xmlNodePtr
3636xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3637 if (first == NULL) return(second);
3638 if (second == NULL) return(first);
3639 if (first->type != XML_TEXT_NODE) return(first);
3640 if (second->type != XML_TEXT_NODE) return(first);
3641 if (second->name != first->name)
3642 return(first);
3643#ifndef XML_USE_BUFFER_CONTENT
3644 xmlNodeAddContent(first, second->content);
3645#else
3646 xmlNodeAddContent(first, xmlBufferContent(second->content));
3647#endif
3648 xmlUnlinkNode(second);
3649 xmlFreeNode(second);
3650 return(first);
3651}
3652
3653/**
3654 * xmlGetNsList:
3655 * @doc: the document
3656 * @node: the current node
3657 *
3658 * Search all the namespace applying to a given element.
3659 * Returns an NULL terminated array of all the xmlNsPtr found
3660 * that need to be freed by the caller or NULL if no
3661 * namespace if defined
3662 */
3663xmlNsPtr *
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003664xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003665 xmlNsPtr cur;
3666 xmlNsPtr *ret = NULL;
3667 int nbns = 0;
3668 int maxns = 10;
3669 int i;
3670
3671 while (node != NULL) {
3672 cur = node->nsDef;
3673 while (cur != NULL) {
3674 if (ret == NULL) {
3675 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
3676 if (ret == NULL) {
3677 xmlGenericError(xmlGenericErrorContext,
3678 "xmlGetNsList : out of memory!\n");
3679 return(NULL);
3680 }
3681 ret[nbns] = NULL;
3682 }
3683 for (i = 0;i < nbns;i++) {
3684 if ((cur->prefix == ret[i]->prefix) ||
3685 (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
3686 }
3687 if (i >= nbns) {
3688 if (nbns >= maxns) {
3689 maxns *= 2;
3690 ret = (xmlNsPtr *) xmlRealloc(ret,
3691 (maxns + 1) * sizeof(xmlNsPtr));
3692 if (ret == NULL) {
3693 xmlGenericError(xmlGenericErrorContext,
3694 "xmlGetNsList : realloc failed!\n");
3695 return(NULL);
3696 }
3697 }
3698 ret[nbns++] = cur;
3699 ret[nbns] = NULL;
3700 }
3701
3702 cur = cur->next;
3703 }
3704 node = node->parent;
3705 }
3706 return(ret);
3707}
3708
3709/**
3710 * xmlSearchNs:
3711 * @doc: the document
3712 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00003713 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00003714 *
3715 * Search a Ns registered under a given name space for a document.
3716 * recurse on the parents until it finds the defined namespace
3717 * or return NULL otherwise.
3718 * @nameSpace can be NULL, this is a search for the default namespace.
3719 * We don't allow to cross entities boundaries. If you don't declare
3720 * the namespace within those you will be in troubles !!! A warning
3721 * is generated to cover this case.
3722 *
3723 * Returns the namespace pointer or NULL.
3724 */
3725xmlNsPtr
3726xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
3727 xmlNsPtr cur;
3728
3729 if (node == NULL) return(NULL);
3730 if ((nameSpace != NULL) &&
3731 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
3732 if (doc->oldNs == NULL) {
3733 /*
3734 * Allocate a new Namespace and fill the fields.
3735 */
3736 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3737 if (doc->oldNs == NULL) {
3738 xmlGenericError(xmlGenericErrorContext,
3739 "xmlSearchNsByHref : malloc failed\n");
3740 return(NULL);
3741 }
3742 memset(doc->oldNs, 0, sizeof(xmlNs));
3743 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3744
3745 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3746 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3747 }
3748 return(doc->oldNs);
3749 }
3750 while (node != NULL) {
3751 if ((node->type == XML_ENTITY_REF_NODE) ||
3752 (node->type == XML_ENTITY_NODE) ||
3753 (node->type == XML_ENTITY_DECL))
3754 return(NULL);
3755 if (node->type == XML_ELEMENT_NODE) {
3756 cur = node->nsDef;
3757 while (cur != NULL) {
3758 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3759 (cur->href != NULL))
3760 return(cur);
3761 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
3762 (cur->href != NULL) &&
3763 (xmlStrEqual(cur->prefix, nameSpace)))
3764 return(cur);
3765 cur = cur->next;
3766 }
3767 }
3768 node = node->parent;
3769 }
3770 return(NULL);
3771}
3772
3773/**
3774 * xmlSearchNsByHref:
3775 * @doc: the document
3776 * @node: the current node
3777 * @href: the namespace value
3778 *
3779 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3780 * the defined namespace or return NULL otherwise.
3781 * Returns the namespace pointer or NULL.
3782 */
3783xmlNsPtr
3784xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
3785 xmlNsPtr cur;
3786 xmlNodePtr orig = node;
3787
3788 if ((node == NULL) || (href == NULL)) return(NULL);
3789 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
3790 if (doc->oldNs == NULL) {
3791 /*
3792 * Allocate a new Namespace and fill the fields.
3793 */
3794 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3795 if (doc->oldNs == NULL) {
3796 xmlGenericError(xmlGenericErrorContext,
3797 "xmlSearchNsByHref : malloc failed\n");
3798 return(NULL);
3799 }
3800 memset(doc->oldNs, 0, sizeof(xmlNs));
3801 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3802
3803 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3804 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3805 }
3806 return(doc->oldNs);
3807 }
3808 while (node != NULL) {
3809 cur = node->nsDef;
3810 while (cur != NULL) {
3811 if ((cur->href != NULL) && (href != NULL) &&
3812 (xmlStrEqual(cur->href, href))) {
3813 /*
3814 * Check that the prefix is not shadowed between orig and node
3815 */
3816 xmlNodePtr check = orig;
3817 xmlNsPtr tst;
3818
3819 while (check != node) {
3820 tst = check->nsDef;
3821 while (tst != NULL) {
3822 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3823 goto shadowed;
3824 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
3825 (xmlStrEqual(tst->prefix, cur->prefix)))
3826 goto shadowed;
3827 tst = tst->next;
3828 }
3829 check = check->parent;
3830 }
3831 return(cur);
3832 }
3833shadowed:
3834 cur = cur->next;
3835 }
3836 node = node->parent;
3837 }
3838 return(NULL);
3839}
3840
3841/**
3842 * xmlNewReconciliedNs
3843 * @doc: the document
3844 * @tree: a node expected to hold the new namespace
3845 * @ns: the original namespace
3846 *
3847 * This function tries to locate a namespace definition in a tree
3848 * ancestors, or create a new namespace definition node similar to
3849 * @ns trying to reuse the same prefix. However if the given prefix is
3850 * null (default namespace) or reused within the subtree defined by
3851 * @tree or on one of its ancestors then a new prefix is generated.
3852 * Returns the (new) namespace definition or NULL in case of error
3853 */
3854xmlNsPtr
3855xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3856 xmlNsPtr def;
3857 xmlChar prefix[50];
3858 int counter = 1;
3859
3860 if (tree == NULL) {
3861#ifdef DEBUG_TREE
3862 xmlGenericError(xmlGenericErrorContext,
3863 "xmlNewReconciliedNs : tree == NULL\n");
3864#endif
3865 return(NULL);
3866 }
3867 if (ns == NULL) {
3868#ifdef DEBUG_TREE
3869 xmlGenericError(xmlGenericErrorContext,
3870 "xmlNewReconciliedNs : ns == NULL\n");
3871#endif
3872 return(NULL);
3873 }
3874 /*
3875 * Search an existing namespace definition inherited.
3876 */
3877 def = xmlSearchNsByHref(doc, tree, ns->href);
3878 if (def != NULL)
3879 return(def);
3880
3881 /*
3882 * Find a close prefix which is not already in use.
3883 * Let's strip namespace prefixes longer than 20 chars !
3884 */
3885 sprintf((char *) prefix, "%.20s", ns->prefix);
3886 def = xmlSearchNs(doc, tree, prefix);
3887 while (def != NULL) {
3888 if (counter > 1000) return(NULL);
3889 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3890 def = xmlSearchNs(doc, tree, prefix);
3891 }
3892
3893 /*
3894 * Ok, now we are ready to create a new one.
3895 */
3896 def = xmlNewNs(tree, ns->href, prefix);
3897 return(def);
3898}
3899
3900/**
3901 * xmlReconciliateNs
3902 * @doc: the document
3903 * @tree: a node defining the subtree to reconciliate
3904 *
3905 * This function checks that all the namespaces declared within the given
3906 * tree are properly declared. This is needed for example after Copy or Cut
3907 * and then paste operations. The subtree may still hold pointers to
3908 * namespace declarations outside the subtree or invalid/masked. As much
3909 * as possible the function try tu reuse the existing namespaces found in
3910 * the new environment. If not possible the new namespaces are redeclared
3911 * on @tree at the top of the given subtree.
3912 * Returns the number of namespace declarations created or -1 in case of error.
3913 */
3914int
3915xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3916 xmlNsPtr *oldNs = NULL;
3917 xmlNsPtr *newNs = NULL;
3918 int sizeCache = 0;
3919 int nbCache = 0;
3920
3921 xmlNsPtr n;
3922 xmlNodePtr node = tree;
3923 xmlAttrPtr attr;
3924 int ret = 0, i;
3925
3926 while (node != NULL) {
3927 /*
3928 * Reconciliate the node namespace
3929 */
3930 if (node->ns != NULL) {
3931 /*
3932 * initialize the cache if needed
3933 */
3934 if (sizeCache == 0) {
3935 sizeCache = 10;
3936 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3937 sizeof(xmlNsPtr));
3938 if (oldNs == NULL) {
3939 xmlGenericError(xmlGenericErrorContext,
3940 "xmlReconciliateNs : memory pbm\n");
3941 return(-1);
3942 }
3943 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3944 sizeof(xmlNsPtr));
3945 if (newNs == NULL) {
3946 xmlGenericError(xmlGenericErrorContext,
3947 "xmlReconciliateNs : memory pbm\n");
3948 xmlFree(oldNs);
3949 return(-1);
3950 }
3951 }
3952 for (i = 0;i < nbCache;i++) {
3953 if (oldNs[i] == node->ns) {
3954 node->ns = newNs[i];
3955 break;
3956 }
3957 }
3958 if (i == nbCache) {
3959 /*
3960 * Ok we need to recreate a new namespace definition
3961 */
3962 n = xmlNewReconciliedNs(doc, tree, node->ns);
3963 if (n != NULL) { /* :-( what if else ??? */
3964 /*
3965 * check if we need to grow the cache buffers.
3966 */
3967 if (sizeCache <= nbCache) {
3968 sizeCache *= 2;
3969 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3970 sizeof(xmlNsPtr));
3971 if (oldNs == NULL) {
3972 xmlGenericError(xmlGenericErrorContext,
3973 "xmlReconciliateNs : memory pbm\n");
3974 xmlFree(newNs);
3975 return(-1);
3976 }
3977 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3978 sizeof(xmlNsPtr));
3979 if (newNs == NULL) {
3980 xmlGenericError(xmlGenericErrorContext,
3981 "xmlReconciliateNs : memory pbm\n");
3982 xmlFree(oldNs);
3983 return(-1);
3984 }
3985 }
3986 newNs[nbCache] = n;
3987 oldNs[nbCache++] = node->ns;
3988 node->ns = n;
3989 }
3990 }
3991 }
3992 /*
3993 * now check for namespace hold by attributes on the node.
3994 */
3995 attr = node->properties;
3996 while (attr != NULL) {
3997 if (attr->ns != NULL) {
3998 /*
3999 * initialize the cache if needed
4000 */
4001 if (sizeCache == 0) {
4002 sizeCache = 10;
4003 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4004 sizeof(xmlNsPtr));
4005 if (oldNs == NULL) {
4006 xmlGenericError(xmlGenericErrorContext,
4007 "xmlReconciliateNs : memory pbm\n");
4008 return(-1);
4009 }
4010 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4011 sizeof(xmlNsPtr));
4012 if (newNs == NULL) {
4013 xmlGenericError(xmlGenericErrorContext,
4014 "xmlReconciliateNs : memory pbm\n");
4015 xmlFree(oldNs);
4016 return(-1);
4017 }
4018 }
4019 for (i = 0;i < nbCache;i++) {
4020 if (oldNs[i] == attr->ns) {
4021 node->ns = newNs[i];
4022 break;
4023 }
4024 }
4025 if (i == nbCache) {
4026 /*
4027 * Ok we need to recreate a new namespace definition
4028 */
4029 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4030 if (n != NULL) { /* :-( what if else ??? */
4031 /*
4032 * check if we need to grow the cache buffers.
4033 */
4034 if (sizeCache <= nbCache) {
4035 sizeCache *= 2;
4036 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4037 sizeof(xmlNsPtr));
4038 if (oldNs == NULL) {
4039 xmlGenericError(xmlGenericErrorContext,
4040 "xmlReconciliateNs : memory pbm\n");
4041 xmlFree(newNs);
4042 return(-1);
4043 }
4044 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4045 sizeof(xmlNsPtr));
4046 if (newNs == NULL) {
4047 xmlGenericError(xmlGenericErrorContext,
4048 "xmlReconciliateNs : memory pbm\n");
4049 xmlFree(oldNs);
4050 return(-1);
4051 }
4052 }
4053 newNs[nbCache] = n;
4054 oldNs[nbCache++] = attr->ns;
4055 attr->ns = n;
4056 }
4057 }
4058 }
4059 attr = attr->next;
4060 }
4061
4062 /*
4063 * Browse the full subtree, deep first
4064 */
4065 if (node->children != NULL) {
4066 /* deep first */
4067 node = node->children;
4068 } else if ((node != tree) && (node->next != NULL)) {
4069 /* then siblings */
4070 node = node->next;
4071 } else if (node != tree) {
4072 /* go up to parents->next if needed */
4073 while (node != tree) {
4074 if (node->parent != NULL)
4075 node = node->parent;
4076 if ((node != tree) && (node->next != NULL)) {
4077 node = node->next;
4078 break;
4079 }
4080 if (node->parent == NULL) {
4081 node = NULL;
4082 break;
4083 }
4084 }
4085 /* exit condition */
4086 if (node == tree)
4087 node = NULL;
4088 }
4089 }
4090 return(ret);
4091}
4092
4093/**
4094 * xmlHasProp:
4095 * @node: the node
4096 * @name: the attribute name
4097 *
4098 * Search an attribute associated to a node
4099 * This function also looks in DTD attribute declaration for #FIXED or
4100 * default declaration values unless DTD use has been turned off.
4101 *
4102 * Returns the attribute or the attribute declaration or NULL if
4103 * neither was found.
4104 */
4105xmlAttrPtr
4106xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4107 xmlAttrPtr prop;
4108 xmlDocPtr doc;
4109
4110 if ((node == NULL) || (name == NULL)) return(NULL);
4111 /*
4112 * Check on the properties attached to the node
4113 */
4114 prop = node->properties;
4115 while (prop != NULL) {
4116 if (xmlStrEqual(prop->name, name)) {
4117 return(prop);
4118 }
4119 prop = prop->next;
4120 }
4121 if (!xmlCheckDTD) return(NULL);
4122
4123 /*
4124 * Check if there is a default declaration in the internal
4125 * or external subsets
4126 */
4127 doc = node->doc;
4128 if (doc != NULL) {
4129 xmlAttributePtr attrDecl;
4130 if (doc->intSubset != NULL) {
4131 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4132 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4133 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4134 if (attrDecl != NULL)
4135 return((xmlAttrPtr) attrDecl);
4136 }
4137 }
4138 return(NULL);
4139}
4140
4141/**
4142 * xmlGetProp:
4143 * @node: the node
4144 * @name: the attribute name
4145 *
4146 * Search and get the value of an attribute associated to a node
4147 * This does the entity substitution.
4148 * This function looks in DTD attribute declaration for #FIXED or
4149 * default declaration values unless DTD use has been turned off.
4150 *
4151 * Returns the attribute value or NULL if not found.
4152 * It's up to the caller to free the memory.
4153 */
4154xmlChar *
4155xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4156 xmlAttrPtr prop;
4157 xmlDocPtr doc;
4158
4159 if ((node == NULL) || (name == NULL)) return(NULL);
4160 /*
4161 * Check on the properties attached to the node
4162 */
4163 prop = node->properties;
4164 while (prop != NULL) {
4165 if (xmlStrEqual(prop->name, name)) {
4166 xmlChar *ret;
4167
4168 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4169 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4170 return(ret);
4171 }
4172 prop = prop->next;
4173 }
4174 if (!xmlCheckDTD) return(NULL);
4175
4176 /*
4177 * Check if there is a default declaration in the internal
4178 * or external subsets
4179 */
4180 doc = node->doc;
4181 if (doc != NULL) {
4182 xmlAttributePtr attrDecl;
4183 if (doc->intSubset != NULL) {
4184 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4185 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4186 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4187 if (attrDecl != NULL)
4188 return(xmlStrdup(attrDecl->defaultValue));
4189 }
4190 }
4191 return(NULL);
4192}
4193
4194/**
4195 * xmlGetNsProp:
4196 * @node: the node
4197 * @name: the attribute name
4198 * @namespace: the URI of the namespace
4199 *
4200 * Search and get the value of an attribute associated to a node
4201 * This attribute has to be anchored in the namespace specified.
4202 * This does the entity substitution.
4203 * This function looks in DTD attribute declaration for #FIXED or
4204 * default declaration values unless DTD use has been turned off.
4205 *
4206 * Returns the attribute value or NULL if not found.
4207 * It's up to the caller to free the memory.
4208 */
4209xmlChar *
4210xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
4211 xmlAttrPtr prop;
4212 xmlDocPtr doc;
4213 xmlNsPtr ns;
4214
4215 if (node == NULL)
4216 return(NULL);
4217
4218 prop = node->properties;
4219 if (namespace == NULL)
4220 return(xmlGetProp(node, name));
4221 while (prop != NULL) {
4222 /*
4223 * One need to have
4224 * - same attribute names
4225 * - and the attribute carrying that namespace
4226 * or
4227 * no namespace on the attribute and the element carrying it
4228 */
4229 if ((xmlStrEqual(prop->name, name)) &&
4230 (((prop->ns == NULL) && (node->ns != NULL) &&
4231 (xmlStrEqual(node->ns->href, namespace))) ||
4232 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
4233 xmlChar *ret;
4234
4235 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4236 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4237 return(ret);
4238 }
4239 prop = prop->next;
4240 }
4241 if (!xmlCheckDTD) return(NULL);
4242
4243 /*
4244 * Check if there is a default declaration in the internal
4245 * or external subsets
4246 */
4247 doc = node->doc;
4248 if (doc != NULL) {
4249 xmlAttributePtr attrDecl;
4250 if (doc->intSubset != NULL) {
4251 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4252 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4253 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4254
4255 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4256 /*
4257 * The DTD declaration only allows a prefix search
4258 */
4259 ns = xmlSearchNs(doc, node, attrDecl->prefix);
4260 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
4261 return(xmlStrdup(attrDecl->defaultValue));
4262 }
4263 }
4264 }
4265 return(NULL);
4266}
4267
4268/**
4269 * xmlSetProp:
4270 * @node: the node
4271 * @name: the attribute name
4272 * @value: the attribute value
4273 *
4274 * Set (or reset) an attribute carried by a node.
4275 * Returns the attribute pointer.
4276 */
4277xmlAttrPtr
4278xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
4279 xmlAttrPtr prop = node->properties;
4280 xmlDocPtr doc = NULL;
4281
4282 if ((node == NULL) || (name == NULL))
4283 return(NULL);
4284 doc = node->doc;
4285 while (prop != NULL) {
4286 if (xmlStrEqual(prop->name, name)) {
4287 if (prop->children != NULL)
4288 xmlFreeNodeList(prop->children);
4289 prop->children = NULL;
4290 prop->last = NULL;
4291 if (value != NULL) {
4292 xmlChar *buffer;
4293 xmlNodePtr tmp;
4294
4295 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4296 prop->children = xmlStringGetNodeList(node->doc, buffer);
4297 prop->last = NULL;
4298 prop->doc = doc;
4299 tmp = prop->children;
4300 while (tmp != NULL) {
4301 tmp->parent = (xmlNodePtr) prop;
4302 tmp->doc = doc;
4303 if (tmp->next == NULL)
4304 prop->last = tmp;
4305 tmp = tmp->next;
4306 }
4307 xmlFree(buffer);
4308 }
4309 return(prop);
4310 }
4311 prop = prop->next;
4312 }
4313 prop = xmlNewProp(node, name, value);
4314 return(prop);
4315}
4316
4317/**
4318 * xmlSetNsProp:
4319 * @node: the node
4320 * @ns: the namespace definition
4321 * @name: the attribute name
4322 * @value: the attribute value
4323 *
4324 * Set (or reset) an attribute carried by a node.
4325 * The ns structure must be in scope, this is not checked.
4326 *
4327 * Returns the attribute pointer.
4328 */
4329xmlAttrPtr
4330xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4331 const xmlChar *value) {
4332 xmlAttrPtr prop;
4333
4334 if ((node == NULL) || (name == NULL))
4335 return(NULL);
4336
4337 if (ns == NULL)
4338 return(xmlSetProp(node, name, value));
4339 if (ns->href == NULL)
4340 return(NULL);
4341 prop = node->properties;
4342
4343 while (prop != NULL) {
4344 /*
4345 * One need to have
4346 * - same attribute names
4347 * - and the attribute carrying that namespace
4348 * or
4349 * no namespace on the attribute and the element carrying it
4350 */
4351 if ((xmlStrEqual(prop->name, name)) &&
4352 (((prop->ns == NULL) && (node->ns != NULL) &&
4353 (xmlStrEqual(node->ns->href, ns->href))) ||
4354 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4355 if (prop->children != NULL)
4356 xmlFreeNodeList(prop->children);
4357 prop->children = NULL;
4358 prop->last = NULL;
4359 prop->ns = ns;
4360 if (value != NULL) {
4361 xmlChar *buffer;
4362 xmlNodePtr tmp;
4363
4364 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4365 prop->children = xmlStringGetNodeList(node->doc, buffer);
4366 prop->last = NULL;
4367 tmp = prop->children;
4368 while (tmp != NULL) {
4369 tmp->parent = (xmlNodePtr) prop;
4370 if (tmp->next == NULL)
4371 prop->last = tmp;
4372 tmp = tmp->next;
4373 }
4374 xmlFree(buffer);
4375 }
4376 return(prop);
4377 }
4378 prop = prop->next;
4379 }
4380 prop = xmlNewNsProp(node, ns, name, value);
4381 return(prop);
4382}
4383
4384/**
4385 * xmlNodeIsText:
4386 * @node: the node
4387 *
4388 * Is this node a Text node ?
4389 * Returns 1 yes, 0 no
4390 */
4391int
4392xmlNodeIsText(xmlNodePtr node) {
4393 if (node == NULL) return(0);
4394
4395 if (node->type == XML_TEXT_NODE) return(1);
4396 return(0);
4397}
4398
4399/**
4400 * xmlIsBlankNode:
4401 * @node: the node
4402 *
4403 * Checks whether this node is an empty or whitespace only
4404 * (and possibly ignorable) text-node.
4405 *
4406 * Returns 1 yes, 0 no
4407 */
4408int
4409xmlIsBlankNode(xmlNodePtr node) {
4410 const xmlChar *cur;
4411 if (node == NULL) return(0);
4412
4413 if (node->type != XML_TEXT_NODE) return(0);
4414 if (node->content == NULL) return(1);
4415#ifndef XML_USE_BUFFER_CONTENT
4416 cur = node->content;
4417#else
4418 cur = xmlBufferContent(node->content);
4419#endif
4420 while (*cur != 0) {
4421 if (!IS_BLANK(*cur)) return(0);
4422 cur++;
4423 }
4424
4425 return(1);
4426}
4427
4428/**
4429 * xmlTextConcat:
4430 * @node: the node
4431 * @content: the content
4432 * @len: @content lenght
4433 *
4434 * Concat the given string at the end of the existing node content
4435 */
4436
4437void
4438xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4439 if (node == NULL) return;
4440
4441 if ((node->type != XML_TEXT_NODE) &&
4442 (node->type != XML_CDATA_SECTION_NODE)) {
4443#ifdef DEBUG_TREE
4444 xmlGenericError(xmlGenericErrorContext,
4445 "xmlTextConcat: node is not text nor cdata\n");
4446#endif
4447 return;
4448 }
4449#ifndef XML_USE_BUFFER_CONTENT
4450 node->content = xmlStrncat(node->content, content, len);
4451#else
4452 xmlBufferAdd(node->content, content, len);
4453#endif
4454}
4455
4456/************************************************************************
4457 * *
4458 * Output : to a FILE or in memory *
4459 * *
4460 ************************************************************************/
4461
4462#define BASE_BUFFER_SIZE 4000
4463
Daniel Veillarde356c282001-03-10 12:32:04 +00004464int xmlDefaultBufferSize = BASE_BUFFER_SIZE;
4465
Owen Taylor3473f882001-02-23 17:55:21 +00004466/**
4467 * xmlBufferCreate:
4468 *
4469 * routine to create an XML buffer.
4470 * returns the new structure.
4471 */
4472xmlBufferPtr
4473xmlBufferCreate(void) {
4474 xmlBufferPtr ret;
4475
4476 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4477 if (ret == NULL) {
4478 xmlGenericError(xmlGenericErrorContext,
4479 "xmlBufferCreate : out of memory!\n");
4480 return(NULL);
4481 }
4482 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004483 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004484 ret->alloc = xmlBufferAllocScheme;
4485 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4486 if (ret->content == NULL) {
4487 xmlGenericError(xmlGenericErrorContext,
4488 "xmlBufferCreate : out of memory!\n");
4489 xmlFree(ret);
4490 return(NULL);
4491 }
4492 ret->content[0] = 0;
4493 return(ret);
4494}
4495
4496/**
4497 * xmlBufferCreateSize:
4498 * @size: initial size of buffer
4499 *
4500 * routine to create an XML buffer.
4501 * returns the new structure.
4502 */
4503xmlBufferPtr
4504xmlBufferCreateSize(size_t size) {
4505 xmlBufferPtr ret;
4506
4507 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4508 if (ret == NULL) {
4509 xmlGenericError(xmlGenericErrorContext,
4510 "xmlBufferCreate : out of memory!\n");
4511 return(NULL);
4512 }
4513 ret->use = 0;
4514 ret->alloc = xmlBufferAllocScheme;
4515 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4516 if (ret->size){
4517 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4518 if (ret->content == NULL) {
4519 xmlGenericError(xmlGenericErrorContext,
4520 "xmlBufferCreate : out of memory!\n");
4521 xmlFree(ret);
4522 return(NULL);
4523 }
4524 ret->content[0] = 0;
4525 } else
4526 ret->content = NULL;
4527 return(ret);
4528}
4529
4530/**
4531 * xmlBufferSetAllocationScheme:
4532 * @buf: the buffer to free
4533 * @scheme: allocation scheme to use
4534 *
4535 * Sets the allocation scheme for this buffer
4536 */
4537void
4538xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4539 xmlBufferAllocationScheme scheme) {
4540 if (buf == NULL) {
4541#ifdef DEBUG_BUFFER
4542 xmlGenericError(xmlGenericErrorContext,
4543 "xmlBufferSetAllocationScheme: buf == NULL\n");
4544#endif
4545 return;
4546 }
4547
4548 buf->alloc = scheme;
4549}
4550
4551/**
4552 * xmlBufferFree:
4553 * @buf: the buffer to free
4554 *
4555 * Frees an XML buffer.
4556 */
4557void
4558xmlBufferFree(xmlBufferPtr buf) {
4559 if (buf == NULL) {
4560#ifdef DEBUG_BUFFER
4561 xmlGenericError(xmlGenericErrorContext,
4562 "xmlBufferFree: buf == NULL\n");
4563#endif
4564 return;
4565 }
4566 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004567 xmlFree(buf->content);
4568 }
Owen Taylor3473f882001-02-23 17:55:21 +00004569 xmlFree(buf);
4570}
4571
4572/**
4573 * xmlBufferEmpty:
4574 * @buf: the buffer
4575 *
4576 * empty a buffer.
4577 */
4578void
4579xmlBufferEmpty(xmlBufferPtr buf) {
4580 if (buf->content == NULL) return;
4581 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004582 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004583}
4584
4585/**
4586 * xmlBufferShrink:
4587 * @buf: the buffer to dump
4588 * @len: the number of xmlChar to remove
4589 *
4590 * Remove the beginning of an XML buffer.
4591 *
4592 * Returns the number of xmlChar removed, or -1 in case of failure.
4593 */
4594int
4595xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
4596 if (len == 0) return(0);
4597 if (len > buf->use) return(-1);
4598
4599 buf->use -= len;
4600 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
4601
4602 buf->content[buf->use] = 0;
4603 return(len);
4604}
4605
4606/**
4607 * xmlBufferGrow:
4608 * @buf: the buffer
4609 * @len: the minimum free size to allocate
4610 *
4611 * Grow the available space of an XML buffer.
4612 *
4613 * Returns the new available space or -1 in case of error
4614 */
4615int
4616xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
4617 int size;
4618 xmlChar *newbuf;
4619
4620 if (len + buf->use < buf->size) return(0);
4621
4622 size = buf->use + len + 100;
4623
4624 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
4625 if (newbuf == NULL) return(-1);
4626 buf->content = newbuf;
4627 buf->size = size;
4628 return(buf->size - buf->use);
4629}
4630
4631/**
4632 * xmlBufferDump:
4633 * @file: the file output
4634 * @buf: the buffer to dump
4635 *
4636 * Dumps an XML buffer to a FILE *.
4637 * Returns the number of xmlChar written
4638 */
4639int
4640xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4641 int ret;
4642
4643 if (buf == NULL) {
4644#ifdef DEBUG_BUFFER
4645 xmlGenericError(xmlGenericErrorContext,
4646 "xmlBufferDump: buf == NULL\n");
4647#endif
4648 return(0);
4649 }
4650 if (buf->content == NULL) {
4651#ifdef DEBUG_BUFFER
4652 xmlGenericError(xmlGenericErrorContext,
4653 "xmlBufferDump: buf->content == NULL\n");
4654#endif
4655 return(0);
4656 }
4657 if (file == NULL) file = stdout;
4658 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
4659 return(ret);
4660}
4661
4662/**
4663 * xmlBufferContent:
4664 * @buf: the buffer
4665 *
4666 * Returns the internal content
4667 */
4668
4669const xmlChar*
4670xmlBufferContent(const xmlBufferPtr buf)
4671{
4672 if(!buf)
4673 return NULL;
4674
4675 return buf->content;
4676}
4677
4678/**
4679 * xmlBufferLength:
4680 * @buf: the buffer
4681 *
4682 * Returns the length of data in the internal content
4683 */
4684
4685int
4686xmlBufferLength(const xmlBufferPtr buf)
4687{
4688 if(!buf)
4689 return 0;
4690
4691 return buf->use;
4692}
4693
4694/**
4695 * xmlBufferResize:
4696 * @buf: the buffer to resize
4697 * @size: the desired size
4698 *
4699 * Resize a buffer to accomodate minimum size of @size.
4700 *
4701 * Returns 0 in case of problems, 1 otherwise
4702 */
4703int
4704xmlBufferResize(xmlBufferPtr buf, unsigned int size)
4705{
4706 unsigned int newSize;
4707 xmlChar* rebuf = NULL;
4708
4709 /*take care of empty case*/
4710 newSize = (buf->size ? buf->size*2 : size);
4711
4712 /* Don't resize if we don't have to */
4713 if (size < buf->size)
4714 return 1;
4715
4716 /* figure out new size */
4717 switch (buf->alloc){
4718 case XML_BUFFER_ALLOC_DOUBLEIT:
4719 while (size > newSize) newSize *= 2;
4720 break;
4721 case XML_BUFFER_ALLOC_EXACT:
4722 newSize = size+10;
4723 break;
4724 default:
4725 newSize = size+10;
4726 break;
4727 }
4728
4729 if (buf->content == NULL)
4730 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4731 else
4732 rebuf = (xmlChar *) xmlRealloc(buf->content,
4733 newSize * sizeof(xmlChar));
4734 if (rebuf == NULL) {
4735 xmlGenericError(xmlGenericErrorContext,
4736 "xmlBufferAdd : out of memory!\n");
4737 return 0;
4738 }
4739 buf->content = rebuf;
4740 buf->size = newSize;
4741
4742 return 1;
4743}
4744
4745/**
4746 * xmlBufferAdd:
4747 * @buf: the buffer to dump
4748 * @str: the xmlChar string
4749 * @len: the number of xmlChar to add
4750 *
4751 * Add a string range to an XML buffer. if len == -1, the lenght of
4752 * str is recomputed.
4753 */
4754void
4755xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
4756 unsigned int needSize;
4757
4758 if (str == NULL) {
4759#ifdef DEBUG_BUFFER
4760 xmlGenericError(xmlGenericErrorContext,
4761 "xmlBufferAdd: str == NULL\n");
4762#endif
4763 return;
4764 }
4765 if (len < -1) {
4766#ifdef DEBUG_BUFFER
4767 xmlGenericError(xmlGenericErrorContext,
4768 "xmlBufferAdd: len < 0\n");
4769#endif
4770 return;
4771 }
4772 if (len == 0) return;
4773
4774 if (len < 0)
4775 len = xmlStrlen(str);
4776
4777 if (len <= 0) return;
4778
4779 needSize = buf->use + len + 2;
4780 if (needSize > buf->size){
4781 if (!xmlBufferResize(buf, needSize)){
4782 xmlGenericError(xmlGenericErrorContext,
4783 "xmlBufferAdd : out of memory!\n");
4784 return;
4785 }
4786 }
4787
4788 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
4789 buf->use += len;
4790 buf->content[buf->use] = 0;
4791}
4792
4793/**
4794 * xmlBufferAddHead:
4795 * @buf: the buffer
4796 * @str: the xmlChar string
4797 * @len: the number of xmlChar to add
4798 *
4799 * Add a string range to the beginning of an XML buffer.
4800 * if len == -1, the lenght of @str is recomputed.
4801 */
4802void
4803xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
4804 unsigned int needSize;
4805
4806 if (str == NULL) {
4807#ifdef DEBUG_BUFFER
4808 xmlGenericError(xmlGenericErrorContext,
4809 "xmlBufferAdd: str == NULL\n");
4810#endif
4811 return;
4812 }
4813 if (len < -1) {
4814#ifdef DEBUG_BUFFER
4815 xmlGenericError(xmlGenericErrorContext,
4816 "xmlBufferAdd: len < 0\n");
4817#endif
4818 return;
4819 }
4820 if (len == 0) return;
4821
4822 if (len < 0)
4823 len = xmlStrlen(str);
4824
4825 if (len <= 0) return;
4826
4827 needSize = buf->use + len + 2;
4828 if (needSize > buf->size){
4829 if (!xmlBufferResize(buf, needSize)){
4830 xmlGenericError(xmlGenericErrorContext,
4831 "xmlBufferAddHead : out of memory!\n");
4832 return;
4833 }
4834 }
4835
4836 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4837 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4838 buf->use += len;
4839 buf->content[buf->use] = 0;
4840}
4841
4842/**
4843 * xmlBufferCat:
4844 * @buf: the buffer to dump
4845 * @str: the xmlChar string
4846 *
4847 * Append a zero terminated string to an XML buffer.
4848 */
4849void
4850xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
4851 if (str != NULL)
4852 xmlBufferAdd(buf, str, -1);
4853}
4854
4855/**
4856 * xmlBufferCCat:
4857 * @buf: the buffer to dump
4858 * @str: the C char string
4859 *
4860 * Append a zero terminated C string to an XML buffer.
4861 */
4862void
4863xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4864 const char *cur;
4865
4866 if (str == NULL) {
4867#ifdef DEBUG_BUFFER
4868 xmlGenericError(xmlGenericErrorContext,
4869 "xmlBufferAdd: str == NULL\n");
4870#endif
4871 return;
4872 }
4873 for (cur = str;*cur != 0;cur++) {
4874 if (buf->use + 10 >= buf->size) {
4875 if (!xmlBufferResize(buf, buf->use+10)){
4876 xmlGenericError(xmlGenericErrorContext,
4877 "xmlBufferCCat : out of memory!\n");
4878 return;
4879 }
4880 }
4881 buf->content[buf->use++] = *cur;
4882 }
4883 buf->content[buf->use] = 0;
4884}
4885
4886/**
4887 * xmlBufferWriteCHAR:
4888 * @buf: the XML buffer
4889 * @string: the string to add
4890 *
4891 * routine which manages and grows an output buffer. This one adds
4892 * xmlChars at the end of the buffer.
4893 */
4894void
4895#ifdef VMS
4896xmlBufferWriteXmlCHAR
4897#else
4898xmlBufferWriteCHAR
4899#endif
4900(xmlBufferPtr buf, const xmlChar *string) {
4901 xmlBufferCat(buf, string);
4902}
4903
4904/**
4905 * xmlBufferWriteChar:
4906 * @buf: the XML buffer output
4907 * @string: the string to add
4908 *
4909 * routine which manage and grows an output buffer. This one add
4910 * C chars at the end of the array.
4911 */
4912void
4913xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4914 xmlBufferCCat(buf, string);
4915}
4916
4917
4918/**
4919 * xmlBufferWriteQuotedString:
4920 * @buf: the XML buffer output
4921 * @string: the string to add
4922 *
4923 * routine which manage and grows an output buffer. This one writes
4924 * a quoted or double quoted xmlChar string, checking first if it holds
4925 * quote or double-quotes internally
4926 */
4927void
4928xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
4929 if (xmlStrchr(string, '"')) {
4930 if (xmlStrchr(string, '\'')) {
4931#ifdef DEBUG_BUFFER
4932 xmlGenericError(xmlGenericErrorContext,
4933 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
4934#endif
4935 }
4936 xmlBufferCCat(buf, "'");
4937 xmlBufferCat(buf, string);
4938 xmlBufferCCat(buf, "'");
4939 } else {
4940 xmlBufferCCat(buf, "\"");
4941 xmlBufferCat(buf, string);
4942 xmlBufferCCat(buf, "\"");
4943 }
4944}
4945
4946
4947/************************************************************************
4948 * *
4949 * Dumping XML tree content to a simple buffer *
4950 * *
4951 ************************************************************************/
4952
4953void
4954xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4955 int format);
4956static void
4957xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4958 int format);
4959void
4960htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4961
4962/**
4963 * xmlNsDump:
4964 * @buf: the XML buffer output
4965 * @cur: a namespace
4966 *
4967 * Dump a local Namespace definition.
4968 * Should be called in the context of attributes dumps.
4969 */
4970static void
4971xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
4972 if (cur == NULL) {
4973#ifdef DEBUG_TREE
4974 xmlGenericError(xmlGenericErrorContext,
4975 "xmlNsDump : Ns == NULL\n");
4976#endif
4977 return;
4978 }
4979 if (cur->type == XML_LOCAL_NAMESPACE) {
4980 /* Within the context of an element attributes */
4981 if (cur->prefix != NULL) {
4982 xmlBufferWriteChar(buf, " xmlns:");
4983 xmlBufferWriteCHAR(buf, cur->prefix);
4984 } else
4985 xmlBufferWriteChar(buf, " xmlns");
4986 xmlBufferWriteChar(buf, "=");
4987 xmlBufferWriteQuotedString(buf, cur->href);
4988 }
4989}
4990
4991/**
4992 * xmlNsListDump:
4993 * @buf: the XML buffer output
4994 * @cur: the first namespace
4995 *
4996 * Dump a list of local Namespace definitions.
4997 * Should be called in the context of attributes dumps.
4998 */
4999static void
5000xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5001 while (cur != NULL) {
5002 xmlNsDump(buf, cur);
5003 cur = cur->next;
5004 }
5005}
5006
5007/**
5008 * xmlDtdDump:
5009 * @buf: the XML buffer output
5010 * @doc: the document
5011 *
5012 * Dump the XML document DTD, if any.
5013 */
5014static void
5015xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5016 if (dtd == NULL) {
5017#ifdef DEBUG_TREE
5018 xmlGenericError(xmlGenericErrorContext,
5019 "xmlDtdDump : no internal subset\n");
5020#endif
5021 return;
5022 }
5023 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5024 xmlBufferWriteCHAR(buf, dtd->name);
5025 if (dtd->ExternalID != NULL) {
5026 xmlBufferWriteChar(buf, " PUBLIC ");
5027 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5028 xmlBufferWriteChar(buf, " ");
5029 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5030 } else if (dtd->SystemID != NULL) {
5031 xmlBufferWriteChar(buf, " SYSTEM ");
5032 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5033 }
5034 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5035 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5036 xmlBufferWriteChar(buf, ">");
5037 return;
5038 }
5039 xmlBufferWriteChar(buf, " [\n");
5040 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5041#if 0
5042 if (dtd->entities != NULL)
5043 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5044 if (dtd->notations != NULL)
5045 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5046 if (dtd->elements != NULL)
5047 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5048 if (dtd->attributes != NULL)
5049 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5050#endif
5051 xmlBufferWriteChar(buf, "]>");
5052}
5053
5054/**
5055 * xmlAttrDump:
5056 * @buf: the XML buffer output
5057 * @doc: the document
5058 * @cur: the attribute pointer
5059 *
5060 * Dump an XML attribute
5061 */
5062static void
5063xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5064 xmlChar *value;
5065
5066 if (cur == NULL) {
5067#ifdef DEBUG_TREE
5068 xmlGenericError(xmlGenericErrorContext,
5069 "xmlAttrDump : property == NULL\n");
5070#endif
5071 return;
5072 }
5073 xmlBufferWriteChar(buf, " ");
5074 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5075 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5076 xmlBufferWriteChar(buf, ":");
5077 }
5078 xmlBufferWriteCHAR(buf, cur->name);
5079 value = xmlNodeListGetString(doc, cur->children, 0);
5080 if (value != NULL) {
5081 xmlBufferWriteChar(buf, "=");
5082 xmlBufferWriteQuotedString(buf, value);
5083 xmlFree(value);
5084 } else {
5085 xmlBufferWriteChar(buf, "=\"\"");
5086 }
5087}
5088
5089/**
5090 * xmlAttrListDump:
5091 * @buf: the XML buffer output
5092 * @doc: the document
5093 * @cur: the first attribute pointer
5094 *
5095 * Dump a list of XML attributes
5096 */
5097static void
5098xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5099 if (cur == NULL) {
5100#ifdef DEBUG_TREE
5101 xmlGenericError(xmlGenericErrorContext,
5102 "xmlAttrListDump : property == NULL\n");
5103#endif
5104 return;
5105 }
5106 while (cur != NULL) {
5107 xmlAttrDump(buf, doc, cur);
5108 cur = cur->next;
5109 }
5110}
5111
5112
5113
5114/**
5115 * xmlNodeListDump:
5116 * @buf: the XML buffer output
5117 * @doc: the document
5118 * @cur: the first node
5119 * @level: the imbrication level for indenting
5120 * @format: is formatting allowed
5121 *
5122 * Dump an XML node list, recursive behaviour,children are printed too.
5123 */
5124static void
5125xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5126 int format) {
5127 int i;
5128
5129 if (cur == NULL) {
5130#ifdef DEBUG_TREE
5131 xmlGenericError(xmlGenericErrorContext,
5132 "xmlNodeListDump : node == NULL\n");
5133#endif
5134 return;
5135 }
5136 while (cur != NULL) {
5137 if ((format) && (xmlIndentTreeOutput) &&
5138 (cur->type == XML_ELEMENT_NODE))
5139 for (i = 0;i < level;i++)
5140 xmlBufferWriteChar(buf, " ");
5141 xmlNodeDump(buf, doc, cur, level, format);
5142 if (format) {
5143 xmlBufferWriteChar(buf, "\n");
5144 }
5145 cur = cur->next;
5146 }
5147}
5148
5149/**
5150 * xmlNodeDump:
5151 * @buf: the XML buffer output
5152 * @doc: the document
5153 * @cur: the current node
5154 * @level: the imbrication level for indenting
5155 * @format: is formatting allowed
5156 *
5157 * Dump an XML node, recursive behaviour,children are printed too.
5158 */
5159void
5160xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5161 int format) {
5162 int i;
5163 xmlNodePtr tmp;
5164
5165 if (cur == NULL) {
5166#ifdef DEBUG_TREE
5167 xmlGenericError(xmlGenericErrorContext,
5168 "xmlNodeDump : node == NULL\n");
5169#endif
5170 return;
5171 }
5172 if (cur->type == XML_XINCLUDE_START)
5173 return;
5174 if (cur->type == XML_XINCLUDE_END)
5175 return;
5176 if (cur->type == XML_DTD_NODE) {
5177 xmlDtdDump(buf, (xmlDtdPtr) cur);
5178 return;
5179 }
5180 if (cur->type == XML_ELEMENT_DECL) {
5181 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5182 return;
5183 }
5184 if (cur->type == XML_ATTRIBUTE_DECL) {
5185 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5186 return;
5187 }
5188 if (cur->type == XML_ENTITY_DECL) {
5189 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5190 return;
5191 }
5192 if (cur->type == XML_TEXT_NODE) {
5193 if (cur->content != NULL) {
5194 if ((cur->name == xmlStringText) ||
5195 (cur->name != xmlStringTextNoenc)) {
5196 xmlChar *buffer;
5197
5198#ifndef XML_USE_BUFFER_CONTENT
5199 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5200#else
5201 buffer = xmlEncodeEntitiesReentrant(doc,
5202 xmlBufferContent(cur->content));
5203#endif
5204 if (buffer != NULL) {
5205 xmlBufferWriteCHAR(buf, buffer);
5206 xmlFree(buffer);
5207 }
5208 } else {
5209 /*
5210 * Disable escaping, needed for XSLT
5211 */
5212#ifndef XML_USE_BUFFER_CONTENT
5213 xmlBufferWriteCHAR(buf, cur->content);
5214#else
5215 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5216#endif
5217 }
5218 }
5219 return;
5220 }
5221 if (cur->type == XML_PI_NODE) {
5222 if (cur->content != NULL) {
5223 xmlBufferWriteChar(buf, "<?");
5224 xmlBufferWriteCHAR(buf, cur->name);
5225 if (cur->content != NULL) {
5226 xmlBufferWriteChar(buf, " ");
5227#ifndef XML_USE_BUFFER_CONTENT
5228 xmlBufferWriteCHAR(buf, cur->content);
5229#else
5230 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5231#endif
5232 }
5233 xmlBufferWriteChar(buf, "?>");
5234 } else {
5235 xmlBufferWriteChar(buf, "<?");
5236 xmlBufferWriteCHAR(buf, cur->name);
5237 xmlBufferWriteChar(buf, "?>");
5238 }
5239 return;
5240 }
5241 if (cur->type == XML_COMMENT_NODE) {
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 xmlBufferWriteChar(buf, "-->");
5250 }
5251 return;
5252 }
5253 if (cur->type == XML_ENTITY_REF_NODE) {
5254 xmlBufferWriteChar(buf, "&");
5255 xmlBufferWriteCHAR(buf, cur->name);
5256 xmlBufferWriteChar(buf, ";");
5257 return;
5258 }
5259 if (cur->type == XML_CDATA_SECTION_NODE) {
5260 xmlBufferWriteChar(buf, "<![CDATA[");
5261 if (cur->content != NULL)
5262#ifndef XML_USE_BUFFER_CONTENT
5263 xmlBufferWriteCHAR(buf, cur->content);
5264#else
5265 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5266#endif
5267 xmlBufferWriteChar(buf, "]]>");
5268 return;
5269 }
5270
5271 if (format == 1) {
5272 tmp = cur->children;
5273 while (tmp != NULL) {
5274 if ((tmp->type == XML_TEXT_NODE) ||
5275 (tmp->type == XML_ENTITY_REF_NODE)) {
5276 format = 0;
5277 break;
5278 }
5279 tmp = tmp->next;
5280 }
5281 }
5282 xmlBufferWriteChar(buf, "<");
5283 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5284 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5285 xmlBufferWriteChar(buf, ":");
5286 }
5287
5288 xmlBufferWriteCHAR(buf, cur->name);
5289 if (cur->nsDef)
5290 xmlNsListDump(buf, cur->nsDef);
5291 if (cur->properties != NULL)
5292 xmlAttrListDump(buf, doc, cur->properties);
5293
5294 if ((cur->content == NULL) && (cur->children == NULL) &&
5295 (!xmlSaveNoEmptyTags)) {
5296 xmlBufferWriteChar(buf, "/>");
5297 return;
5298 }
5299 xmlBufferWriteChar(buf, ">");
5300 if (cur->content != NULL) {
5301 xmlChar *buffer;
5302
5303#ifndef XML_USE_BUFFER_CONTENT
5304 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5305#else
5306 buffer = xmlEncodeEntitiesReentrant(doc,
5307 xmlBufferContent(cur->content));
5308#endif
5309 if (buffer != NULL) {
5310 xmlBufferWriteCHAR(buf, buffer);
5311 xmlFree(buffer);
5312 }
5313 }
5314 if (cur->children != NULL) {
5315 if (format) xmlBufferWriteChar(buf, "\n");
5316 xmlNodeListDump(buf, doc, cur->children,
5317 (level >= 0?level+1:-1), format);
5318 if ((xmlIndentTreeOutput) && (format))
5319 for (i = 0;i < level;i++)
5320 xmlBufferWriteChar(buf, " ");
5321 }
5322 xmlBufferWriteChar(buf, "</");
5323 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5324 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5325 xmlBufferWriteChar(buf, ":");
5326 }
5327
5328 xmlBufferWriteCHAR(buf, cur->name);
5329 xmlBufferWriteChar(buf, ">");
5330}
5331
5332/**
5333 * xmlElemDump:
5334 * @f: the FILE * for the output
5335 * @doc: the document
5336 * @cur: the current node
5337 *
5338 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5339 */
5340void
5341xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5342 xmlBufferPtr buf;
5343
5344 if (cur == NULL) {
5345#ifdef DEBUG_TREE
5346 xmlGenericError(xmlGenericErrorContext,
5347 "xmlElemDump : cur == NULL\n");
5348#endif
5349 return;
5350 }
5351 if (doc == NULL) {
5352#ifdef DEBUG_TREE
5353 xmlGenericError(xmlGenericErrorContext,
5354 "xmlElemDump : doc == NULL\n");
5355#endif
5356 }
5357 buf = xmlBufferCreate();
5358 if (buf == NULL) return;
5359 if ((doc != NULL) &&
5360 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5361#ifdef LIBXML_HTML_ENABLED
5362 htmlNodeDump(buf, doc, cur);
5363#else
5364 xmlGenericError(xmlGenericErrorContext,
5365 "HTML support not compiled in\n");
5366#endif /* LIBXML_HTML_ENABLED */
5367 } else
5368 xmlNodeDump(buf, doc, cur, 0, 1);
5369 xmlBufferDump(f, buf);
5370 xmlBufferFree(buf);
5371}
5372
5373/************************************************************************
5374 * *
5375 * Dumping XML tree content to an I/O output buffer *
5376 * *
5377 ************************************************************************/
5378
5379void
5380xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5381 int level, int format, const char *encoding);
5382static void
5383xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5384 int level, int format, const char *encoding);
5385/**
5386 * xmlNsDumpOutput:
5387 * @buf: the XML buffer output
5388 * @cur: a namespace
5389 *
5390 * Dump a local Namespace definition.
5391 * Should be called in the context of attributes dumps.
5392 */
5393static void
5394xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5395 if (cur == NULL) {
5396#ifdef DEBUG_TREE
5397 xmlGenericError(xmlGenericErrorContext,
5398 "xmlNsDump : Ns == NULL\n");
5399#endif
5400 return;
5401 }
5402 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5403 /* Within the context of an element attributes */
5404 if (cur->prefix != NULL) {
5405 xmlOutputBufferWriteString(buf, " xmlns:");
5406 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5407 } else
5408 xmlOutputBufferWriteString(buf, " xmlns");
5409 xmlOutputBufferWriteString(buf, "=");
5410 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5411 }
5412}
5413
5414/**
5415 * xmlNsListDumpOutput:
5416 * @buf: the XML buffer output
5417 * @cur: the first namespace
5418 *
5419 * Dump a list of local Namespace definitions.
5420 * Should be called in the context of attributes dumps.
5421 */
5422static void
5423xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5424 while (cur != NULL) {
5425 xmlNsDumpOutput(buf, cur);
5426 cur = cur->next;
5427 }
5428}
5429
5430/**
5431 * xmlDtdDumpOutput:
5432 * @buf: the XML buffer output
5433 * @doc: the document
5434 * @encoding: an optional encoding string
5435 *
5436 * Dump the XML document DTD, if any.
5437 */
5438static void
5439xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5440 if (dtd == NULL) {
5441#ifdef DEBUG_TREE
5442 xmlGenericError(xmlGenericErrorContext,
5443 "xmlDtdDump : no internal subset\n");
5444#endif
5445 return;
5446 }
5447 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5448 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5449 if (dtd->ExternalID != NULL) {
5450 xmlOutputBufferWriteString(buf, " PUBLIC ");
5451 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5452 xmlOutputBufferWriteString(buf, " ");
5453 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5454 } else if (dtd->SystemID != NULL) {
5455 xmlOutputBufferWriteString(buf, " SYSTEM ");
5456 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5457 }
5458 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5459 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5460 xmlOutputBufferWriteString(buf, ">");
5461 return;
5462 }
5463 xmlOutputBufferWriteString(buf, " [\n");
5464 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5465 xmlOutputBufferWriteString(buf, "]>");
5466}
5467
5468/**
5469 * xmlAttrDumpOutput:
5470 * @buf: the XML buffer output
5471 * @doc: the document
5472 * @cur: the attribute pointer
5473 * @encoding: an optional encoding string
5474 *
5475 * Dump an XML attribute
5476 */
5477static void
5478xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005479 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005480 xmlChar *value;
5481
5482 if (cur == NULL) {
5483#ifdef DEBUG_TREE
5484 xmlGenericError(xmlGenericErrorContext,
5485 "xmlAttrDump : property == NULL\n");
5486#endif
5487 return;
5488 }
5489 xmlOutputBufferWriteString(buf, " ");
5490 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5491 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5492 xmlOutputBufferWriteString(buf, ":");
5493 }
5494 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5495 value = xmlNodeListGetString(doc, cur->children, 0);
5496 if (value) {
5497 xmlOutputBufferWriteString(buf, "=");
5498 xmlBufferWriteQuotedString(buf->buffer, value);
5499 xmlFree(value);
5500 } else {
5501 xmlOutputBufferWriteString(buf, "=\"\"");
5502 }
5503}
5504
5505/**
5506 * xmlAttrListDumpOutput:
5507 * @buf: the XML buffer output
5508 * @doc: the document
5509 * @cur: the first attribute pointer
5510 * @encoding: an optional encoding string
5511 *
5512 * Dump a list of XML attributes
5513 */
5514static void
5515xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5516 xmlAttrPtr cur, const char *encoding) {
5517 if (cur == NULL) {
5518#ifdef DEBUG_TREE
5519 xmlGenericError(xmlGenericErrorContext,
5520 "xmlAttrListDump : property == NULL\n");
5521#endif
5522 return;
5523 }
5524 while (cur != NULL) {
5525 xmlAttrDumpOutput(buf, doc, cur, encoding);
5526 cur = cur->next;
5527 }
5528}
5529
5530
5531
5532/**
5533 * xmlNodeListDumpOutput:
5534 * @buf: the XML buffer output
5535 * @doc: the document
5536 * @cur: the first node
5537 * @level: the imbrication level for indenting
5538 * @format: is formatting allowed
5539 * @encoding: an optional encoding string
5540 *
5541 * Dump an XML node list, recursive behaviour,children are printed too.
5542 */
5543static void
5544xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5545 xmlNodePtr cur, int level, int format, const char *encoding) {
5546 int i;
5547
5548 if (cur == NULL) {
5549#ifdef DEBUG_TREE
5550 xmlGenericError(xmlGenericErrorContext,
5551 "xmlNodeListDump : node == NULL\n");
5552#endif
5553 return;
5554 }
5555 while (cur != NULL) {
5556 if ((format) && (xmlIndentTreeOutput) &&
5557 (cur->type == XML_ELEMENT_NODE))
5558 for (i = 0;i < level;i++)
5559 xmlOutputBufferWriteString(buf, " ");
5560 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5561 if (format) {
5562 xmlOutputBufferWriteString(buf, "\n");
5563 }
5564 cur = cur->next;
5565 }
5566}
5567
5568/**
5569 * xmlNodeDumpOutput:
5570 * @buf: the XML buffer output
5571 * @doc: the document
5572 * @cur: the current node
5573 * @level: the imbrication level for indenting
5574 * @format: is formatting allowed
5575 * @encoding: an optional encoding string
5576 *
5577 * Dump an XML node, recursive behaviour,children are printed too.
5578 */
5579void
5580xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5581 int level, int format, const char *encoding) {
5582 int i;
5583 xmlNodePtr tmp;
5584
5585 if (cur == NULL) {
5586#ifdef DEBUG_TREE
5587 xmlGenericError(xmlGenericErrorContext,
5588 "xmlNodeDump : node == NULL\n");
5589#endif
5590 return;
5591 }
5592 if (cur->type == XML_XINCLUDE_START)
5593 return;
5594 if (cur->type == XML_XINCLUDE_END)
5595 return;
5596 if (cur->type == XML_DTD_NODE) {
5597 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5598 return;
5599 }
5600 if (cur->type == XML_ELEMENT_DECL) {
5601 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5602 return;
5603 }
5604 if (cur->type == XML_ATTRIBUTE_DECL) {
5605 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5606 return;
5607 }
5608 if (cur->type == XML_ENTITY_DECL) {
5609 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5610 return;
5611 }
5612 if (cur->type == XML_TEXT_NODE) {
5613 if (cur->content != NULL) {
5614 if ((cur->name == xmlStringText) ||
5615 (cur->name != xmlStringTextNoenc)) {
5616 xmlChar *buffer;
5617
5618#ifndef XML_USE_BUFFER_CONTENT
5619 if (encoding == NULL)
5620 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5621 else
5622 buffer = xmlEncodeSpecialChars(doc, cur->content);
5623#else
5624 if (encoding == NULL)
5625 buffer = xmlEncodeEntitiesReentrant(doc,
5626 xmlBufferContent(cur->content));
5627 else
5628 buffer = xmlEncodeSpecialChars(doc,
5629 xmlBufferContent(cur->content));
5630#endif
5631 if (buffer != NULL) {
5632 xmlOutputBufferWriteString(buf, (const char *)buffer);
5633 xmlFree(buffer);
5634 }
5635 } else {
5636 /*
5637 * Disable escaping, needed for XSLT
5638 */
5639#ifndef XML_USE_BUFFER_CONTENT
5640 xmlOutputBufferWriteString(buf, (const char *) cur->content);
5641#else
5642 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5643#endif
5644 }
5645 }
5646
5647 return;
5648 }
5649 if (cur->type == XML_PI_NODE) {
5650 if (cur->content != NULL) {
5651 xmlOutputBufferWriteString(buf, "<?");
5652 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5653 if (cur->content != NULL) {
5654 xmlOutputBufferWriteString(buf, " ");
5655#ifndef XML_USE_BUFFER_CONTENT
5656 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5657#else
5658 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5659#endif
5660 }
5661 xmlOutputBufferWriteString(buf, "?>");
5662 } else {
5663 xmlOutputBufferWriteString(buf, "<?");
5664 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5665 xmlOutputBufferWriteString(buf, "?>");
5666 }
5667 return;
5668 }
5669 if (cur->type == XML_COMMENT_NODE) {
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 xmlOutputBufferWriteString(buf, "-->");
5678 }
5679 return;
5680 }
5681 if (cur->type == XML_ENTITY_REF_NODE) {
5682 xmlOutputBufferWriteString(buf, "&");
5683 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5684 xmlOutputBufferWriteString(buf, ";");
5685 return;
5686 }
5687 if (cur->type == XML_CDATA_SECTION_NODE) {
5688 xmlOutputBufferWriteString(buf, "<![CDATA[");
5689 if (cur->content != NULL)
5690#ifndef XML_USE_BUFFER_CONTENT
5691 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5692#else
5693 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5694#endif
5695 xmlOutputBufferWriteString(buf, "]]>");
5696 return;
5697 }
5698
5699 if (format == 1) {
5700 tmp = cur->children;
5701 while (tmp != NULL) {
5702 if ((tmp->type == XML_TEXT_NODE) ||
5703 (tmp->type == XML_ENTITY_REF_NODE)) {
5704 format = 0;
5705 break;
5706 }
5707 tmp = tmp->next;
5708 }
5709 }
5710 xmlOutputBufferWriteString(buf, "<");
5711 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5712 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5713 xmlOutputBufferWriteString(buf, ":");
5714 }
5715
5716 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5717 if (cur->nsDef)
5718 xmlNsListDumpOutput(buf, cur->nsDef);
5719 if (cur->properties != NULL)
5720 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5721
5722 if ((cur->content == NULL) && (cur->children == NULL) &&
5723 (!xmlSaveNoEmptyTags)) {
5724 xmlOutputBufferWriteString(buf, "/>");
5725 return;
5726 }
5727 xmlOutputBufferWriteString(buf, ">");
5728 if (cur->content != NULL) {
5729 xmlChar *buffer;
5730
5731#ifndef XML_USE_BUFFER_CONTENT
5732 if (encoding == NULL)
5733 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5734 else
5735 buffer = xmlEncodeSpecialChars(doc, cur->content);
5736#else
5737 if (encoding == NULL)
5738 buffer = xmlEncodeEntitiesReentrant(doc,
5739 xmlBufferContent(cur->content));
5740 else
5741 buffer = xmlEncodeSpecialChars(doc,
5742 xmlBufferContent(cur->content));
5743#endif
5744 if (buffer != NULL) {
5745 xmlOutputBufferWriteString(buf, (const char *)buffer);
5746 xmlFree(buffer);
5747 }
5748 }
5749 if (cur->children != NULL) {
5750 if (format) xmlOutputBufferWriteString(buf, "\n");
5751 xmlNodeListDumpOutput(buf, doc, cur->children,
5752 (level >= 0?level+1:-1), format, encoding);
5753 if ((xmlIndentTreeOutput) && (format))
5754 for (i = 0;i < level;i++)
5755 xmlOutputBufferWriteString(buf, " ");
5756 }
5757 xmlOutputBufferWriteString(buf, "</");
5758 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5759 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5760 xmlOutputBufferWriteString(buf, ":");
5761 }
5762
5763 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5764 xmlOutputBufferWriteString(buf, ">");
5765}
5766
5767/**
5768 * xmlDocContentDumpOutput:
5769 * @buf: the XML buffer output
5770 * @cur: the document
5771 * @encoding: an optional encoding string
5772 * @format: should formatting spaces been added
5773 *
5774 * Dump an XML document.
5775 */
5776static void
5777xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
5778 const char *encoding, int format) {
5779 xmlOutputBufferWriteString(buf, "<?xml version=");
5780 if (cur->version != NULL)
5781 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5782 else
5783 xmlOutputBufferWriteString(buf, "\"1.0\"");
5784 if (encoding == NULL) {
5785 if (cur->encoding != NULL)
5786 encoding = (const char *) cur->encoding;
5787 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
5788 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
5789 }
5790 if (encoding != NULL) {
5791 xmlOutputBufferWriteString(buf, " encoding=");
5792 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5793 }
5794 switch (cur->standalone) {
5795 case 0:
5796 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5797 break;
5798 case 1:
5799 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5800 break;
5801 }
5802 xmlOutputBufferWriteString(buf, "?>\n");
5803 if (cur->children != NULL) {
5804 xmlNodePtr child = cur->children;
5805
5806 while (child != NULL) {
5807 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
5808 xmlOutputBufferWriteString(buf, "\n");
5809 child = child->next;
5810 }
5811 }
5812}
5813
5814/************************************************************************
5815 * *
5816 * Saving functions front-ends *
5817 * *
5818 ************************************************************************/
5819
5820/**
5821 * xmlDocDumpMemoryEnc:
5822 * @out_doc: Document to generate XML text from
5823 * @doc_txt_ptr: Memory pointer for allocated XML text
5824 * @doc_txt_len: Length of the generated XML text
5825 * @txt_encoding: Character encoding to use when generating XML text
5826 * @format: should formatting spaces been added
5827 *
5828 * Dump the current DOM tree into memory using the character encoding specified
5829 * by the caller. Note it is up to the caller of this function to free the
5830 * allocated memory.
5831 */
5832
5833void
5834xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005835 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00005836 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00005837 int dummy = 0;
5838
5839 xmlCharEncoding doc_charset;
5840 xmlOutputBufferPtr out_buff = NULL;
5841 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
5842
5843 if (doc_txt_len == NULL) {
5844 doc_txt_len = &dummy; /* Continue, caller just won't get length */
5845 }
5846
5847 if (doc_txt_ptr == NULL) {
5848 *doc_txt_len = 0;
5849 xmlGenericError(xmlGenericErrorContext,
5850 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
5851 return;
5852 }
5853
5854 *doc_txt_ptr = NULL;
5855 *doc_txt_len = 0;
5856
5857 if (out_doc == NULL) {
5858 /* No document, no output */
5859 xmlGenericError(xmlGenericErrorContext,
5860 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
5861 return;
5862 }
5863
5864 /*
5865 * Validate the encoding value, if provided.
5866 * This logic is copied from xmlSaveFileEnc.
5867 */
5868
5869 if (txt_encoding == NULL)
5870 txt_encoding = (const char *) out_doc->encoding;
5871 if (txt_encoding != NULL) {
5872 doc_charset = xmlParseCharEncoding(txt_encoding);
5873
5874 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
5875 xmlGenericError(xmlGenericErrorContext,
5876 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
5877 return;
5878
5879 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
5880 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
5881 if ( conv_hdlr == NULL ) {
5882 xmlGenericError(xmlGenericErrorContext,
5883 "%s: %s %s '%s'\n",
5884 "xmlDocDumpFormatMemoryEnc",
5885 "Failed to identify encoding handler for",
5886 "character set",
5887 txt_encoding);
5888 return;
5889 }
5890 }
5891 }
5892
5893 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
5894 xmlGenericError(xmlGenericErrorContext,
5895 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
5896 return;
5897 }
5898
Daniel Veillard1731d6a2001-04-10 16:38:06 +00005899 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00005900 xmlOutputBufferFlush(out_buff);
5901 if (out_buff->conv != NULL) {
5902 *doc_txt_len = out_buff->conv->use;
5903 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
5904 } else {
5905 *doc_txt_len = out_buff->buffer->use;
5906 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
5907 }
5908 (void)xmlOutputBufferClose(out_buff);
5909
5910 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
5911 *doc_txt_len = 0;
5912 xmlGenericError(xmlGenericErrorContext,
5913 "xmlDocDumpFormatMemoryEnc: %s\n",
5914 "Failed to allocate memory for document text representation.");
5915 }
5916
5917 return;
5918}
5919
5920/**
5921 * xmlDocDumpMemory:
5922 * @cur: the document
5923 * @mem: OUT: the memory pointer
5924 * @size: OUT: the memory lenght
5925 *
5926 * Dump an XML document in memory and return the xmlChar * and it's size.
5927 * It's up to the caller to free the memory.
5928 */
5929void
5930xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
5931 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
5932}
5933
5934/**
5935 * xmlDocDumpFormatMemory:
5936 * @cur: the document
5937 * @mem: OUT: the memory pointer
5938 * @size: OUT: the memory lenght
5939 * @format: should formatting spaces been added
5940 *
5941 *
5942 * Dump an XML document in memory and return the xmlChar * and it's size.
5943 * It's up to the caller to free the memory.
5944 */
5945void
5946xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
5947 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
5948}
5949
5950/**
5951 * xmlDocDumpMemoryEnc:
5952 * @out_doc: Document to generate XML text from
5953 * @doc_txt_ptr: Memory pointer for allocated XML text
5954 * @doc_txt_len: Length of the generated XML text
5955 * @txt_encoding: Character encoding to use when generating XML text
5956 *
5957 * Dump the current DOM tree into memory using the character encoding specified
5958 * by the caller. Note it is up to the caller of this function to free the
5959 * allocated memory.
5960 */
5961
5962void
5963xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5964 int * doc_txt_len, const char * txt_encoding) {
5965 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00005966 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005967}
5968
5969/**
5970 * xmlGetDocCompressMode:
5971 * @doc: the document
5972 *
5973 * get the compression ratio for a document, ZLIB based
5974 * Returns 0 (uncompressed) to 9 (max compression)
5975 */
5976int
5977xmlGetDocCompressMode (xmlDocPtr doc) {
5978 if (doc == NULL) return(-1);
5979 return(doc->compression);
5980}
5981
5982/**
5983 * xmlSetDocCompressMode:
5984 * @doc: the document
5985 * @mode: the compression ratio
5986 *
5987 * set the compression ratio for a document, ZLIB based
5988 * Correct values: 0 (uncompressed) to 9 (max compression)
5989 */
5990void
5991xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
5992 if (doc == NULL) return;
5993 if (mode < 0) doc->compression = 0;
5994 else if (mode > 9) doc->compression = 9;
5995 else doc->compression = mode;
5996}
5997
5998/**
5999 * xmlGetCompressMode:
6000 *
6001 * get the default compression mode used, ZLIB based.
6002 * Returns 0 (uncompressed) to 9 (max compression)
6003 */
6004int
6005 xmlGetCompressMode(void) {
6006 return(xmlCompressMode);
6007}
6008
6009/**
6010 * xmlSetCompressMode:
6011 * @mode: the compression ratio
6012 *
6013 * set the default compression mode used, ZLIB based
6014 * Correct values: 0 (uncompressed) to 9 (max compression)
6015 */
6016void
6017xmlSetCompressMode(int mode) {
6018 if (mode < 0) xmlCompressMode = 0;
6019 else if (mode > 9) xmlCompressMode = 9;
6020 else xmlCompressMode = mode;
6021}
6022
6023/**
6024 * xmlDocDump:
6025 * @f: the FILE*
6026 * @cur: the document
6027 *
6028 * Dump an XML document to an open FILE.
6029 *
6030 * returns: the number of byte written or -1 in case of failure.
6031 */
6032int
6033xmlDocDump(FILE *f, xmlDocPtr cur) {
6034 xmlOutputBufferPtr buf;
6035 const char * encoding;
6036 xmlCharEncodingHandlerPtr handler = NULL;
6037 int ret;
6038
6039 if (cur == NULL) {
6040#ifdef DEBUG_TREE
6041 xmlGenericError(xmlGenericErrorContext,
6042 "xmlDocDump : document == NULL\n");
6043#endif
6044 return(-1);
6045 }
6046 encoding = (const char *) cur->encoding;
6047
6048 if (encoding != NULL) {
6049 xmlCharEncoding enc;
6050
6051 enc = xmlParseCharEncoding(encoding);
6052
6053 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6054 xmlGenericError(xmlGenericErrorContext,
6055 "xmlDocDump: document not in UTF8\n");
6056 return(-1);
6057 }
6058 if (enc != XML_CHAR_ENCODING_UTF8) {
6059 handler = xmlFindCharEncodingHandler(encoding);
6060 if (handler == NULL) {
6061 xmlFree((char *) cur->encoding);
6062 cur->encoding = NULL;
6063 }
6064 }
6065 }
6066 buf = xmlOutputBufferCreateFile(f, handler);
6067 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006068 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006069
6070 ret = xmlOutputBufferClose(buf);
6071 return(ret);
6072}
6073
6074/**
6075 * xmlSaveFileTo:
6076 * @buf: an output I/O buffer
6077 * @cur: the document
6078 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6079 *
6080 * Dump an XML document to an I/O buffer.
6081 *
6082 * returns: the number of byte written or -1 in case of failure.
6083 */
6084int
6085xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
6086 int ret;
6087
6088 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006089 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006090 ret = xmlOutputBufferClose(buf);
6091 return(ret);
6092}
6093
6094/**
6095 * xmlSaveFileEnc:
6096 * @filename: the filename (or URL)
6097 * @cur: the document
6098 * @encoding: the name of an encoding (or NULL)
6099 *
6100 * Dump an XML document, converting it to the given encoding
6101 *
6102 * returns: the number of byte written or -1 in case of failure.
6103 */
6104int
6105xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6106 xmlOutputBufferPtr buf;
6107 xmlCharEncodingHandlerPtr handler = NULL;
6108 int ret;
6109
6110 if (encoding != NULL) {
6111 xmlCharEncoding enc;
6112
6113 enc = xmlParseCharEncoding(encoding);
6114 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6115 xmlGenericError(xmlGenericErrorContext,
6116 "xmlSaveFileEnc: document not in UTF8\n");
6117 return(-1);
6118 }
6119 if (enc != XML_CHAR_ENCODING_UTF8) {
6120 handler = xmlFindCharEncodingHandler(encoding);
6121 if (handler == NULL) {
6122 return(-1);
6123 }
6124 }
6125 }
6126
6127 /*
6128 * save the content to a temp buffer.
6129 */
6130 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
6131 if (buf == NULL) return(-1);
6132
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006133 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006134
6135 ret = xmlOutputBufferClose(buf);
6136 return(ret);
6137}
6138
6139/**
6140 * xmlSaveFile:
6141 * @filename: the filename (or URL)
6142 * @cur: the document
6143 *
6144 * Dump an XML document to a file. Will use compression if
6145 * compiled in and enabled. If @filename is "-" the stdout file is
6146 * used.
6147 * returns: the number of byte written or -1 in case of failure.
6148 */
6149int
6150xmlSaveFile(const char *filename, xmlDocPtr cur) {
6151 xmlOutputBufferPtr buf;
6152 const char *encoding;
6153 xmlCharEncodingHandlerPtr handler = NULL;
6154 int ret;
6155
6156 if (cur == NULL)
6157 return(-1);
6158 encoding = (const char *) cur->encoding;
6159
6160 /*
6161 * save the content to a temp buffer.
6162 */
6163#ifdef HAVE_ZLIB_H
6164 if (cur->compression < 0) cur->compression = xmlCompressMode;
6165#endif
6166 if (encoding != NULL) {
6167 xmlCharEncoding enc;
6168
6169 enc = xmlParseCharEncoding(encoding);
6170
6171 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6172 xmlGenericError(xmlGenericErrorContext,
6173 "xmlSaveFile: document not in UTF8\n");
6174 return(-1);
6175 }
6176 if (enc != XML_CHAR_ENCODING_UTF8) {
6177 handler = xmlFindCharEncodingHandler(encoding);
6178 if (handler == NULL) {
6179 xmlFree((char *) cur->encoding);
6180 cur->encoding = NULL;
6181 }
6182 }
6183 }
6184
6185 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
6186 if (buf == NULL) return(-1);
6187
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006188 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006189
6190 ret = xmlOutputBufferClose(buf);
6191 return(ret);
6192}
6193