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