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