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