blob: d002d7f70427f6c8c80c080aa3038af242602fbb [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 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001971 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1972 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001973#ifndef XML_USE_BUFFER_CONTENT
1974 xmlChar *tmp;
1975
1976 tmp = xmlStrdup(elem->content);
1977 tmp = xmlStrcat(tmp, cur->next->content);
1978 xmlNodeSetContent(cur->next, tmp);
1979 xmlFree(tmp);
1980#else
1981 xmlBufferAddHead(cur->next->content,
1982 xmlBufferContent(elem->content),
1983 xmlBufferLength(elem->content));
1984#endif
1985 xmlFreeNode(elem);
1986 return(cur->next);
1987 }
1988 }
1989
1990 if (elem->doc != cur->doc) {
1991 xmlSetTreeDoc(elem, cur->doc);
1992 }
1993 elem->parent = cur->parent;
1994 elem->prev = cur;
1995 elem->next = cur->next;
1996 cur->next = elem;
1997 if (elem->next != NULL)
1998 elem->next->prev = elem;
1999 if ((elem->parent != NULL) && (elem->parent->last == cur))
2000 elem->parent->last = elem;
2001 return(elem);
2002}
2003
2004/**
2005 * xmlAddPrevSibling:
2006 * @cur: the child node
2007 * @elem: the new node
2008 *
2009 * Add a new element @elem as the previous siblings of @cur
2010 * merging adjacent TEXT nodes (@elem may be freed)
2011 * If the new element was already inserted in a document it is
2012 * first unlinked from its existing context.
2013 *
2014 * Returns the new element or NULL in case of error.
2015 */
2016xmlNodePtr
2017xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2018 if (cur == NULL) {
2019#ifdef DEBUG_TREE
2020 xmlGenericError(xmlGenericErrorContext,
2021 "xmlAddPrevSibling : cur == NULL\n");
2022#endif
2023 return(NULL);
2024 }
2025 if (elem == NULL) {
2026#ifdef DEBUG_TREE
2027 xmlGenericError(xmlGenericErrorContext,
2028 "xmlAddPrevSibling : elem == NULL\n");
2029#endif
2030 return(NULL);
2031 }
2032
2033 xmlUnlinkNode(elem);
2034
2035 if (elem->type == XML_TEXT_NODE) {
2036 if (cur->type == XML_TEXT_NODE) {
2037#ifndef XML_USE_BUFFER_CONTENT
2038 xmlChar *tmp;
2039
2040 tmp = xmlStrdup(elem->content);
2041 tmp = xmlStrcat(tmp, cur->content);
2042 xmlNodeSetContent(cur, tmp);
2043 xmlFree(tmp);
2044#else
2045 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2046 xmlBufferLength(elem->content));
2047#endif
2048 xmlFreeNode(elem);
2049 return(cur);
2050 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002051 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2052 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002053#ifndef XML_USE_BUFFER_CONTENT
2054 xmlNodeAddContent(cur->prev, elem->content);
2055#else
2056 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2057#endif
2058 xmlFreeNode(elem);
2059 return(cur->prev);
2060 }
2061 }
2062
2063 if (elem->doc != cur->doc) {
2064 xmlSetTreeDoc(elem, cur->doc);
2065 }
2066 elem->parent = cur->parent;
2067 elem->next = cur;
2068 elem->prev = cur->prev;
2069 cur->prev = elem;
2070 if (elem->prev != NULL)
2071 elem->prev->next = elem;
2072 if ((elem->parent != NULL) && (elem->parent->children == cur))
2073 elem->parent->children = elem;
2074 return(elem);
2075}
2076
2077/**
2078 * xmlAddSibling:
2079 * @cur: the child node
2080 * @elem: the new node
2081 *
2082 * Add a new element @elem to the list of siblings of @cur
2083 * merging adjacent TEXT nodes (@elem may be freed)
2084 * If the new element was already inserted in a document it is
2085 * first unlinked from its existing context.
2086 *
2087 * Returns the new element or NULL in case of error.
2088 */
2089xmlNodePtr
2090xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2091 xmlNodePtr parent;
2092
2093 if (cur == NULL) {
2094#ifdef DEBUG_TREE
2095 xmlGenericError(xmlGenericErrorContext,
2096 "xmlAddSibling : cur == NULL\n");
2097#endif
2098 return(NULL);
2099 }
2100
2101 if (elem == NULL) {
2102#ifdef DEBUG_TREE
2103 xmlGenericError(xmlGenericErrorContext,
2104 "xmlAddSibling : elem == NULL\n");
2105#endif
2106 return(NULL);
2107 }
2108
2109 /*
2110 * Constant time is we can rely on the ->parent->last to find
2111 * the last sibling.
2112 */
2113 if ((cur->parent != NULL) &&
2114 (cur->parent->children != NULL) &&
2115 (cur->parent->last != NULL) &&
2116 (cur->parent->last->next == NULL)) {
2117 cur = cur->parent->last;
2118 } else {
2119 while (cur->next != NULL) cur = cur->next;
2120 }
2121
2122 xmlUnlinkNode(elem);
2123
2124 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2125#ifndef XML_USE_BUFFER_CONTENT
2126 xmlNodeAddContent(cur, elem->content);
2127#else
2128 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2129#endif
2130 xmlFreeNode(elem);
2131 return(cur);
2132 }
2133
2134 if (elem->doc != cur->doc) {
2135 xmlSetTreeDoc(elem, cur->doc);
2136 }
2137 parent = cur->parent;
2138 elem->prev = cur;
2139 elem->next = NULL;
2140 elem->parent = parent;
2141 cur->next = elem;
2142 if (parent != NULL)
2143 parent->last = elem;
2144
2145 return(elem);
2146}
2147
2148/**
2149 * xmlAddChildList:
2150 * @parent: the parent node
2151 * @cur: the first node in the list
2152 *
2153 * Add a list of node at the end of the child list of the parent
2154 * merging adjacent TEXT nodes (@cur may be freed)
2155 *
2156 * Returns the last child or NULL in case of error.
2157 */
2158xmlNodePtr
2159xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2160 xmlNodePtr prev;
2161
2162 if (parent == NULL) {
2163#ifdef DEBUG_TREE
2164 xmlGenericError(xmlGenericErrorContext,
2165 "xmlAddChild : parent == NULL\n");
2166#endif
2167 return(NULL);
2168 }
2169
2170 if (cur == NULL) {
2171#ifdef DEBUG_TREE
2172 xmlGenericError(xmlGenericErrorContext,
2173 "xmlAddChild : child == NULL\n");
2174#endif
2175 return(NULL);
2176 }
2177
2178 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2179 (cur->doc != parent->doc)) {
2180#ifdef DEBUG_TREE
2181 xmlGenericError(xmlGenericErrorContext,
2182 "Elements moved to a different document\n");
2183#endif
2184 }
2185
2186 /*
2187 * add the first element at the end of the children list.
2188 */
2189 if (parent->children == NULL) {
2190 parent->children = cur;
2191 } else {
2192 /*
2193 * If cur and parent->last both are TEXT nodes, then merge them.
2194 */
2195 if ((cur->type == XML_TEXT_NODE) &&
2196 (parent->last->type == XML_TEXT_NODE) &&
2197 (cur->name == parent->last->name)) {
2198#ifndef XML_USE_BUFFER_CONTENT
2199 xmlNodeAddContent(parent->last, cur->content);
2200#else
2201 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2202#endif
2203 /*
2204 * if it's the only child, nothing more to be done.
2205 */
2206 if (cur->next == NULL) {
2207 xmlFreeNode(cur);
2208 return(parent->last);
2209 }
2210 prev = cur;
2211 cur = cur->next;
2212 xmlFreeNode(prev);
2213 }
2214 prev = parent->last;
2215 prev->next = cur;
2216 cur->prev = prev;
2217 }
2218 while (cur->next != NULL) {
2219 cur->parent = parent;
2220 if (cur->doc != parent->doc) {
2221 xmlSetTreeDoc(cur, parent->doc);
2222 }
2223 cur = cur->next;
2224 }
2225 cur->parent = parent;
2226 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2227 parent->last = cur;
2228
2229 return(cur);
2230}
2231
2232/**
2233 * xmlAddChild:
2234 * @parent: the parent node
2235 * @cur: the child node
2236 *
2237 * Add a new child element, to @parent, at the end of the child list
2238 * merging adjacent TEXT nodes (in which case @cur is freed)
2239 * Returns the child or NULL in case of error.
2240 */
2241xmlNodePtr
2242xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2243 xmlNodePtr prev;
2244
2245 if (parent == NULL) {
2246#ifdef DEBUG_TREE
2247 xmlGenericError(xmlGenericErrorContext,
2248 "xmlAddChild : parent == NULL\n");
2249#endif
2250 return(NULL);
2251 }
2252
2253 if (cur == NULL) {
2254#ifdef DEBUG_TREE
2255 xmlGenericError(xmlGenericErrorContext,
2256 "xmlAddChild : child == NULL\n");
2257#endif
2258 return(NULL);
2259 }
2260
Owen Taylor3473f882001-02-23 17:55:21 +00002261 /*
2262 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002263 * cur is then freed.
2264 */
2265 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002266 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002267 (parent->content != NULL)) {
2268#ifndef XML_USE_BUFFER_CONTENT
2269 xmlNodeAddContent(parent, cur->content);
2270#else
2271 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2272#endif
2273 xmlFreeNode(cur);
2274 return(parent);
2275 }
2276 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2277 (parent->last->name == cur->name)) {
2278#ifndef XML_USE_BUFFER_CONTENT
2279 xmlNodeAddContent(parent->last, cur->content);
2280#else
2281 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2282#endif
2283 xmlFreeNode(cur);
2284 return(parent->last);
2285 }
2286 }
2287
2288 /*
2289 * add the new element at the end of the children list.
2290 */
2291 cur->parent = parent;
2292 if (cur->doc != parent->doc) {
2293 xmlSetTreeDoc(cur, parent->doc);
2294 }
2295
2296 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002297 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002298 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002299 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002300 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002301#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002302 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002303#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002304 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002305#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002306 xmlFreeNode(cur);
2307 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002308 }
2309 if (parent->children == NULL) {
2310 parent->children = cur;
2311 parent->last = cur;
2312 } else {
2313 prev = parent->last;
2314 prev->next = cur;
2315 cur->prev = prev;
2316 parent->last = cur;
2317 }
2318
2319 return(cur);
2320}
2321
2322/**
2323 * xmlGetLastChild:
2324 * @parent: the parent node
2325 *
2326 * Search the last child of a node.
2327 * Returns the last child or NULL if none.
2328 */
2329xmlNodePtr
2330xmlGetLastChild(xmlNodePtr parent) {
2331 if (parent == NULL) {
2332#ifdef DEBUG_TREE
2333 xmlGenericError(xmlGenericErrorContext,
2334 "xmlGetLastChild : parent == NULL\n");
2335#endif
2336 return(NULL);
2337 }
2338 return(parent->last);
2339}
2340
2341/**
2342 * xmlFreeNodeList:
2343 * @cur: the first node in the list
2344 *
2345 * Free a node and all its siblings, this is a recursive behaviour, all
2346 * the children are freed too.
2347 */
2348void
2349xmlFreeNodeList(xmlNodePtr cur) {
2350 xmlNodePtr next;
2351 if (cur == NULL) {
2352#ifdef DEBUG_TREE
2353 xmlGenericError(xmlGenericErrorContext,
2354 "xmlFreeNodeList : node == NULL\n");
2355#endif
2356 return;
2357 }
2358 while (cur != NULL) {
2359 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002360 /* unroll to speed up freeing the document */
2361 if (cur->type != XML_DTD_NODE) {
2362 if ((cur->children != NULL) &&
2363 (cur->type != XML_ENTITY_REF_NODE))
2364 xmlFreeNodeList(cur->children);
2365 if (cur->properties != NULL)
2366 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002367 if ((cur->type != XML_ELEMENT_NODE) &&
2368 (cur->type != XML_XINCLUDE_START) &&
2369 (cur->type != XML_XINCLUDE_END) &&
2370 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002371#ifndef XML_USE_BUFFER_CONTENT
2372 if (cur->content != NULL) xmlFree(cur->content);
2373#else
2374 if (cur->content != NULL) xmlBufferFree(cur->content);
2375#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002376 }
2377 if (((cur->type == XML_ELEMENT_NODE) ||
2378 (cur->type == XML_XINCLUDE_START) ||
2379 (cur->type == XML_XINCLUDE_END)) &&
2380 (cur->nsDef != NULL))
2381 xmlFreeNsList(cur->nsDef);
2382
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002383 /*
2384 * When a node is a text node or a comment, it uses a global static
2385 * variable for the name of the node.
2386 *
2387 * The xmlStrEqual comparisons need to be done when (happened with
2388 * XML::libXML and XML::libXSLT) the library is included twice
2389 * statically in the binary and a tree allocated by one occurent
2390 * of the lib gets freed by the other occurence, in this case
2391 * the string addresses compare are not sufficient.
2392 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002393 if ((cur->name != NULL) &&
2394 (cur->name != xmlStringText) &&
2395 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002396 (cur->name != xmlStringComment)) {
2397 if (cur->type == XML_TEXT_NODE) {
2398 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2399 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2400 xmlFree((char *) cur->name);
2401 } else if (cur->type == XML_COMMENT_NODE) {
2402 if (!xmlStrEqual(cur->name, xmlStringComment))
2403 xmlFree((char *) cur->name);
2404 } else
2405 xmlFree((char *) cur->name);
2406 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002407 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002408 xmlFree(cur);
2409 }
Owen Taylor3473f882001-02-23 17:55:21 +00002410 cur = next;
2411 }
2412}
2413
2414/**
2415 * xmlFreeNode:
2416 * @cur: the node
2417 *
2418 * Free a node, this is a recursive behaviour, all the children are freed too.
2419 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2420 */
2421void
2422xmlFreeNode(xmlNodePtr cur) {
2423 if (cur == NULL) {
2424#ifdef DEBUG_TREE
2425 xmlGenericError(xmlGenericErrorContext,
2426 "xmlFreeNode : node == NULL\n");
2427#endif
2428 return;
2429 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002430 /* use xmlFreeDtd for DTD nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002431 if (cur->type == XML_DTD_NODE)
2432 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002433 if ((cur->children != NULL) &&
2434 (cur->type != XML_ENTITY_REF_NODE))
2435 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002436 if (cur->properties != NULL)
2437 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002438 if ((cur->type != XML_ELEMENT_NODE) &&
2439 (cur->content != NULL) &&
2440 (cur->type != XML_ENTITY_REF_NODE) &&
2441 (cur->type != XML_XINCLUDE_END) &&
2442 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002443#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002444 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002445#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002446 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002447#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002448 }
2449
Daniel Veillardacd370f2001-06-09 17:17:51 +00002450 /*
2451 * When a node is a text node or a comment, it uses a global static
2452 * variable for the name of the node.
2453 *
2454 * The xmlStrEqual comparisons need to be done when (happened with
2455 * XML::libXML and XML::libXSLT) the library is included twice statically
2456 * in the binary and a tree allocated by one occurent of the lib gets
2457 * freed by the other occurence, in this case the string addresses compare
2458 * are not sufficient.
2459 */
Owen Taylor3473f882001-02-23 17:55:21 +00002460 if ((cur->name != NULL) &&
2461 (cur->name != xmlStringText) &&
2462 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002463 (cur->name != xmlStringComment)) {
2464 if (cur->type == XML_TEXT_NODE) {
2465 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2466 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2467 xmlFree((char *) cur->name);
2468 } else if (cur->type == XML_COMMENT_NODE) {
2469 if (!xmlStrEqual(cur->name, xmlStringComment))
2470 xmlFree((char *) cur->name);
2471 } else
2472 xmlFree((char *) cur->name);
2473 }
2474
Owen Taylor3473f882001-02-23 17:55:21 +00002475 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002476 xmlFree(cur);
2477}
2478
2479/**
2480 * xmlUnlinkNode:
2481 * @cur: the node
2482 *
2483 * Unlink a node from it's current context, the node is not freed
2484 */
2485void
2486xmlUnlinkNode(xmlNodePtr cur) {
2487 if (cur == NULL) {
2488#ifdef DEBUG_TREE
2489 xmlGenericError(xmlGenericErrorContext,
2490 "xmlUnlinkNode : node == NULL\n");
2491#endif
2492 return;
2493 }
2494 if ((cur->parent != NULL) && (cur->parent->children == cur))
2495 cur->parent->children = cur->next;
2496 if ((cur->parent != NULL) && (cur->parent->last == cur))
2497 cur->parent->last = cur->prev;
2498 if (cur->next != NULL)
2499 cur->next->prev = cur->prev;
2500 if (cur->prev != NULL)
2501 cur->prev->next = cur->next;
2502 cur->next = cur->prev = NULL;
2503 cur->parent = NULL;
2504}
2505
2506/**
2507 * xmlReplaceNode:
2508 * @old: the old node
2509 * @cur: the node
2510 *
2511 * Unlink the old node from it's current context, prune the new one
2512 * at the same place. If cur was already inserted in a document it is
2513 * first unlinked from its existing context.
2514 *
2515 * Returns the old node
2516 */
2517xmlNodePtr
2518xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2519 if (old == NULL) {
2520#ifdef DEBUG_TREE
2521 xmlGenericError(xmlGenericErrorContext,
2522 "xmlReplaceNode : old == NULL\n");
2523#endif
2524 return(NULL);
2525 }
2526 if (cur == NULL) {
2527 xmlUnlinkNode(old);
2528 return(old);
2529 }
2530 if (cur == old) {
2531 return(old);
2532 }
2533 xmlUnlinkNode(cur);
2534 cur->doc = old->doc;
2535 cur->parent = old->parent;
2536 cur->next = old->next;
2537 if (cur->next != NULL)
2538 cur->next->prev = cur;
2539 cur->prev = old->prev;
2540 if (cur->prev != NULL)
2541 cur->prev->next = cur;
2542 if (cur->parent != NULL) {
2543 if (cur->parent->children == old)
2544 cur->parent->children = cur;
2545 if (cur->parent->last == old)
2546 cur->parent->last = cur;
2547 }
2548 old->next = old->prev = NULL;
2549 old->parent = NULL;
2550 return(old);
2551}
2552
2553/************************************************************************
2554 * *
2555 * Copy operations *
2556 * *
2557 ************************************************************************/
2558
2559/**
2560 * xmlCopyNamespace:
2561 * @cur: the namespace
2562 *
2563 * Do a copy of the namespace.
2564 *
2565 * Returns: a new xmlNsPtr, or NULL in case of error.
2566 */
2567xmlNsPtr
2568xmlCopyNamespace(xmlNsPtr cur) {
2569 xmlNsPtr ret;
2570
2571 if (cur == NULL) return(NULL);
2572 switch (cur->type) {
2573 case XML_LOCAL_NAMESPACE:
2574 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2575 break;
2576 default:
2577#ifdef DEBUG_TREE
2578 xmlGenericError(xmlGenericErrorContext,
2579 "xmlCopyNamespace: invalid type %d\n", cur->type);
2580#endif
2581 return(NULL);
2582 }
2583 return(ret);
2584}
2585
2586/**
2587 * xmlCopyNamespaceList:
2588 * @cur: the first namespace
2589 *
2590 * Do a copy of an namespace list.
2591 *
2592 * Returns: a new xmlNsPtr, or NULL in case of error.
2593 */
2594xmlNsPtr
2595xmlCopyNamespaceList(xmlNsPtr cur) {
2596 xmlNsPtr ret = NULL;
2597 xmlNsPtr p = NULL,q;
2598
2599 while (cur != NULL) {
2600 q = xmlCopyNamespace(cur);
2601 if (p == NULL) {
2602 ret = p = q;
2603 } else {
2604 p->next = q;
2605 p = q;
2606 }
2607 cur = cur->next;
2608 }
2609 return(ret);
2610}
2611
2612static xmlNodePtr
2613xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2614/**
2615 * xmlCopyProp:
2616 * @target: the element where the attribute will be grafted
2617 * @cur: the attribute
2618 *
2619 * Do a copy of the attribute.
2620 *
2621 * Returns: a new xmlAttrPtr, or NULL in case of error.
2622 */
2623xmlAttrPtr
2624xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2625 xmlAttrPtr ret;
2626
2627 if (cur == NULL) return(NULL);
2628 if (target != NULL)
2629 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2630 else if (cur->parent != NULL)
2631 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2632 else if (cur->children != NULL)
2633 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2634 else
2635 ret = xmlNewDocProp(NULL, cur->name, NULL);
2636 if (ret == NULL) return(NULL);
2637 ret->parent = target;
2638
2639 if ((cur->ns != NULL) && (target != NULL)) {
2640 xmlNsPtr ns;
2641
2642 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2643 ret->ns = ns;
2644 } else
2645 ret->ns = NULL;
2646
2647 if (cur->children != NULL) {
2648 xmlNodePtr tmp;
2649
2650 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2651 ret->last = NULL;
2652 tmp = ret->children;
2653 while (tmp != NULL) {
2654 /* tmp->parent = (xmlNodePtr)ret; */
2655 if (tmp->next == NULL)
2656 ret->last = tmp;
2657 tmp = tmp->next;
2658 }
2659 }
2660 return(ret);
2661}
2662
2663/**
2664 * xmlCopyPropList:
2665 * @target: the element where the attributes will be grafted
2666 * @cur: the first attribute
2667 *
2668 * Do a copy of an attribute list.
2669 *
2670 * Returns: a new xmlAttrPtr, or NULL in case of error.
2671 */
2672xmlAttrPtr
2673xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2674 xmlAttrPtr ret = NULL;
2675 xmlAttrPtr p = NULL,q;
2676
2677 while (cur != NULL) {
2678 q = xmlCopyProp(target, cur);
2679 if (p == NULL) {
2680 ret = p = q;
2681 } else {
2682 p->next = q;
2683 q->prev = p;
2684 p = q;
2685 }
2686 cur = cur->next;
2687 }
2688 return(ret);
2689}
2690
2691/*
2692 * NOTE abeut the CopyNode operations !
2693 *
2694 * They are splitted into external and internal parts for one
2695 * tricky reason: namespaces. Doing a direct copy of a node
2696 * say RPM:Copyright without changing the namespace pointer to
2697 * something else can produce stale links. One way to do it is
2698 * to keep a reference counter but this doesn't work as soon
2699 * as one move the element or the subtree out of the scope of
2700 * the existing namespace. The actual solution seems to add
2701 * a copy of the namespace at the top of the copied tree if
2702 * not available in the subtree.
2703 * Hence two functions, the public front-end call the inner ones
2704 */
2705
2706static xmlNodePtr
2707xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2708
2709static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002710xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002711 int recursive) {
2712 xmlNodePtr ret;
2713
2714 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002715 switch (node->type) {
2716 case XML_TEXT_NODE:
2717 case XML_CDATA_SECTION_NODE:
2718 case XML_ELEMENT_NODE:
2719 case XML_ENTITY_REF_NODE:
2720 case XML_ENTITY_NODE:
2721 case XML_PI_NODE:
2722 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002723 case XML_XINCLUDE_START:
2724 case XML_XINCLUDE_END:
2725 break;
2726 case XML_ATTRIBUTE_NODE:
2727 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2728 case XML_NAMESPACE_DECL:
2729 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2730
Daniel Veillard39196eb2001-06-19 18:09:42 +00002731 case XML_DOCUMENT_NODE:
2732 case XML_HTML_DOCUMENT_NODE:
2733#ifdef LIBXML_DOCB_ENABLED
2734 case XML_DOCB_DOCUMENT_NODE:
2735#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002736 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002737 case XML_DOCUMENT_TYPE_NODE:
2738 case XML_DOCUMENT_FRAG_NODE:
2739 case XML_NOTATION_NODE:
2740 case XML_DTD_NODE:
2741 case XML_ELEMENT_DECL:
2742 case XML_ATTRIBUTE_DECL:
2743 case XML_ENTITY_DECL:
2744 return(NULL);
2745 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002746
Owen Taylor3473f882001-02-23 17:55:21 +00002747 /*
2748 * Allocate a new node and fill the fields.
2749 */
2750 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2751 if (ret == NULL) {
2752 xmlGenericError(xmlGenericErrorContext,
2753 "xmlStaticCopyNode : malloc failed\n");
2754 return(NULL);
2755 }
2756 memset(ret, 0, sizeof(xmlNode));
2757 ret->type = node->type;
2758
2759 ret->doc = doc;
2760 ret->parent = parent;
2761 if (node->name == xmlStringText)
2762 ret->name = xmlStringText;
2763 else if (node->name == xmlStringTextNoenc)
2764 ret->name = xmlStringTextNoenc;
2765 else if (node->name == xmlStringComment)
2766 ret->name = xmlStringComment;
2767 else if (node->name != NULL)
2768 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002769 if ((node->type != XML_ELEMENT_NODE) &&
2770 (node->content != NULL) &&
2771 (node->type != XML_ENTITY_REF_NODE) &&
2772 (node->type != XML_XINCLUDE_END) &&
2773 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002774#ifndef XML_USE_BUFFER_CONTENT
2775 ret->content = xmlStrdup(node->content);
2776#else
2777 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2778 xmlBufferSetAllocationScheme(ret->content,
2779 xmlGetBufferAllocationScheme());
2780 xmlBufferAdd(ret->content,
2781 xmlBufferContent(node->content),
2782 xmlBufferLength(node->content));
2783#endif
2784 }
2785 if (parent != NULL)
2786 xmlAddChild(parent, ret);
2787
2788 if (!recursive) return(ret);
2789 if (node->nsDef != NULL)
2790 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2791
2792 if (node->ns != NULL) {
2793 xmlNsPtr ns;
2794
2795 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2796 if (ns == NULL) {
2797 /*
2798 * Humm, we are copying an element whose namespace is defined
2799 * out of the new tree scope. Search it in the original tree
2800 * and add it at the top of the new tree
2801 */
2802 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2803 if (ns != NULL) {
2804 xmlNodePtr root = ret;
2805
2806 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002807 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002808 }
2809 } else {
2810 /*
2811 * reference the existing namespace definition in our own tree.
2812 */
2813 ret->ns = ns;
2814 }
2815 }
2816 if (node->properties != NULL)
2817 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002818 if (node->type == XML_ENTITY_REF_NODE) {
2819 if ((doc == NULL) || (node->doc != doc)) {
2820 /*
2821 * The copied node will go into a separate document, so
2822 * to havoid dandling references to the ENTITY_DECL node
2823 * we cannot keep the reference. Try to find it in the
2824 * target document.
2825 */
2826 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2827 } else {
2828 ret->children = node->children;
2829 }
2830 } else if (node->children != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002831 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
2832 UPDATE_LAST_CHILD_AND_PARENT(ret)
2833 return(ret);
2834}
2835
2836static xmlNodePtr
2837xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2838 xmlNodePtr ret = NULL;
2839 xmlNodePtr p = NULL,q;
2840
2841 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002842 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002843 if (doc == NULL) {
2844 node = node->next;
2845 continue;
2846 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002847 if (doc->intSubset == NULL) {
2848 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2849 q->doc = doc;
2850 q->parent = parent;
2851 doc->intSubset = (xmlDtdPtr) q;
2852 } else {
2853 q = (xmlNodePtr) doc->intSubset;
2854 }
2855 } else
2856 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002857 if (ret == NULL) {
2858 q->prev = NULL;
2859 ret = p = q;
2860 } else {
2861 p->next = q;
2862 q->prev = p;
2863 p = q;
2864 }
2865 node = node->next;
2866 }
2867 return(ret);
2868}
2869
2870/**
2871 * xmlCopyNode:
2872 * @node: the node
2873 * @recursive: if 1 do a recursive copy.
2874 *
2875 * Do a copy of the node.
2876 *
2877 * Returns: a new xmlNodePtr, or NULL in case of error.
2878 */
2879xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002880xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002881 xmlNodePtr ret;
2882
2883 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2884 return(ret);
2885}
2886
2887/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002888 * xmlDocCopyNode:
2889 * @node: the node
2890 * @recursive: if 1 do a recursive copy.
2891 *
2892 * Do a copy of the node to a given document.
2893 *
2894 * Returns: a new xmlNodePtr, or NULL in case of error.
2895 */
2896xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002897xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002898 xmlNodePtr ret;
2899
2900 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2901 return(ret);
2902}
2903
2904/**
Owen Taylor3473f882001-02-23 17:55:21 +00002905 * xmlCopyNodeList:
2906 * @node: the first node in the list.
2907 *
2908 * Do a recursive copy of the node list.
2909 *
2910 * Returns: a new xmlNodePtr, or NULL in case of error.
2911 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002912xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002913 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2914 return(ret);
2915}
2916
2917/**
Owen Taylor3473f882001-02-23 17:55:21 +00002918 * xmlCopyDtd:
2919 * @dtd: the dtd
2920 *
2921 * Do a copy of the dtd.
2922 *
2923 * Returns: a new xmlDtdPtr, or NULL in case of error.
2924 */
2925xmlDtdPtr
2926xmlCopyDtd(xmlDtdPtr dtd) {
2927 xmlDtdPtr ret;
2928
2929 if (dtd == NULL) return(NULL);
2930 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2931 if (ret == NULL) return(NULL);
2932 if (dtd->entities != NULL)
2933 ret->entities = (void *) xmlCopyEntitiesTable(
2934 (xmlEntitiesTablePtr) dtd->entities);
2935 if (dtd->notations != NULL)
2936 ret->notations = (void *) xmlCopyNotationTable(
2937 (xmlNotationTablePtr) dtd->notations);
2938 if (dtd->elements != NULL)
2939 ret->elements = (void *) xmlCopyElementTable(
2940 (xmlElementTablePtr) dtd->elements);
2941 if (dtd->attributes != NULL)
2942 ret->attributes = (void *) xmlCopyAttributeTable(
2943 (xmlAttributeTablePtr) dtd->attributes);
2944 return(ret);
2945}
2946
2947/**
2948 * xmlCopyDoc:
2949 * @doc: the document
2950 * @recursive: if 1 do a recursive copy.
2951 *
2952 * Do a copy of the document info. If recursive, the content tree will
2953 * be copied too as well as Dtd, namespaces and entities.
2954 *
2955 * Returns: a new xmlDocPtr, or NULL in case of error.
2956 */
2957xmlDocPtr
2958xmlCopyDoc(xmlDocPtr doc, int recursive) {
2959 xmlDocPtr ret;
2960
2961 if (doc == NULL) return(NULL);
2962 ret = xmlNewDoc(doc->version);
2963 if (ret == NULL) return(NULL);
2964 if (doc->name != NULL)
2965 ret->name = xmlMemStrdup(doc->name);
2966 if (doc->encoding != NULL)
2967 ret->encoding = xmlStrdup(doc->encoding);
2968 ret->charset = doc->charset;
2969 ret->compression = doc->compression;
2970 ret->standalone = doc->standalone;
2971 if (!recursive) return(ret);
2972
Daniel Veillardb33c2012001-04-25 12:59:04 +00002973 ret->last = NULL;
2974 ret->children = NULL;
2975 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002976 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002977 ret->intSubset->doc = ret;
2978 ret->intSubset->parent = ret;
2979 }
Owen Taylor3473f882001-02-23 17:55:21 +00002980 if (doc->oldNs != NULL)
2981 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2982 if (doc->children != NULL) {
2983 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002984
2985 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2986 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002987 ret->last = NULL;
2988 tmp = ret->children;
2989 while (tmp != NULL) {
2990 if (tmp->next == NULL)
2991 ret->last = tmp;
2992 tmp = tmp->next;
2993 }
2994 }
2995 return(ret);
2996}
2997
2998/************************************************************************
2999 * *
3000 * Content access functions *
3001 * *
3002 ************************************************************************/
3003
3004/**
3005 * xmlDocGetRootElement:
3006 * @doc: the document
3007 *
3008 * Get the root element of the document (doc->children is a list
3009 * containing possibly comments, PIs, etc ...).
3010 *
3011 * Returns the xmlNodePtr for the root or NULL
3012 */
3013xmlNodePtr
3014xmlDocGetRootElement(xmlDocPtr doc) {
3015 xmlNodePtr ret;
3016
3017 if (doc == NULL) return(NULL);
3018 ret = doc->children;
3019 while (ret != NULL) {
3020 if (ret->type == XML_ELEMENT_NODE)
3021 return(ret);
3022 ret = ret->next;
3023 }
3024 return(ret);
3025}
3026
3027/**
3028 * xmlDocSetRootElement:
3029 * @doc: the document
3030 * @root: the new document root element
3031 *
3032 * Set the root element of the document (doc->children is a list
3033 * containing possibly comments, PIs, etc ...).
3034 *
3035 * Returns the old root element if any was found
3036 */
3037xmlNodePtr
3038xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3039 xmlNodePtr old = NULL;
3040
3041 if (doc == NULL) return(NULL);
3042 old = doc->children;
3043 while (old != NULL) {
3044 if (old->type == XML_ELEMENT_NODE)
3045 break;
3046 old = old->next;
3047 }
3048 if (old == NULL) {
3049 if (doc->children == NULL) {
3050 doc->children = root;
3051 doc->last = root;
3052 } else {
3053 xmlAddSibling(doc->children, root);
3054 }
3055 } else {
3056 xmlReplaceNode(old, root);
3057 }
3058 return(old);
3059}
3060
3061/**
3062 * xmlNodeSetLang:
3063 * @cur: the node being changed
3064 * @lang: the langage description
3065 *
3066 * Set the language of a node, i.e. the values of the xml:lang
3067 * attribute.
3068 */
3069void
3070xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3071 if (cur == NULL) return;
3072 switch(cur->type) {
3073 case XML_TEXT_NODE:
3074 case XML_CDATA_SECTION_NODE:
3075 case XML_COMMENT_NODE:
3076 case XML_DOCUMENT_NODE:
3077 case XML_DOCUMENT_TYPE_NODE:
3078 case XML_DOCUMENT_FRAG_NODE:
3079 case XML_NOTATION_NODE:
3080 case XML_HTML_DOCUMENT_NODE:
3081 case XML_DTD_NODE:
3082 case XML_ELEMENT_DECL:
3083 case XML_ATTRIBUTE_DECL:
3084 case XML_ENTITY_DECL:
3085 case XML_PI_NODE:
3086 case XML_ENTITY_REF_NODE:
3087 case XML_ENTITY_NODE:
3088 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003089#ifdef LIBXML_DOCB_ENABLED
3090 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003091#endif
3092 case XML_XINCLUDE_START:
3093 case XML_XINCLUDE_END:
3094 return;
3095 case XML_ELEMENT_NODE:
3096 case XML_ATTRIBUTE_NODE:
3097 break;
3098 }
3099 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3100}
3101
3102/**
3103 * xmlNodeGetLang:
3104 * @cur: the node being checked
3105 *
3106 * Searches the language of a node, i.e. the values of the xml:lang
3107 * attribute or the one carried by the nearest ancestor.
3108 *
3109 * Returns a pointer to the lang value, or NULL if not found
3110 * It's up to the caller to free the memory.
3111 */
3112xmlChar *
3113xmlNodeGetLang(xmlNodePtr cur) {
3114 xmlChar *lang;
3115
3116 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003117 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003118 if (lang != NULL)
3119 return(lang);
3120 cur = cur->parent;
3121 }
3122 return(NULL);
3123}
3124
3125
3126/**
3127 * xmlNodeSetSpacePreserve:
3128 * @cur: the node being changed
3129 * @val: the xml:space value ("0": default, 1: "preserve")
3130 *
3131 * Set (or reset) the space preserving behaviour of a node, i.e. the
3132 * value of the xml:space attribute.
3133 */
3134void
3135xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3136 if (cur == NULL) return;
3137 switch(cur->type) {
3138 case XML_TEXT_NODE:
3139 case XML_CDATA_SECTION_NODE:
3140 case XML_COMMENT_NODE:
3141 case XML_DOCUMENT_NODE:
3142 case XML_DOCUMENT_TYPE_NODE:
3143 case XML_DOCUMENT_FRAG_NODE:
3144 case XML_NOTATION_NODE:
3145 case XML_HTML_DOCUMENT_NODE:
3146 case XML_DTD_NODE:
3147 case XML_ELEMENT_DECL:
3148 case XML_ATTRIBUTE_DECL:
3149 case XML_ENTITY_DECL:
3150 case XML_PI_NODE:
3151 case XML_ENTITY_REF_NODE:
3152 case XML_ENTITY_NODE:
3153 case XML_NAMESPACE_DECL:
3154 case XML_XINCLUDE_START:
3155 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003156#ifdef LIBXML_DOCB_ENABLED
3157 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003158#endif
3159 return;
3160 case XML_ELEMENT_NODE:
3161 case XML_ATTRIBUTE_NODE:
3162 break;
3163 }
3164 switch (val) {
3165 case 0:
3166 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3167 break;
3168 case 1:
3169 xmlSetProp(cur, BAD_CAST "xml:space",
3170 BAD_CAST "preserve");
3171 break;
3172 }
3173}
3174
3175/**
3176 * xmlNodeGetSpacePreserve:
3177 * @cur: the node being checked
3178 *
3179 * Searches the space preserving behaviour of a node, i.e. the values
3180 * of the xml:space attribute or the one carried by the nearest
3181 * ancestor.
3182 *
3183 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
3184 */
3185int
3186xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3187 xmlChar *space;
3188
3189 while (cur != NULL) {
3190 space = xmlGetProp(cur, BAD_CAST "xml:space");
3191 if (space != NULL) {
3192 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3193 xmlFree(space);
3194 return(1);
3195 }
3196 if (xmlStrEqual(space, BAD_CAST "default")) {
3197 xmlFree(space);
3198 return(0);
3199 }
3200 xmlFree(space);
3201 }
3202 cur = cur->parent;
3203 }
3204 return(-1);
3205}
3206
3207/**
3208 * xmlNodeSetName:
3209 * @cur: the node being changed
3210 * @name: the new tag name
3211 *
3212 * Set (or reset) the name of a node.
3213 */
3214void
3215xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3216 if (cur == NULL) return;
3217 if (name == NULL) return;
3218 switch(cur->type) {
3219 case XML_TEXT_NODE:
3220 case XML_CDATA_SECTION_NODE:
3221 case XML_COMMENT_NODE:
3222 case XML_DOCUMENT_TYPE_NODE:
3223 case XML_DOCUMENT_FRAG_NODE:
3224 case XML_NOTATION_NODE:
3225 case XML_HTML_DOCUMENT_NODE:
3226 case XML_NAMESPACE_DECL:
3227 case XML_XINCLUDE_START:
3228 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003229#ifdef LIBXML_DOCB_ENABLED
3230 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003231#endif
3232 return;
3233 case XML_ELEMENT_NODE:
3234 case XML_ATTRIBUTE_NODE:
3235 case XML_PI_NODE:
3236 case XML_ENTITY_REF_NODE:
3237 case XML_ENTITY_NODE:
3238 case XML_DTD_NODE:
3239 case XML_DOCUMENT_NODE:
3240 case XML_ELEMENT_DECL:
3241 case XML_ATTRIBUTE_DECL:
3242 case XML_ENTITY_DECL:
3243 break;
3244 }
3245 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3246 cur->name = xmlStrdup(name);
3247}
3248
3249/**
3250 * xmlNodeSetBase:
3251 * @cur: the node being changed
3252 * @uri: the new base URI
3253 *
3254 * Set (or reset) the base URI of a node, i.e. the value of the
3255 * xml:base attribute.
3256 */
3257void
3258xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3259 if (cur == NULL) return;
3260 switch(cur->type) {
3261 case XML_TEXT_NODE:
3262 case XML_CDATA_SECTION_NODE:
3263 case XML_COMMENT_NODE:
3264 case XML_DOCUMENT_NODE:
3265 case XML_DOCUMENT_TYPE_NODE:
3266 case XML_DOCUMENT_FRAG_NODE:
3267 case XML_NOTATION_NODE:
3268 case XML_HTML_DOCUMENT_NODE:
3269 case XML_DTD_NODE:
3270 case XML_ELEMENT_DECL:
3271 case XML_ATTRIBUTE_DECL:
3272 case XML_ENTITY_DECL:
3273 case XML_PI_NODE:
3274 case XML_ENTITY_REF_NODE:
3275 case XML_ENTITY_NODE:
3276 case XML_NAMESPACE_DECL:
3277 case XML_XINCLUDE_START:
3278 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003279#ifdef LIBXML_DOCB_ENABLED
3280 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003281#endif
3282 return;
3283 case XML_ELEMENT_NODE:
3284 case XML_ATTRIBUTE_NODE:
3285 break;
3286 }
3287 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3288}
3289
3290/**
Owen Taylor3473f882001-02-23 17:55:21 +00003291 * xmlNodeGetBase:
3292 * @doc: the document the node pertains to
3293 * @cur: the node being checked
3294 *
3295 * Searches for the BASE URL. The code should work on both XML
3296 * and HTML document even if base mechanisms are completely different.
3297 * It returns the base as defined in RFC 2396 sections
3298 * 5.1.1. Base URI within Document Content
3299 * and
3300 * 5.1.2. Base URI from the Encapsulating Entity
3301 * However it does not return the document base (5.1.3), use
3302 * xmlDocumentGetBase() for this
3303 *
3304 * Returns a pointer to the base URL, or NULL if not found
3305 * It's up to the caller to free the memory.
3306 */
3307xmlChar *
3308xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003309 xmlChar *oldbase = NULL;
3310 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003311
3312 if ((cur == NULL) && (doc == NULL))
3313 return(NULL);
3314 if (doc == NULL) doc = cur->doc;
3315 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3316 cur = doc->children;
3317 while ((cur != NULL) && (cur->name != NULL)) {
3318 if (cur->type != XML_ELEMENT_NODE) {
3319 cur = cur->next;
3320 continue;
3321 }
3322 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3323 cur = cur->children;
3324 continue;
3325 }
3326 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3327 cur = cur->children;
3328 continue;
3329 }
3330 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3331 return(xmlGetProp(cur, BAD_CAST "href"));
3332 }
3333 cur = cur->next;
3334 }
3335 return(NULL);
3336 }
3337 while (cur != NULL) {
3338 if (cur->type == XML_ENTITY_DECL) {
3339 xmlEntityPtr ent = (xmlEntityPtr) cur;
3340 return(xmlStrdup(ent->URI));
3341 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003342 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003343 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003344 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003345 if (oldbase != NULL) {
3346 newbase = xmlBuildURI(oldbase, base);
3347 if (newbase != NULL) {
3348 xmlFree(oldbase);
3349 xmlFree(base);
3350 oldbase = newbase;
3351 } else {
3352 xmlFree(oldbase);
3353 xmlFree(base);
3354 return(NULL);
3355 }
3356 } else {
3357 oldbase = base;
3358 }
3359 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3360 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3361 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3362 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003363 }
3364 }
Owen Taylor3473f882001-02-23 17:55:21 +00003365 cur = cur->parent;
3366 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003367 if ((doc != NULL) && (doc->URL != NULL)) {
3368 if (oldbase == NULL)
3369 return(xmlStrdup(doc->URL));
3370 newbase = xmlBuildURI(oldbase, doc->URL);
3371 xmlFree(oldbase);
3372 return(newbase);
3373 }
3374 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003375}
3376
3377/**
3378 * xmlNodeGetContent:
3379 * @cur: the node being read
3380 *
3381 * Read the value of a node, this can be either the text carried
3382 * directly by this node if it's a TEXT node or the aggregate string
3383 * of the values carried by this node child's (TEXT and ENTITY_REF).
3384 * Entity references are substitued.
3385 * Returns a new xmlChar * or NULL if no content is available.
3386 * It's up to the caller to free the memory.
3387 */
3388xmlChar *
3389xmlNodeGetContent(xmlNodePtr cur) {
3390 if (cur == NULL) return(NULL);
3391 switch (cur->type) {
3392 case XML_DOCUMENT_FRAG_NODE:
3393 case XML_ELEMENT_NODE: {
3394 xmlNodePtr tmp = cur;
3395 xmlBufferPtr buffer;
3396 xmlChar *ret;
3397
3398 buffer = xmlBufferCreate();
3399 if (buffer == NULL)
3400 return(NULL);
3401 while (tmp != NULL) {
3402 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003403 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003404 case XML_TEXT_NODE:
3405 if (tmp->content != NULL)
3406#ifndef XML_USE_BUFFER_CONTENT
3407 xmlBufferCat(buffer, tmp->content);
3408#else
3409 xmlBufferCat(buffer,
3410 xmlBufferContent(tmp->content));
3411#endif
3412 break;
3413 case XML_ENTITY_REF_NODE: {
3414 xmlEntityPtr ent;
3415
3416 ent = xmlGetDocEntity(cur->doc, tmp->name);
3417 if (ent != NULL)
3418 xmlBufferCat(buffer, ent->content);
3419 }
3420 default:
3421 break;
3422 }
3423 /*
3424 * Skip to next node
3425 */
3426 if (tmp->children != NULL) {
3427 if (tmp->children->type != XML_ENTITY_DECL) {
3428 tmp = tmp->children;
3429 continue;
3430 }
3431 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003432 if (tmp == cur)
3433 break;
3434
Owen Taylor3473f882001-02-23 17:55:21 +00003435 if (tmp->next != NULL) {
3436 tmp = tmp->next;
3437 continue;
3438 }
3439
3440 do {
3441 tmp = tmp->parent;
3442 if (tmp == NULL)
3443 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003444 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003445 tmp = NULL;
3446 break;
3447 }
3448 if (tmp->next != NULL) {
3449 tmp = tmp->next;
3450 break;
3451 }
3452 } while (tmp != NULL);
3453 }
3454 ret = buffer->content;
3455 buffer->content = NULL;
3456 xmlBufferFree(buffer);
3457 return(ret);
3458 }
3459 case XML_ATTRIBUTE_NODE: {
3460 xmlAttrPtr attr = (xmlAttrPtr) cur;
3461 if (attr->parent != NULL)
3462 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3463 else
3464 return(xmlNodeListGetString(NULL, attr->children, 1));
3465 break;
3466 }
3467 case XML_COMMENT_NODE:
3468 case XML_PI_NODE:
3469 if (cur->content != NULL)
3470#ifndef XML_USE_BUFFER_CONTENT
3471 return(xmlStrdup(cur->content));
3472#else
3473 return(xmlStrdup(xmlBufferContent(cur->content)));
3474#endif
3475 return(NULL);
3476 case XML_ENTITY_REF_NODE:
3477 /*
3478 * Locate the entity, and get it's content
3479 * @@@
3480 */
3481 return(NULL);
3482 case XML_ENTITY_NODE:
3483 case XML_DOCUMENT_NODE:
3484 case XML_HTML_DOCUMENT_NODE:
3485 case XML_DOCUMENT_TYPE_NODE:
3486 case XML_NOTATION_NODE:
3487 case XML_DTD_NODE:
3488 case XML_XINCLUDE_START:
3489 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003490#ifdef LIBXML_DOCB_ENABLED
3491 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003492#endif
3493 return(NULL);
3494 case XML_NAMESPACE_DECL:
3495 return(xmlStrdup(((xmlNsPtr)cur)->href));
3496 case XML_ELEMENT_DECL:
3497 /* TODO !!! */
3498 return(NULL);
3499 case XML_ATTRIBUTE_DECL:
3500 /* TODO !!! */
3501 return(NULL);
3502 case XML_ENTITY_DECL:
3503 /* TODO !!! */
3504 return(NULL);
3505 case XML_CDATA_SECTION_NODE:
3506 case XML_TEXT_NODE:
3507 if (cur->content != NULL)
3508#ifndef XML_USE_BUFFER_CONTENT
3509 return(xmlStrdup(cur->content));
3510#else
3511 return(xmlStrdup(xmlBufferContent(cur->content)));
3512#endif
3513 return(NULL);
3514 }
3515 return(NULL);
3516}
3517
3518/**
3519 * xmlNodeSetContent:
3520 * @cur: the node being modified
3521 * @content: the new value of the content
3522 *
3523 * Replace the content of a node.
3524 */
3525void
3526xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3527 if (cur == NULL) {
3528#ifdef DEBUG_TREE
3529 xmlGenericError(xmlGenericErrorContext,
3530 "xmlNodeSetContent : node == NULL\n");
3531#endif
3532 return;
3533 }
3534 switch (cur->type) {
3535 case XML_DOCUMENT_FRAG_NODE:
3536 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003537 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3538 cur->children = xmlStringGetNodeList(cur->doc, content);
3539 UPDATE_LAST_CHILD_AND_PARENT(cur)
3540 break;
3541 case XML_ATTRIBUTE_NODE:
3542 break;
3543 case XML_TEXT_NODE:
3544 case XML_CDATA_SECTION_NODE:
3545 case XML_ENTITY_REF_NODE:
3546 case XML_ENTITY_NODE:
3547 case XML_PI_NODE:
3548 case XML_COMMENT_NODE:
3549 if (cur->content != NULL) {
3550#ifndef XML_USE_BUFFER_CONTENT
3551 xmlFree(cur->content);
3552#else
3553 xmlBufferFree(cur->content);
3554#endif
3555 }
3556 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3557 cur->last = cur->children = NULL;
3558 if (content != NULL) {
3559#ifndef XML_USE_BUFFER_CONTENT
3560 cur->content = xmlStrdup(content);
3561#else
3562 cur->content = xmlBufferCreateSize(0);
3563 xmlBufferSetAllocationScheme(cur->content,
3564 xmlGetBufferAllocationScheme());
3565 xmlBufferAdd(cur->content, content, -1);
3566#endif
3567 } else
3568 cur->content = NULL;
3569 break;
3570 case XML_DOCUMENT_NODE:
3571 case XML_HTML_DOCUMENT_NODE:
3572 case XML_DOCUMENT_TYPE_NODE:
3573 case XML_XINCLUDE_START:
3574 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003575#ifdef LIBXML_DOCB_ENABLED
3576 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003577#endif
3578 break;
3579 case XML_NOTATION_NODE:
3580 break;
3581 case XML_DTD_NODE:
3582 break;
3583 case XML_NAMESPACE_DECL:
3584 break;
3585 case XML_ELEMENT_DECL:
3586 /* TODO !!! */
3587 break;
3588 case XML_ATTRIBUTE_DECL:
3589 /* TODO !!! */
3590 break;
3591 case XML_ENTITY_DECL:
3592 /* TODO !!! */
3593 break;
3594 }
3595}
3596
3597/**
3598 * xmlNodeSetContentLen:
3599 * @cur: the node being modified
3600 * @content: the new value of the content
3601 * @len: the size of @content
3602 *
3603 * Replace the content of a node.
3604 */
3605void
3606xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3607 if (cur == NULL) {
3608#ifdef DEBUG_TREE
3609 xmlGenericError(xmlGenericErrorContext,
3610 "xmlNodeSetContentLen : node == NULL\n");
3611#endif
3612 return;
3613 }
3614 switch (cur->type) {
3615 case XML_DOCUMENT_FRAG_NODE:
3616 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003617 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3618 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3619 UPDATE_LAST_CHILD_AND_PARENT(cur)
3620 break;
3621 case XML_ATTRIBUTE_NODE:
3622 break;
3623 case XML_TEXT_NODE:
3624 case XML_CDATA_SECTION_NODE:
3625 case XML_ENTITY_REF_NODE:
3626 case XML_ENTITY_NODE:
3627 case XML_PI_NODE:
3628 case XML_COMMENT_NODE:
3629 case XML_NOTATION_NODE:
3630 if (cur->content != NULL) {
3631#ifndef XML_USE_BUFFER_CONTENT
3632 xmlFree(cur->content);
3633#else
3634 xmlBufferFree(cur->content);
3635#endif
3636 }
3637 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3638 cur->children = cur->last = NULL;
3639 if (content != NULL) {
3640#ifndef XML_USE_BUFFER_CONTENT
3641 cur->content = xmlStrndup(content, len);
3642#else
3643 cur->content = xmlBufferCreateSize(len);
3644 xmlBufferSetAllocationScheme(cur->content,
3645 xmlGetBufferAllocationScheme());
3646 xmlBufferAdd(cur->content, content, len);
3647#endif
3648 } else
3649 cur->content = NULL;
3650 break;
3651 case XML_DOCUMENT_NODE:
3652 case XML_DTD_NODE:
3653 case XML_HTML_DOCUMENT_NODE:
3654 case XML_DOCUMENT_TYPE_NODE:
3655 case XML_NAMESPACE_DECL:
3656 case XML_XINCLUDE_START:
3657 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003658#ifdef LIBXML_DOCB_ENABLED
3659 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003660#endif
3661 break;
3662 case XML_ELEMENT_DECL:
3663 /* TODO !!! */
3664 break;
3665 case XML_ATTRIBUTE_DECL:
3666 /* TODO !!! */
3667 break;
3668 case XML_ENTITY_DECL:
3669 /* TODO !!! */
3670 break;
3671 }
3672}
3673
3674/**
3675 * xmlNodeAddContentLen:
3676 * @cur: the node being modified
3677 * @content: extra content
3678 * @len: the size of @content
3679 *
3680 * Append the extra substring to the node content.
3681 */
3682void
3683xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3684 if (cur == NULL) {
3685#ifdef DEBUG_TREE
3686 xmlGenericError(xmlGenericErrorContext,
3687 "xmlNodeAddContentLen : node == NULL\n");
3688#endif
3689 return;
3690 }
3691 if (len <= 0) return;
3692 switch (cur->type) {
3693 case XML_DOCUMENT_FRAG_NODE:
3694 case XML_ELEMENT_NODE: {
Daniel Veillard7db37732001-07-12 01:20:08 +00003695 xmlNodePtr last, newNode;
Owen Taylor3473f882001-02-23 17:55:21 +00003696
Daniel Veillard7db37732001-07-12 01:20:08 +00003697 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003698 newNode = xmlNewTextLen(content, len);
3699 if (newNode != NULL) {
3700 xmlAddChild(cur, newNode);
3701 if ((last != NULL) && (last->next == newNode)) {
3702 xmlTextMerge(last, newNode);
3703 }
3704 }
3705 break;
3706 }
3707 case XML_ATTRIBUTE_NODE:
3708 break;
3709 case XML_TEXT_NODE:
3710 case XML_CDATA_SECTION_NODE:
3711 case XML_ENTITY_REF_NODE:
3712 case XML_ENTITY_NODE:
3713 case XML_PI_NODE:
3714 case XML_COMMENT_NODE:
3715 case XML_NOTATION_NODE:
3716 if (content != NULL) {
3717#ifndef XML_USE_BUFFER_CONTENT
3718 cur->content = xmlStrncat(cur->content, content, len);
3719#else
3720 xmlBufferAdd(cur->content, content, len);
3721#endif
3722 }
3723 case XML_DOCUMENT_NODE:
3724 case XML_DTD_NODE:
3725 case XML_HTML_DOCUMENT_NODE:
3726 case XML_DOCUMENT_TYPE_NODE:
3727 case XML_NAMESPACE_DECL:
3728 case XML_XINCLUDE_START:
3729 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003730#ifdef LIBXML_DOCB_ENABLED
3731 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003732#endif
3733 break;
3734 case XML_ELEMENT_DECL:
3735 case XML_ATTRIBUTE_DECL:
3736 case XML_ENTITY_DECL:
3737 break;
3738 }
3739}
3740
3741/**
3742 * xmlNodeAddContent:
3743 * @cur: the node being modified
3744 * @content: extra content
3745 *
3746 * Append the extra substring to the node content.
3747 */
3748void
3749xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3750 int len;
3751
3752 if (cur == NULL) {
3753#ifdef DEBUG_TREE
3754 xmlGenericError(xmlGenericErrorContext,
3755 "xmlNodeAddContent : node == NULL\n");
3756#endif
3757 return;
3758 }
3759 if (content == NULL) return;
3760 len = xmlStrlen(content);
3761 xmlNodeAddContentLen(cur, content, len);
3762}
3763
3764/**
3765 * xmlTextMerge:
3766 * @first: the first text node
3767 * @second: the second text node being merged
3768 *
3769 * Merge two text nodes into one
3770 * Returns the first text node augmented
3771 */
3772xmlNodePtr
3773xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3774 if (first == NULL) return(second);
3775 if (second == NULL) return(first);
3776 if (first->type != XML_TEXT_NODE) return(first);
3777 if (second->type != XML_TEXT_NODE) return(first);
3778 if (second->name != first->name)
3779 return(first);
3780#ifndef XML_USE_BUFFER_CONTENT
3781 xmlNodeAddContent(first, second->content);
3782#else
3783 xmlNodeAddContent(first, xmlBufferContent(second->content));
3784#endif
3785 xmlUnlinkNode(second);
3786 xmlFreeNode(second);
3787 return(first);
3788}
3789
3790/**
3791 * xmlGetNsList:
3792 * @doc: the document
3793 * @node: the current node
3794 *
3795 * Search all the namespace applying to a given element.
3796 * Returns an NULL terminated array of all the xmlNsPtr found
3797 * that need to be freed by the caller or NULL if no
3798 * namespace if defined
3799 */
3800xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003801xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3802{
Owen Taylor3473f882001-02-23 17:55:21 +00003803 xmlNsPtr cur;
3804 xmlNsPtr *ret = NULL;
3805 int nbns = 0;
3806 int maxns = 10;
3807 int i;
3808
3809 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00003810 if (node->type == XML_ELEMENT_NODE) {
3811 cur = node->nsDef;
3812 while (cur != NULL) {
3813 if (ret == NULL) {
3814 ret =
3815 (xmlNsPtr *) xmlMalloc((maxns + 1) *
3816 sizeof(xmlNsPtr));
3817 if (ret == NULL) {
3818 xmlGenericError(xmlGenericErrorContext,
3819 "xmlGetNsList : out of memory!\n");
3820 return (NULL);
3821 }
3822 ret[nbns] = NULL;
3823 }
3824 for (i = 0; i < nbns; i++) {
3825 if ((cur->prefix == ret[i]->prefix) ||
3826 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
3827 break;
3828 }
3829 if (i >= nbns) {
3830 if (nbns >= maxns) {
3831 maxns *= 2;
3832 ret = (xmlNsPtr *) xmlRealloc(ret,
3833 (maxns +
3834 1) *
3835 sizeof(xmlNsPtr));
3836 if (ret == NULL) {
3837 xmlGenericError(xmlGenericErrorContext,
3838 "xmlGetNsList : realloc failed!\n");
3839 return (NULL);
3840 }
3841 }
3842 ret[nbns++] = cur;
3843 ret[nbns] = NULL;
3844 }
Owen Taylor3473f882001-02-23 17:55:21 +00003845
Daniel Veillard77044732001-06-29 21:31:07 +00003846 cur = cur->next;
3847 }
3848 }
3849 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003850 }
Daniel Veillard77044732001-06-29 21:31:07 +00003851 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003852}
3853
3854/**
3855 * xmlSearchNs:
3856 * @doc: the document
3857 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00003858 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00003859 *
3860 * Search a Ns registered under a given name space for a document.
3861 * recurse on the parents until it finds the defined namespace
3862 * or return NULL otherwise.
3863 * @nameSpace can be NULL, this is a search for the default namespace.
3864 * We don't allow to cross entities boundaries. If you don't declare
3865 * the namespace within those you will be in troubles !!! A warning
3866 * is generated to cover this case.
3867 *
3868 * Returns the namespace pointer or NULL.
3869 */
3870xmlNsPtr
3871xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
3872 xmlNsPtr cur;
3873
3874 if (node == NULL) return(NULL);
3875 if ((nameSpace != NULL) &&
3876 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
3877 if (doc->oldNs == NULL) {
3878 /*
3879 * Allocate a new Namespace and fill the fields.
3880 */
3881 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3882 if (doc->oldNs == NULL) {
3883 xmlGenericError(xmlGenericErrorContext,
3884 "xmlSearchNsByHref : malloc failed\n");
3885 return(NULL);
3886 }
3887 memset(doc->oldNs, 0, sizeof(xmlNs));
3888 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3889
3890 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3891 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3892 }
3893 return(doc->oldNs);
3894 }
3895 while (node != NULL) {
3896 if ((node->type == XML_ENTITY_REF_NODE) ||
3897 (node->type == XML_ENTITY_NODE) ||
3898 (node->type == XML_ENTITY_DECL))
3899 return(NULL);
3900 if (node->type == XML_ELEMENT_NODE) {
3901 cur = node->nsDef;
3902 while (cur != NULL) {
3903 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3904 (cur->href != NULL))
3905 return(cur);
3906 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
3907 (cur->href != NULL) &&
3908 (xmlStrEqual(cur->prefix, nameSpace)))
3909 return(cur);
3910 cur = cur->next;
3911 }
3912 }
3913 node = node->parent;
3914 }
3915 return(NULL);
3916}
3917
3918/**
3919 * xmlSearchNsByHref:
3920 * @doc: the document
3921 * @node: the current node
3922 * @href: the namespace value
3923 *
3924 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3925 * the defined namespace or return NULL otherwise.
3926 * Returns the namespace pointer or NULL.
3927 */
3928xmlNsPtr
3929xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
3930 xmlNsPtr cur;
3931 xmlNodePtr orig = node;
3932
3933 if ((node == NULL) || (href == NULL)) return(NULL);
3934 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
3935 if (doc->oldNs == NULL) {
3936 /*
3937 * Allocate a new Namespace and fill the fields.
3938 */
3939 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3940 if (doc->oldNs == NULL) {
3941 xmlGenericError(xmlGenericErrorContext,
3942 "xmlSearchNsByHref : malloc failed\n");
3943 return(NULL);
3944 }
3945 memset(doc->oldNs, 0, sizeof(xmlNs));
3946 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3947
3948 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3949 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3950 }
3951 return(doc->oldNs);
3952 }
3953 while (node != NULL) {
3954 cur = node->nsDef;
3955 while (cur != NULL) {
3956 if ((cur->href != NULL) && (href != NULL) &&
3957 (xmlStrEqual(cur->href, href))) {
3958 /*
3959 * Check that the prefix is not shadowed between orig and node
3960 */
3961 xmlNodePtr check = orig;
3962 xmlNsPtr tst;
3963
3964 while (check != node) {
3965 tst = check->nsDef;
3966 while (tst != NULL) {
3967 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3968 goto shadowed;
3969 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
3970 (xmlStrEqual(tst->prefix, cur->prefix)))
3971 goto shadowed;
3972 tst = tst->next;
3973 }
3974 check = check->parent;
3975 }
3976 return(cur);
3977 }
3978shadowed:
3979 cur = cur->next;
3980 }
3981 node = node->parent;
3982 }
3983 return(NULL);
3984}
3985
3986/**
3987 * xmlNewReconciliedNs
3988 * @doc: the document
3989 * @tree: a node expected to hold the new namespace
3990 * @ns: the original namespace
3991 *
3992 * This function tries to locate a namespace definition in a tree
3993 * ancestors, or create a new namespace definition node similar to
3994 * @ns trying to reuse the same prefix. However if the given prefix is
3995 * null (default namespace) or reused within the subtree defined by
3996 * @tree or on one of its ancestors then a new prefix is generated.
3997 * Returns the (new) namespace definition or NULL in case of error
3998 */
3999xmlNsPtr
4000xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4001 xmlNsPtr def;
4002 xmlChar prefix[50];
4003 int counter = 1;
4004
4005 if (tree == NULL) {
4006#ifdef DEBUG_TREE
4007 xmlGenericError(xmlGenericErrorContext,
4008 "xmlNewReconciliedNs : tree == NULL\n");
4009#endif
4010 return(NULL);
4011 }
4012 if (ns == NULL) {
4013#ifdef DEBUG_TREE
4014 xmlGenericError(xmlGenericErrorContext,
4015 "xmlNewReconciliedNs : ns == NULL\n");
4016#endif
4017 return(NULL);
4018 }
4019 /*
4020 * Search an existing namespace definition inherited.
4021 */
4022 def = xmlSearchNsByHref(doc, tree, ns->href);
4023 if (def != NULL)
4024 return(def);
4025
4026 /*
4027 * Find a close prefix which is not already in use.
4028 * Let's strip namespace prefixes longer than 20 chars !
4029 */
4030 sprintf((char *) prefix, "%.20s", ns->prefix);
4031 def = xmlSearchNs(doc, tree, prefix);
4032 while (def != NULL) {
4033 if (counter > 1000) return(NULL);
4034 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4035 def = xmlSearchNs(doc, tree, prefix);
4036 }
4037
4038 /*
4039 * Ok, now we are ready to create a new one.
4040 */
4041 def = xmlNewNs(tree, ns->href, prefix);
4042 return(def);
4043}
4044
4045/**
4046 * xmlReconciliateNs
4047 * @doc: the document
4048 * @tree: a node defining the subtree to reconciliate
4049 *
4050 * This function checks that all the namespaces declared within the given
4051 * tree are properly declared. This is needed for example after Copy or Cut
4052 * and then paste operations. The subtree may still hold pointers to
4053 * namespace declarations outside the subtree or invalid/masked. As much
4054 * as possible the function try tu reuse the existing namespaces found in
4055 * the new environment. If not possible the new namespaces are redeclared
4056 * on @tree at the top of the given subtree.
4057 * Returns the number of namespace declarations created or -1 in case of error.
4058 */
4059int
4060xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4061 xmlNsPtr *oldNs = NULL;
4062 xmlNsPtr *newNs = NULL;
4063 int sizeCache = 0;
4064 int nbCache = 0;
4065
4066 xmlNsPtr n;
4067 xmlNodePtr node = tree;
4068 xmlAttrPtr attr;
4069 int ret = 0, i;
4070
4071 while (node != NULL) {
4072 /*
4073 * Reconciliate the node namespace
4074 */
4075 if (node->ns != NULL) {
4076 /*
4077 * initialize the cache if needed
4078 */
4079 if (sizeCache == 0) {
4080 sizeCache = 10;
4081 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4082 sizeof(xmlNsPtr));
4083 if (oldNs == NULL) {
4084 xmlGenericError(xmlGenericErrorContext,
4085 "xmlReconciliateNs : memory pbm\n");
4086 return(-1);
4087 }
4088 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4089 sizeof(xmlNsPtr));
4090 if (newNs == NULL) {
4091 xmlGenericError(xmlGenericErrorContext,
4092 "xmlReconciliateNs : memory pbm\n");
4093 xmlFree(oldNs);
4094 return(-1);
4095 }
4096 }
4097 for (i = 0;i < nbCache;i++) {
4098 if (oldNs[i] == node->ns) {
4099 node->ns = newNs[i];
4100 break;
4101 }
4102 }
4103 if (i == nbCache) {
4104 /*
4105 * Ok we need to recreate a new namespace definition
4106 */
4107 n = xmlNewReconciliedNs(doc, tree, node->ns);
4108 if (n != NULL) { /* :-( what if else ??? */
4109 /*
4110 * check if we need to grow the cache buffers.
4111 */
4112 if (sizeCache <= nbCache) {
4113 sizeCache *= 2;
4114 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4115 sizeof(xmlNsPtr));
4116 if (oldNs == NULL) {
4117 xmlGenericError(xmlGenericErrorContext,
4118 "xmlReconciliateNs : memory pbm\n");
4119 xmlFree(newNs);
4120 return(-1);
4121 }
4122 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4123 sizeof(xmlNsPtr));
4124 if (newNs == NULL) {
4125 xmlGenericError(xmlGenericErrorContext,
4126 "xmlReconciliateNs : memory pbm\n");
4127 xmlFree(oldNs);
4128 return(-1);
4129 }
4130 }
4131 newNs[nbCache] = n;
4132 oldNs[nbCache++] = node->ns;
4133 node->ns = n;
4134 }
4135 }
4136 }
4137 /*
4138 * now check for namespace hold by attributes on the node.
4139 */
4140 attr = node->properties;
4141 while (attr != NULL) {
4142 if (attr->ns != NULL) {
4143 /*
4144 * initialize the cache if needed
4145 */
4146 if (sizeCache == 0) {
4147 sizeCache = 10;
4148 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4149 sizeof(xmlNsPtr));
4150 if (oldNs == NULL) {
4151 xmlGenericError(xmlGenericErrorContext,
4152 "xmlReconciliateNs : memory pbm\n");
4153 return(-1);
4154 }
4155 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4156 sizeof(xmlNsPtr));
4157 if (newNs == NULL) {
4158 xmlGenericError(xmlGenericErrorContext,
4159 "xmlReconciliateNs : memory pbm\n");
4160 xmlFree(oldNs);
4161 return(-1);
4162 }
4163 }
4164 for (i = 0;i < nbCache;i++) {
4165 if (oldNs[i] == attr->ns) {
4166 node->ns = newNs[i];
4167 break;
4168 }
4169 }
4170 if (i == nbCache) {
4171 /*
4172 * Ok we need to recreate a new namespace definition
4173 */
4174 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4175 if (n != NULL) { /* :-( what if else ??? */
4176 /*
4177 * check if we need to grow the cache buffers.
4178 */
4179 if (sizeCache <= nbCache) {
4180 sizeCache *= 2;
4181 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4182 sizeof(xmlNsPtr));
4183 if (oldNs == NULL) {
4184 xmlGenericError(xmlGenericErrorContext,
4185 "xmlReconciliateNs : memory pbm\n");
4186 xmlFree(newNs);
4187 return(-1);
4188 }
4189 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4190 sizeof(xmlNsPtr));
4191 if (newNs == NULL) {
4192 xmlGenericError(xmlGenericErrorContext,
4193 "xmlReconciliateNs : memory pbm\n");
4194 xmlFree(oldNs);
4195 return(-1);
4196 }
4197 }
4198 newNs[nbCache] = n;
4199 oldNs[nbCache++] = attr->ns;
4200 attr->ns = n;
4201 }
4202 }
4203 }
4204 attr = attr->next;
4205 }
4206
4207 /*
4208 * Browse the full subtree, deep first
4209 */
4210 if (node->children != NULL) {
4211 /* deep first */
4212 node = node->children;
4213 } else if ((node != tree) && (node->next != NULL)) {
4214 /* then siblings */
4215 node = node->next;
4216 } else if (node != tree) {
4217 /* go up to parents->next if needed */
4218 while (node != tree) {
4219 if (node->parent != NULL)
4220 node = node->parent;
4221 if ((node != tree) && (node->next != NULL)) {
4222 node = node->next;
4223 break;
4224 }
4225 if (node->parent == NULL) {
4226 node = NULL;
4227 break;
4228 }
4229 }
4230 /* exit condition */
4231 if (node == tree)
4232 node = NULL;
4233 }
4234 }
4235 return(ret);
4236}
4237
4238/**
4239 * xmlHasProp:
4240 * @node: the node
4241 * @name: the attribute name
4242 *
4243 * Search an attribute associated to a node
4244 * This function also looks in DTD attribute declaration for #FIXED or
4245 * default declaration values unless DTD use has been turned off.
4246 *
4247 * Returns the attribute or the attribute declaration or NULL if
4248 * neither was found.
4249 */
4250xmlAttrPtr
4251xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4252 xmlAttrPtr prop;
4253 xmlDocPtr doc;
4254
4255 if ((node == NULL) || (name == NULL)) return(NULL);
4256 /*
4257 * Check on the properties attached to the node
4258 */
4259 prop = node->properties;
4260 while (prop != NULL) {
4261 if (xmlStrEqual(prop->name, name)) {
4262 return(prop);
4263 }
4264 prop = prop->next;
4265 }
4266 if (!xmlCheckDTD) return(NULL);
4267
4268 /*
4269 * Check if there is a default declaration in the internal
4270 * or external subsets
4271 */
4272 doc = node->doc;
4273 if (doc != NULL) {
4274 xmlAttributePtr attrDecl;
4275 if (doc->intSubset != NULL) {
4276 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4277 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4278 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4279 if (attrDecl != NULL)
4280 return((xmlAttrPtr) attrDecl);
4281 }
4282 }
4283 return(NULL);
4284}
4285
4286/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004287 * xmlHasNsProp:
4288 * @node: the node
4289 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004290 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004291 *
4292 * Search for an attribute associated to a node
4293 * This attribute has to be anchored in the namespace specified.
4294 * This does the entity substitution.
4295 * This function looks in DTD attribute declaration for #FIXED or
4296 * default declaration values unless DTD use has been turned off.
4297 *
4298 * Returns the attribute or the attribute declaration or NULL
4299 * if neither was found.
4300 */
4301xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004302xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004303 xmlAttrPtr prop;
4304 xmlDocPtr doc;
4305 xmlNsPtr ns;
4306
4307 if (node == NULL)
4308 return(NULL);
4309
4310 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004311 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004312 return(xmlHasProp(node, name));
4313 while (prop != NULL) {
4314 /*
4315 * One need to have
4316 * - same attribute names
4317 * - and the attribute carrying that namespace
4318 * or
4319 * no namespace on the attribute and the element carrying it
4320 */
4321 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004322 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4323 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004324 }
4325 prop = prop->next;
4326 }
4327 if (!xmlCheckDTD) return(NULL);
4328
4329 /*
4330 * Check if there is a default declaration in the internal
4331 * or external subsets
4332 */
4333 doc = node->doc;
4334 if (doc != NULL) {
4335 if (doc->intSubset != NULL) {
4336 xmlAttributePtr attrDecl;
4337
4338 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4339 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4340 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4341
4342 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4343 /*
4344 * The DTD declaration only allows a prefix search
4345 */
4346 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004347 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004348 return((xmlAttrPtr) attrDecl);
4349 }
4350 }
4351 }
4352 return(NULL);
4353}
4354
4355/**
Owen Taylor3473f882001-02-23 17:55:21 +00004356 * xmlGetProp:
4357 * @node: the node
4358 * @name: the attribute name
4359 *
4360 * Search and get the value of an attribute associated to a node
4361 * This does the entity substitution.
4362 * This function looks in DTD attribute declaration for #FIXED or
4363 * default declaration values unless DTD use has been turned off.
4364 *
4365 * Returns the attribute value or NULL if not found.
4366 * It's up to the caller to free the memory.
4367 */
4368xmlChar *
4369xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4370 xmlAttrPtr prop;
4371 xmlDocPtr doc;
4372
4373 if ((node == NULL) || (name == NULL)) return(NULL);
4374 /*
4375 * Check on the properties attached to the node
4376 */
4377 prop = node->properties;
4378 while (prop != NULL) {
4379 if (xmlStrEqual(prop->name, name)) {
4380 xmlChar *ret;
4381
4382 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4383 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4384 return(ret);
4385 }
4386 prop = prop->next;
4387 }
4388 if (!xmlCheckDTD) return(NULL);
4389
4390 /*
4391 * Check if there is a default declaration in the internal
4392 * or external subsets
4393 */
4394 doc = node->doc;
4395 if (doc != NULL) {
4396 xmlAttributePtr attrDecl;
4397 if (doc->intSubset != NULL) {
4398 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4399 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4400 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4401 if (attrDecl != NULL)
4402 return(xmlStrdup(attrDecl->defaultValue));
4403 }
4404 }
4405 return(NULL);
4406}
4407
4408/**
4409 * xmlGetNsProp:
4410 * @node: the node
4411 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004412 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004413 *
4414 * Search and get the value of an attribute associated to a node
4415 * This attribute has to be anchored in the namespace specified.
4416 * This does the entity substitution.
4417 * This function looks in DTD attribute declaration for #FIXED or
4418 * default declaration values unless DTD use has been turned off.
4419 *
4420 * Returns the attribute value or NULL if not found.
4421 * It's up to the caller to free the memory.
4422 */
4423xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004424xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004425 xmlAttrPtr prop;
4426 xmlDocPtr doc;
4427 xmlNsPtr ns;
4428
4429 if (node == NULL)
4430 return(NULL);
4431
4432 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004433 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004434 return(xmlGetProp(node, name));
4435 while (prop != NULL) {
4436 /*
4437 * One need to have
4438 * - same attribute names
4439 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004440 */
4441 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004442 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004443 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004444 xmlChar *ret;
4445
4446 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4447 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4448 return(ret);
4449 }
4450 prop = prop->next;
4451 }
4452 if (!xmlCheckDTD) return(NULL);
4453
4454 /*
4455 * Check if there is a default declaration in the internal
4456 * or external subsets
4457 */
4458 doc = node->doc;
4459 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004460 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004461 xmlAttributePtr attrDecl;
4462
Owen Taylor3473f882001-02-23 17:55:21 +00004463 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4464 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4465 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4466
4467 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4468 /*
4469 * The DTD declaration only allows a prefix search
4470 */
4471 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004472 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004473 return(xmlStrdup(attrDecl->defaultValue));
4474 }
4475 }
4476 }
4477 return(NULL);
4478}
4479
4480/**
4481 * xmlSetProp:
4482 * @node: the node
4483 * @name: the attribute name
4484 * @value: the attribute value
4485 *
4486 * Set (or reset) an attribute carried by a node.
4487 * Returns the attribute pointer.
4488 */
4489xmlAttrPtr
4490xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
4491 xmlAttrPtr prop = node->properties;
4492 xmlDocPtr doc = NULL;
4493
4494 if ((node == NULL) || (name == NULL))
4495 return(NULL);
4496 doc = node->doc;
4497 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004498 if ((xmlStrEqual(prop->name, name)) &&
4499 (prop->ns == NULL)){
Owen Taylor3473f882001-02-23 17:55:21 +00004500 if (prop->children != NULL)
4501 xmlFreeNodeList(prop->children);
4502 prop->children = NULL;
4503 prop->last = NULL;
4504 if (value != NULL) {
4505 xmlChar *buffer;
4506 xmlNodePtr tmp;
4507
4508 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4509 prop->children = xmlStringGetNodeList(node->doc, buffer);
4510 prop->last = NULL;
4511 prop->doc = doc;
4512 tmp = prop->children;
4513 while (tmp != NULL) {
4514 tmp->parent = (xmlNodePtr) prop;
4515 tmp->doc = doc;
4516 if (tmp->next == NULL)
4517 prop->last = tmp;
4518 tmp = tmp->next;
4519 }
4520 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004521 }
Owen Taylor3473f882001-02-23 17:55:21 +00004522 return(prop);
4523 }
4524 prop = prop->next;
4525 }
4526 prop = xmlNewProp(node, name, value);
4527 return(prop);
4528}
4529
4530/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004531 * xmlUnsetProp:
4532 * @node: the node
4533 * @name: the attribute name
4534 *
4535 * Remove an attribute carried by a node.
4536 * Returns 0 if successful, -1 if not found
4537 */
4538int
4539xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4540 xmlAttrPtr prop = node->properties, prev = NULL;;
4541
4542 if ((node == NULL) || (name == NULL))
4543 return(-1);
4544 while (prop != NULL) {
4545 if ((xmlStrEqual(prop->name, name)) &&
4546 (prop->ns == NULL)) {
4547 if (prev == NULL)
4548 node->properties = prop->next;
4549 else
4550 prev->next = prop->next;
4551 xmlFreeProp(prop);
4552 return(0);
4553 }
4554 prev = prop;
4555 prop = prop->next;
4556 }
4557 return(-1);
4558}
4559
4560/**
Owen Taylor3473f882001-02-23 17:55:21 +00004561 * xmlSetNsProp:
4562 * @node: the node
4563 * @ns: the namespace definition
4564 * @name: the attribute name
4565 * @value: the attribute value
4566 *
4567 * Set (or reset) an attribute carried by a node.
4568 * The ns structure must be in scope, this is not checked.
4569 *
4570 * Returns the attribute pointer.
4571 */
4572xmlAttrPtr
4573xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4574 const xmlChar *value) {
4575 xmlAttrPtr prop;
4576
4577 if ((node == NULL) || (name == NULL))
4578 return(NULL);
4579
4580 if (ns == NULL)
4581 return(xmlSetProp(node, name, value));
4582 if (ns->href == NULL)
4583 return(NULL);
4584 prop = node->properties;
4585
4586 while (prop != NULL) {
4587 /*
4588 * One need to have
4589 * - same attribute names
4590 * - and the attribute carrying that namespace
4591 * or
4592 * no namespace on the attribute and the element carrying it
4593 */
4594 if ((xmlStrEqual(prop->name, name)) &&
4595 (((prop->ns == NULL) && (node->ns != NULL) &&
4596 (xmlStrEqual(node->ns->href, ns->href))) ||
4597 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4598 if (prop->children != NULL)
4599 xmlFreeNodeList(prop->children);
4600 prop->children = NULL;
4601 prop->last = NULL;
4602 prop->ns = ns;
4603 if (value != NULL) {
4604 xmlChar *buffer;
4605 xmlNodePtr tmp;
4606
4607 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4608 prop->children = xmlStringGetNodeList(node->doc, buffer);
4609 prop->last = NULL;
4610 tmp = prop->children;
4611 while (tmp != NULL) {
4612 tmp->parent = (xmlNodePtr) prop;
4613 if (tmp->next == NULL)
4614 prop->last = tmp;
4615 tmp = tmp->next;
4616 }
4617 xmlFree(buffer);
4618 }
4619 return(prop);
4620 }
4621 prop = prop->next;
4622 }
4623 prop = xmlNewNsProp(node, ns, name, value);
4624 return(prop);
4625}
4626
4627/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004628 * xmlUnsetNsProp:
4629 * @node: the node
4630 * @ns: the namespace definition
4631 * @name: the attribute name
4632 *
4633 * Remove an attribute carried by a node.
4634 * Returns 0 if successful, -1 if not found
4635 */
4636int
4637xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4638 xmlAttrPtr prop = node->properties, prev = NULL;;
4639
4640 if ((node == NULL) || (name == NULL))
4641 return(-1);
4642 if (ns == NULL)
4643 return(xmlUnsetProp(node, name));
4644 if (ns->href == NULL)
4645 return(-1);
4646 while (prop != NULL) {
4647 if ((xmlStrEqual(prop->name, name)) &&
4648 (((prop->ns == NULL) && (node->ns != NULL) &&
4649 (xmlStrEqual(node->ns->href, ns->href))) ||
4650 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4651 if (prev == NULL)
4652 node->properties = prop->next;
4653 else
4654 prev->next = prop->next;
4655 xmlFreeProp(prop);
4656 return(0);
4657 }
4658 prev = prop;
4659 prop = prop->next;
4660 }
4661 return(-1);
4662}
4663
4664/**
Owen Taylor3473f882001-02-23 17:55:21 +00004665 * xmlNodeIsText:
4666 * @node: the node
4667 *
4668 * Is this node a Text node ?
4669 * Returns 1 yes, 0 no
4670 */
4671int
4672xmlNodeIsText(xmlNodePtr node) {
4673 if (node == NULL) return(0);
4674
4675 if (node->type == XML_TEXT_NODE) return(1);
4676 return(0);
4677}
4678
4679/**
4680 * xmlIsBlankNode:
4681 * @node: the node
4682 *
4683 * Checks whether this node is an empty or whitespace only
4684 * (and possibly ignorable) text-node.
4685 *
4686 * Returns 1 yes, 0 no
4687 */
4688int
4689xmlIsBlankNode(xmlNodePtr node) {
4690 const xmlChar *cur;
4691 if (node == NULL) return(0);
4692
Daniel Veillard7db37732001-07-12 01:20:08 +00004693 if ((node->type != XML_TEXT_NODE) &&
4694 (node->type != XML_CDATA_SECTION_NODE))
4695 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004696 if (node->content == NULL) return(1);
4697#ifndef XML_USE_BUFFER_CONTENT
4698 cur = node->content;
4699#else
4700 cur = xmlBufferContent(node->content);
4701#endif
4702 while (*cur != 0) {
4703 if (!IS_BLANK(*cur)) return(0);
4704 cur++;
4705 }
4706
4707 return(1);
4708}
4709
4710/**
4711 * xmlTextConcat:
4712 * @node: the node
4713 * @content: the content
4714 * @len: @content lenght
4715 *
4716 * Concat the given string at the end of the existing node content
4717 */
4718
4719void
4720xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4721 if (node == NULL) return;
4722
4723 if ((node->type != XML_TEXT_NODE) &&
4724 (node->type != XML_CDATA_SECTION_NODE)) {
4725#ifdef DEBUG_TREE
4726 xmlGenericError(xmlGenericErrorContext,
4727 "xmlTextConcat: node is not text nor cdata\n");
4728#endif
4729 return;
4730 }
4731#ifndef XML_USE_BUFFER_CONTENT
4732 node->content = xmlStrncat(node->content, content, len);
4733#else
4734 xmlBufferAdd(node->content, content, len);
4735#endif
4736}
4737
4738/************************************************************************
4739 * *
4740 * Output : to a FILE or in memory *
4741 * *
4742 ************************************************************************/
4743
4744#define BASE_BUFFER_SIZE 4000
4745
Daniel Veillarde356c282001-03-10 12:32:04 +00004746int xmlDefaultBufferSize = BASE_BUFFER_SIZE;
4747
Owen Taylor3473f882001-02-23 17:55:21 +00004748/**
4749 * xmlBufferCreate:
4750 *
4751 * routine to create an XML buffer.
4752 * returns the new structure.
4753 */
4754xmlBufferPtr
4755xmlBufferCreate(void) {
4756 xmlBufferPtr ret;
4757
4758 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4759 if (ret == NULL) {
4760 xmlGenericError(xmlGenericErrorContext,
4761 "xmlBufferCreate : out of memory!\n");
4762 return(NULL);
4763 }
4764 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004765 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004766 ret->alloc = xmlBufferAllocScheme;
4767 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4768 if (ret->content == NULL) {
4769 xmlGenericError(xmlGenericErrorContext,
4770 "xmlBufferCreate : out of memory!\n");
4771 xmlFree(ret);
4772 return(NULL);
4773 }
4774 ret->content[0] = 0;
4775 return(ret);
4776}
4777
4778/**
4779 * xmlBufferCreateSize:
4780 * @size: initial size of buffer
4781 *
4782 * routine to create an XML buffer.
4783 * returns the new structure.
4784 */
4785xmlBufferPtr
4786xmlBufferCreateSize(size_t size) {
4787 xmlBufferPtr ret;
4788
4789 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4790 if (ret == NULL) {
4791 xmlGenericError(xmlGenericErrorContext,
4792 "xmlBufferCreate : out of memory!\n");
4793 return(NULL);
4794 }
4795 ret->use = 0;
4796 ret->alloc = xmlBufferAllocScheme;
4797 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4798 if (ret->size){
4799 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4800 if (ret->content == NULL) {
4801 xmlGenericError(xmlGenericErrorContext,
4802 "xmlBufferCreate : out of memory!\n");
4803 xmlFree(ret);
4804 return(NULL);
4805 }
4806 ret->content[0] = 0;
4807 } else
4808 ret->content = NULL;
4809 return(ret);
4810}
4811
4812/**
4813 * xmlBufferSetAllocationScheme:
4814 * @buf: the buffer to free
4815 * @scheme: allocation scheme to use
4816 *
4817 * Sets the allocation scheme for this buffer
4818 */
4819void
4820xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4821 xmlBufferAllocationScheme scheme) {
4822 if (buf == NULL) {
4823#ifdef DEBUG_BUFFER
4824 xmlGenericError(xmlGenericErrorContext,
4825 "xmlBufferSetAllocationScheme: buf == NULL\n");
4826#endif
4827 return;
4828 }
4829
4830 buf->alloc = scheme;
4831}
4832
4833/**
4834 * xmlBufferFree:
4835 * @buf: the buffer to free
4836 *
4837 * Frees an XML buffer.
4838 */
4839void
4840xmlBufferFree(xmlBufferPtr buf) {
4841 if (buf == NULL) {
4842#ifdef DEBUG_BUFFER
4843 xmlGenericError(xmlGenericErrorContext,
4844 "xmlBufferFree: buf == NULL\n");
4845#endif
4846 return;
4847 }
4848 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004849 xmlFree(buf->content);
4850 }
Owen Taylor3473f882001-02-23 17:55:21 +00004851 xmlFree(buf);
4852}
4853
4854/**
4855 * xmlBufferEmpty:
4856 * @buf: the buffer
4857 *
4858 * empty a buffer.
4859 */
4860void
4861xmlBufferEmpty(xmlBufferPtr buf) {
4862 if (buf->content == NULL) return;
4863 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004864 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00004865}
4866
4867/**
4868 * xmlBufferShrink:
4869 * @buf: the buffer to dump
4870 * @len: the number of xmlChar to remove
4871 *
4872 * Remove the beginning of an XML buffer.
4873 *
4874 * Returns the number of xmlChar removed, or -1 in case of failure.
4875 */
4876int
4877xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
4878 if (len == 0) return(0);
4879 if (len > buf->use) return(-1);
4880
4881 buf->use -= len;
4882 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
4883
4884 buf->content[buf->use] = 0;
4885 return(len);
4886}
4887
4888/**
4889 * xmlBufferGrow:
4890 * @buf: the buffer
4891 * @len: the minimum free size to allocate
4892 *
4893 * Grow the available space of an XML buffer.
4894 *
4895 * Returns the new available space or -1 in case of error
4896 */
4897int
4898xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
4899 int size;
4900 xmlChar *newbuf;
4901
4902 if (len + buf->use < buf->size) return(0);
4903
4904 size = buf->use + len + 100;
4905
4906 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
4907 if (newbuf == NULL) return(-1);
4908 buf->content = newbuf;
4909 buf->size = size;
4910 return(buf->size - buf->use);
4911}
4912
4913/**
4914 * xmlBufferDump:
4915 * @file: the file output
4916 * @buf: the buffer to dump
4917 *
4918 * Dumps an XML buffer to a FILE *.
4919 * Returns the number of xmlChar written
4920 */
4921int
4922xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4923 int ret;
4924
4925 if (buf == NULL) {
4926#ifdef DEBUG_BUFFER
4927 xmlGenericError(xmlGenericErrorContext,
4928 "xmlBufferDump: buf == NULL\n");
4929#endif
4930 return(0);
4931 }
4932 if (buf->content == NULL) {
4933#ifdef DEBUG_BUFFER
4934 xmlGenericError(xmlGenericErrorContext,
4935 "xmlBufferDump: buf->content == NULL\n");
4936#endif
4937 return(0);
4938 }
4939 if (file == NULL) file = stdout;
4940 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
4941 return(ret);
4942}
4943
4944/**
4945 * xmlBufferContent:
4946 * @buf: the buffer
4947 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004948 * Function to extract the content of a buffer
4949 *
Owen Taylor3473f882001-02-23 17:55:21 +00004950 * Returns the internal content
4951 */
4952
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004953const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00004954xmlBufferContent(const xmlBufferPtr buf)
4955{
4956 if(!buf)
4957 return NULL;
4958
4959 return buf->content;
4960}
4961
4962/**
4963 * xmlBufferLength:
4964 * @buf: the buffer
4965 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004966 * Function to get the length of a buffer
4967 *
Owen Taylor3473f882001-02-23 17:55:21 +00004968 * Returns the length of data in the internal content
4969 */
4970
4971int
4972xmlBufferLength(const xmlBufferPtr buf)
4973{
4974 if(!buf)
4975 return 0;
4976
4977 return buf->use;
4978}
4979
4980/**
4981 * xmlBufferResize:
4982 * @buf: the buffer to resize
4983 * @size: the desired size
4984 *
4985 * Resize a buffer to accomodate minimum size of @size.
4986 *
4987 * Returns 0 in case of problems, 1 otherwise
4988 */
4989int
4990xmlBufferResize(xmlBufferPtr buf, unsigned int size)
4991{
4992 unsigned int newSize;
4993 xmlChar* rebuf = NULL;
4994
4995 /*take care of empty case*/
4996 newSize = (buf->size ? buf->size*2 : size);
4997
4998 /* Don't resize if we don't have to */
4999 if (size < buf->size)
5000 return 1;
5001
5002 /* figure out new size */
5003 switch (buf->alloc){
5004 case XML_BUFFER_ALLOC_DOUBLEIT:
5005 while (size > newSize) newSize *= 2;
5006 break;
5007 case XML_BUFFER_ALLOC_EXACT:
5008 newSize = size+10;
5009 break;
5010 default:
5011 newSize = size+10;
5012 break;
5013 }
5014
5015 if (buf->content == NULL)
5016 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5017 else
5018 rebuf = (xmlChar *) xmlRealloc(buf->content,
5019 newSize * sizeof(xmlChar));
5020 if (rebuf == NULL) {
5021 xmlGenericError(xmlGenericErrorContext,
5022 "xmlBufferAdd : out of memory!\n");
5023 return 0;
5024 }
5025 buf->content = rebuf;
5026 buf->size = newSize;
5027
5028 return 1;
5029}
5030
5031/**
5032 * xmlBufferAdd:
5033 * @buf: the buffer to dump
5034 * @str: the xmlChar string
5035 * @len: the number of xmlChar to add
5036 *
5037 * Add a string range to an XML buffer. if len == -1, the lenght of
5038 * str is recomputed.
5039 */
5040void
5041xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5042 unsigned int needSize;
5043
5044 if (str == NULL) {
5045#ifdef DEBUG_BUFFER
5046 xmlGenericError(xmlGenericErrorContext,
5047 "xmlBufferAdd: str == NULL\n");
5048#endif
5049 return;
5050 }
5051 if (len < -1) {
5052#ifdef DEBUG_BUFFER
5053 xmlGenericError(xmlGenericErrorContext,
5054 "xmlBufferAdd: len < 0\n");
5055#endif
5056 return;
5057 }
5058 if (len == 0) return;
5059
5060 if (len < 0)
5061 len = xmlStrlen(str);
5062
5063 if (len <= 0) return;
5064
5065 needSize = buf->use + len + 2;
5066 if (needSize > buf->size){
5067 if (!xmlBufferResize(buf, needSize)){
5068 xmlGenericError(xmlGenericErrorContext,
5069 "xmlBufferAdd : out of memory!\n");
5070 return;
5071 }
5072 }
5073
5074 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5075 buf->use += len;
5076 buf->content[buf->use] = 0;
5077}
5078
5079/**
5080 * xmlBufferAddHead:
5081 * @buf: the buffer
5082 * @str: the xmlChar string
5083 * @len: the number of xmlChar to add
5084 *
5085 * Add a string range to the beginning of an XML buffer.
5086 * if len == -1, the lenght of @str is recomputed.
5087 */
5088void
5089xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5090 unsigned int needSize;
5091
5092 if (str == NULL) {
5093#ifdef DEBUG_BUFFER
5094 xmlGenericError(xmlGenericErrorContext,
5095 "xmlBufferAdd: str == NULL\n");
5096#endif
5097 return;
5098 }
5099 if (len < -1) {
5100#ifdef DEBUG_BUFFER
5101 xmlGenericError(xmlGenericErrorContext,
5102 "xmlBufferAdd: len < 0\n");
5103#endif
5104 return;
5105 }
5106 if (len == 0) return;
5107
5108 if (len < 0)
5109 len = xmlStrlen(str);
5110
5111 if (len <= 0) return;
5112
5113 needSize = buf->use + len + 2;
5114 if (needSize > buf->size){
5115 if (!xmlBufferResize(buf, needSize)){
5116 xmlGenericError(xmlGenericErrorContext,
5117 "xmlBufferAddHead : out of memory!\n");
5118 return;
5119 }
5120 }
5121
5122 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5123 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5124 buf->use += len;
5125 buf->content[buf->use] = 0;
5126}
5127
5128/**
5129 * xmlBufferCat:
5130 * @buf: the buffer to dump
5131 * @str: the xmlChar string
5132 *
5133 * Append a zero terminated string to an XML buffer.
5134 */
5135void
5136xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5137 if (str != NULL)
5138 xmlBufferAdd(buf, str, -1);
5139}
5140
5141/**
5142 * xmlBufferCCat:
5143 * @buf: the buffer to dump
5144 * @str: the C char string
5145 *
5146 * Append a zero terminated C string to an XML buffer.
5147 */
5148void
5149xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5150 const char *cur;
5151
5152 if (str == NULL) {
5153#ifdef DEBUG_BUFFER
5154 xmlGenericError(xmlGenericErrorContext,
5155 "xmlBufferAdd: str == NULL\n");
5156#endif
5157 return;
5158 }
5159 for (cur = str;*cur != 0;cur++) {
5160 if (buf->use + 10 >= buf->size) {
5161 if (!xmlBufferResize(buf, buf->use+10)){
5162 xmlGenericError(xmlGenericErrorContext,
5163 "xmlBufferCCat : out of memory!\n");
5164 return;
5165 }
5166 }
5167 buf->content[buf->use++] = *cur;
5168 }
5169 buf->content[buf->use] = 0;
5170}
5171
5172/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005173 * xmlBufferWriteXmlCHAR:
5174 * @buf: the XML buffer
5175 * @string: the string to add
5176 *
5177 * For VMS only.
5178 * routine which manages and grows an output buffer. This one adds
5179 * xmlChars at the end of the buffer.
5180 */
5181/**
Owen Taylor3473f882001-02-23 17:55:21 +00005182 * xmlBufferWriteCHAR:
5183 * @buf: the XML buffer
5184 * @string: the string to add
5185 *
5186 * routine which manages and grows an output buffer. This one adds
5187 * xmlChars at the end of the buffer.
5188 */
5189void
5190#ifdef VMS
5191xmlBufferWriteXmlCHAR
5192#else
5193xmlBufferWriteCHAR
5194#endif
5195(xmlBufferPtr buf, const xmlChar *string) {
5196 xmlBufferCat(buf, string);
5197}
5198
5199/**
5200 * xmlBufferWriteChar:
5201 * @buf: the XML buffer output
5202 * @string: the string to add
5203 *
5204 * routine which manage and grows an output buffer. This one add
5205 * C chars at the end of the array.
5206 */
5207void
5208xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5209 xmlBufferCCat(buf, string);
5210}
5211
5212
5213/**
5214 * xmlBufferWriteQuotedString:
5215 * @buf: the XML buffer output
5216 * @string: the string to add
5217 *
5218 * routine which manage and grows an output buffer. This one writes
5219 * a quoted or double quoted xmlChar string, checking first if it holds
5220 * quote or double-quotes internally
5221 */
5222void
5223xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5224 if (xmlStrchr(string, '"')) {
5225 if (xmlStrchr(string, '\'')) {
5226#ifdef DEBUG_BUFFER
5227 xmlGenericError(xmlGenericErrorContext,
5228 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5229#endif
5230 }
5231 xmlBufferCCat(buf, "'");
5232 xmlBufferCat(buf, string);
5233 xmlBufferCCat(buf, "'");
5234 } else {
5235 xmlBufferCCat(buf, "\"");
5236 xmlBufferCat(buf, string);
5237 xmlBufferCCat(buf, "\"");
5238 }
5239}
5240
5241
5242/************************************************************************
5243 * *
5244 * Dumping XML tree content to a simple buffer *
5245 * *
5246 ************************************************************************/
5247
5248void
5249xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5250 int format);
5251static void
5252xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5253 int format);
5254void
5255htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5256
5257/**
5258 * xmlNsDump:
5259 * @buf: the XML buffer output
5260 * @cur: a namespace
5261 *
5262 * Dump a local Namespace definition.
5263 * Should be called in the context of attributes dumps.
5264 */
5265static void
5266xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5267 if (cur == NULL) {
5268#ifdef DEBUG_TREE
5269 xmlGenericError(xmlGenericErrorContext,
5270 "xmlNsDump : Ns == NULL\n");
5271#endif
5272 return;
5273 }
5274 if (cur->type == XML_LOCAL_NAMESPACE) {
5275 /* Within the context of an element attributes */
5276 if (cur->prefix != NULL) {
5277 xmlBufferWriteChar(buf, " xmlns:");
5278 xmlBufferWriteCHAR(buf, cur->prefix);
5279 } else
5280 xmlBufferWriteChar(buf, " xmlns");
5281 xmlBufferWriteChar(buf, "=");
5282 xmlBufferWriteQuotedString(buf, cur->href);
5283 }
5284}
5285
5286/**
5287 * xmlNsListDump:
5288 * @buf: the XML buffer output
5289 * @cur: the first namespace
5290 *
5291 * Dump a list of local Namespace definitions.
5292 * Should be called in the context of attributes dumps.
5293 */
5294static void
5295xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5296 while (cur != NULL) {
5297 xmlNsDump(buf, cur);
5298 cur = cur->next;
5299 }
5300}
5301
5302/**
5303 * xmlDtdDump:
5304 * @buf: the XML buffer output
5305 * @doc: the document
5306 *
5307 * Dump the XML document DTD, if any.
5308 */
5309static void
5310xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5311 if (dtd == NULL) {
5312#ifdef DEBUG_TREE
5313 xmlGenericError(xmlGenericErrorContext,
5314 "xmlDtdDump : no internal subset\n");
5315#endif
5316 return;
5317 }
5318 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5319 xmlBufferWriteCHAR(buf, dtd->name);
5320 if (dtd->ExternalID != NULL) {
5321 xmlBufferWriteChar(buf, " PUBLIC ");
5322 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5323 xmlBufferWriteChar(buf, " ");
5324 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5325 } else if (dtd->SystemID != NULL) {
5326 xmlBufferWriteChar(buf, " SYSTEM ");
5327 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5328 }
5329 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5330 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5331 xmlBufferWriteChar(buf, ">");
5332 return;
5333 }
5334 xmlBufferWriteChar(buf, " [\n");
5335 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5336#if 0
5337 if (dtd->entities != NULL)
5338 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5339 if (dtd->notations != NULL)
5340 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5341 if (dtd->elements != NULL)
5342 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5343 if (dtd->attributes != NULL)
5344 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5345#endif
5346 xmlBufferWriteChar(buf, "]>");
5347}
5348
5349/**
5350 * xmlAttrDump:
5351 * @buf: the XML buffer output
5352 * @doc: the document
5353 * @cur: the attribute pointer
5354 *
5355 * Dump an XML attribute
5356 */
5357static void
5358xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5359 xmlChar *value;
5360
5361 if (cur == NULL) {
5362#ifdef DEBUG_TREE
5363 xmlGenericError(xmlGenericErrorContext,
5364 "xmlAttrDump : property == NULL\n");
5365#endif
5366 return;
5367 }
5368 xmlBufferWriteChar(buf, " ");
5369 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5370 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5371 xmlBufferWriteChar(buf, ":");
5372 }
5373 xmlBufferWriteCHAR(buf, cur->name);
5374 value = xmlNodeListGetString(doc, cur->children, 0);
5375 if (value != NULL) {
5376 xmlBufferWriteChar(buf, "=");
5377 xmlBufferWriteQuotedString(buf, value);
5378 xmlFree(value);
5379 } else {
5380 xmlBufferWriteChar(buf, "=\"\"");
5381 }
5382}
5383
5384/**
5385 * xmlAttrListDump:
5386 * @buf: the XML buffer output
5387 * @doc: the document
5388 * @cur: the first attribute pointer
5389 *
5390 * Dump a list of XML attributes
5391 */
5392static void
5393xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5394 if (cur == NULL) {
5395#ifdef DEBUG_TREE
5396 xmlGenericError(xmlGenericErrorContext,
5397 "xmlAttrListDump : property == NULL\n");
5398#endif
5399 return;
5400 }
5401 while (cur != NULL) {
5402 xmlAttrDump(buf, doc, cur);
5403 cur = cur->next;
5404 }
5405}
5406
5407
5408
5409/**
5410 * xmlNodeListDump:
5411 * @buf: the XML buffer output
5412 * @doc: the document
5413 * @cur: the first node
5414 * @level: the imbrication level for indenting
5415 * @format: is formatting allowed
5416 *
5417 * Dump an XML node list, recursive behaviour,children are printed too.
5418 */
5419static void
5420xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5421 int format) {
5422 int i;
5423
5424 if (cur == NULL) {
5425#ifdef DEBUG_TREE
5426 xmlGenericError(xmlGenericErrorContext,
5427 "xmlNodeListDump : node == NULL\n");
5428#endif
5429 return;
5430 }
5431 while (cur != NULL) {
5432 if ((format) && (xmlIndentTreeOutput) &&
5433 (cur->type == XML_ELEMENT_NODE))
5434 for (i = 0;i < level;i++)
5435 xmlBufferWriteChar(buf, " ");
5436 xmlNodeDump(buf, doc, cur, level, format);
5437 if (format) {
5438 xmlBufferWriteChar(buf, "\n");
5439 }
5440 cur = cur->next;
5441 }
5442}
5443
5444/**
5445 * xmlNodeDump:
5446 * @buf: the XML buffer output
5447 * @doc: the document
5448 * @cur: the current node
5449 * @level: the imbrication level for indenting
5450 * @format: is formatting allowed
5451 *
5452 * Dump an XML node, recursive behaviour,children are printed too.
5453 */
5454void
5455xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5456 int format) {
5457 int i;
5458 xmlNodePtr tmp;
5459
5460 if (cur == NULL) {
5461#ifdef DEBUG_TREE
5462 xmlGenericError(xmlGenericErrorContext,
5463 "xmlNodeDump : node == NULL\n");
5464#endif
5465 return;
5466 }
5467 if (cur->type == XML_XINCLUDE_START)
5468 return;
5469 if (cur->type == XML_XINCLUDE_END)
5470 return;
5471 if (cur->type == XML_DTD_NODE) {
5472 xmlDtdDump(buf, (xmlDtdPtr) cur);
5473 return;
5474 }
5475 if (cur->type == XML_ELEMENT_DECL) {
5476 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5477 return;
5478 }
5479 if (cur->type == XML_ATTRIBUTE_DECL) {
5480 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5481 return;
5482 }
5483 if (cur->type == XML_ENTITY_DECL) {
5484 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5485 return;
5486 }
5487 if (cur->type == XML_TEXT_NODE) {
5488 if (cur->content != NULL) {
5489 if ((cur->name == xmlStringText) ||
5490 (cur->name != xmlStringTextNoenc)) {
5491 xmlChar *buffer;
5492
5493#ifndef XML_USE_BUFFER_CONTENT
5494 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5495#else
5496 buffer = xmlEncodeEntitiesReentrant(doc,
5497 xmlBufferContent(cur->content));
5498#endif
5499 if (buffer != NULL) {
5500 xmlBufferWriteCHAR(buf, buffer);
5501 xmlFree(buffer);
5502 }
5503 } else {
5504 /*
5505 * Disable escaping, needed for XSLT
5506 */
5507#ifndef XML_USE_BUFFER_CONTENT
5508 xmlBufferWriteCHAR(buf, cur->content);
5509#else
5510 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5511#endif
5512 }
5513 }
5514 return;
5515 }
5516 if (cur->type == XML_PI_NODE) {
5517 if (cur->content != NULL) {
5518 xmlBufferWriteChar(buf, "<?");
5519 xmlBufferWriteCHAR(buf, cur->name);
5520 if (cur->content != NULL) {
5521 xmlBufferWriteChar(buf, " ");
5522#ifndef XML_USE_BUFFER_CONTENT
5523 xmlBufferWriteCHAR(buf, cur->content);
5524#else
5525 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5526#endif
5527 }
5528 xmlBufferWriteChar(buf, "?>");
5529 } else {
5530 xmlBufferWriteChar(buf, "<?");
5531 xmlBufferWriteCHAR(buf, cur->name);
5532 xmlBufferWriteChar(buf, "?>");
5533 }
5534 return;
5535 }
5536 if (cur->type == XML_COMMENT_NODE) {
5537 if (cur->content != NULL) {
5538 xmlBufferWriteChar(buf, "<!--");
5539#ifndef XML_USE_BUFFER_CONTENT
5540 xmlBufferWriteCHAR(buf, cur->content);
5541#else
5542 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5543#endif
5544 xmlBufferWriteChar(buf, "-->");
5545 }
5546 return;
5547 }
5548 if (cur->type == XML_ENTITY_REF_NODE) {
5549 xmlBufferWriteChar(buf, "&");
5550 xmlBufferWriteCHAR(buf, cur->name);
5551 xmlBufferWriteChar(buf, ";");
5552 return;
5553 }
5554 if (cur->type == XML_CDATA_SECTION_NODE) {
5555 xmlBufferWriteChar(buf, "<![CDATA[");
5556 if (cur->content != NULL)
5557#ifndef XML_USE_BUFFER_CONTENT
5558 xmlBufferWriteCHAR(buf, cur->content);
5559#else
5560 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5561#endif
5562 xmlBufferWriteChar(buf, "]]>");
5563 return;
5564 }
5565
5566 if (format == 1) {
5567 tmp = cur->children;
5568 while (tmp != NULL) {
5569 if ((tmp->type == XML_TEXT_NODE) ||
5570 (tmp->type == XML_ENTITY_REF_NODE)) {
5571 format = 0;
5572 break;
5573 }
5574 tmp = tmp->next;
5575 }
5576 }
5577 xmlBufferWriteChar(buf, "<");
5578 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5579 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5580 xmlBufferWriteChar(buf, ":");
5581 }
5582
5583 xmlBufferWriteCHAR(buf, cur->name);
5584 if (cur->nsDef)
5585 xmlNsListDump(buf, cur->nsDef);
5586 if (cur->properties != NULL)
5587 xmlAttrListDump(buf, doc, cur->properties);
5588
Daniel Veillard7db37732001-07-12 01:20:08 +00005589 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5590 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005591 (!xmlSaveNoEmptyTags)) {
5592 xmlBufferWriteChar(buf, "/>");
5593 return;
5594 }
5595 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005596 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005597 xmlChar *buffer;
5598
5599#ifndef XML_USE_BUFFER_CONTENT
5600 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5601#else
5602 buffer = xmlEncodeEntitiesReentrant(doc,
5603 xmlBufferContent(cur->content));
5604#endif
5605 if (buffer != NULL) {
5606 xmlBufferWriteCHAR(buf, buffer);
5607 xmlFree(buffer);
5608 }
5609 }
5610 if (cur->children != NULL) {
5611 if (format) xmlBufferWriteChar(buf, "\n");
5612 xmlNodeListDump(buf, doc, cur->children,
5613 (level >= 0?level+1:-1), format);
5614 if ((xmlIndentTreeOutput) && (format))
5615 for (i = 0;i < level;i++)
5616 xmlBufferWriteChar(buf, " ");
5617 }
5618 xmlBufferWriteChar(buf, "</");
5619 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5620 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5621 xmlBufferWriteChar(buf, ":");
5622 }
5623
5624 xmlBufferWriteCHAR(buf, cur->name);
5625 xmlBufferWriteChar(buf, ">");
5626}
5627
5628/**
5629 * xmlElemDump:
5630 * @f: the FILE * for the output
5631 * @doc: the document
5632 * @cur: the current node
5633 *
5634 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5635 */
5636void
5637xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5638 xmlBufferPtr buf;
5639
5640 if (cur == NULL) {
5641#ifdef DEBUG_TREE
5642 xmlGenericError(xmlGenericErrorContext,
5643 "xmlElemDump : cur == NULL\n");
5644#endif
5645 return;
5646 }
Owen Taylor3473f882001-02-23 17:55:21 +00005647#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005648 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005649 xmlGenericError(xmlGenericErrorContext,
5650 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005651 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005652#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005653 buf = xmlBufferCreate();
5654 if (buf == NULL) return;
5655 if ((doc != NULL) &&
5656 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5657#ifdef LIBXML_HTML_ENABLED
5658 htmlNodeDump(buf, doc, cur);
5659#else
5660 xmlGenericError(xmlGenericErrorContext,
5661 "HTML support not compiled in\n");
5662#endif /* LIBXML_HTML_ENABLED */
5663 } else
5664 xmlNodeDump(buf, doc, cur, 0, 1);
5665 xmlBufferDump(f, buf);
5666 xmlBufferFree(buf);
5667}
5668
5669/************************************************************************
5670 * *
5671 * Dumping XML tree content to an I/O output buffer *
5672 * *
5673 ************************************************************************/
5674
5675void
5676xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5677 int level, int format, const char *encoding);
5678static void
5679xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5680 int level, int format, const char *encoding);
5681/**
5682 * xmlNsDumpOutput:
5683 * @buf: the XML buffer output
5684 * @cur: a namespace
5685 *
5686 * Dump a local Namespace definition.
5687 * Should be called in the context of attributes dumps.
5688 */
5689static void
5690xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5691 if (cur == NULL) {
5692#ifdef DEBUG_TREE
5693 xmlGenericError(xmlGenericErrorContext,
5694 "xmlNsDump : Ns == NULL\n");
5695#endif
5696 return;
5697 }
5698 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5699 /* Within the context of an element attributes */
5700 if (cur->prefix != NULL) {
5701 xmlOutputBufferWriteString(buf, " xmlns:");
5702 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5703 } else
5704 xmlOutputBufferWriteString(buf, " xmlns");
5705 xmlOutputBufferWriteString(buf, "=");
5706 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5707 }
5708}
5709
5710/**
5711 * xmlNsListDumpOutput:
5712 * @buf: the XML buffer output
5713 * @cur: the first namespace
5714 *
5715 * Dump a list of local Namespace definitions.
5716 * Should be called in the context of attributes dumps.
5717 */
5718static void
5719xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5720 while (cur != NULL) {
5721 xmlNsDumpOutput(buf, cur);
5722 cur = cur->next;
5723 }
5724}
5725
5726/**
5727 * xmlDtdDumpOutput:
5728 * @buf: the XML buffer output
5729 * @doc: the document
5730 * @encoding: an optional encoding string
5731 *
5732 * Dump the XML document DTD, if any.
5733 */
5734static void
5735xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5736 if (dtd == NULL) {
5737#ifdef DEBUG_TREE
5738 xmlGenericError(xmlGenericErrorContext,
5739 "xmlDtdDump : no internal subset\n");
5740#endif
5741 return;
5742 }
5743 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5744 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5745 if (dtd->ExternalID != NULL) {
5746 xmlOutputBufferWriteString(buf, " PUBLIC ");
5747 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5748 xmlOutputBufferWriteString(buf, " ");
5749 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5750 } else if (dtd->SystemID != NULL) {
5751 xmlOutputBufferWriteString(buf, " SYSTEM ");
5752 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5753 }
5754 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5755 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5756 xmlOutputBufferWriteString(buf, ">");
5757 return;
5758 }
5759 xmlOutputBufferWriteString(buf, " [\n");
5760 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5761 xmlOutputBufferWriteString(buf, "]>");
5762}
5763
5764/**
5765 * xmlAttrDumpOutput:
5766 * @buf: the XML buffer output
5767 * @doc: the document
5768 * @cur: the attribute pointer
5769 * @encoding: an optional encoding string
5770 *
5771 * Dump an XML attribute
5772 */
5773static void
5774xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005775 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005776 xmlChar *value;
5777
5778 if (cur == NULL) {
5779#ifdef DEBUG_TREE
5780 xmlGenericError(xmlGenericErrorContext,
5781 "xmlAttrDump : property == NULL\n");
5782#endif
5783 return;
5784 }
5785 xmlOutputBufferWriteString(buf, " ");
5786 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5787 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5788 xmlOutputBufferWriteString(buf, ":");
5789 }
5790 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5791 value = xmlNodeListGetString(doc, cur->children, 0);
5792 if (value) {
5793 xmlOutputBufferWriteString(buf, "=");
5794 xmlBufferWriteQuotedString(buf->buffer, value);
5795 xmlFree(value);
5796 } else {
5797 xmlOutputBufferWriteString(buf, "=\"\"");
5798 }
5799}
5800
5801/**
5802 * xmlAttrListDumpOutput:
5803 * @buf: the XML buffer output
5804 * @doc: the document
5805 * @cur: the first attribute pointer
5806 * @encoding: an optional encoding string
5807 *
5808 * Dump a list of XML attributes
5809 */
5810static void
5811xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5812 xmlAttrPtr cur, const char *encoding) {
5813 if (cur == NULL) {
5814#ifdef DEBUG_TREE
5815 xmlGenericError(xmlGenericErrorContext,
5816 "xmlAttrListDump : property == NULL\n");
5817#endif
5818 return;
5819 }
5820 while (cur != NULL) {
5821 xmlAttrDumpOutput(buf, doc, cur, encoding);
5822 cur = cur->next;
5823 }
5824}
5825
5826
5827
5828/**
5829 * xmlNodeListDumpOutput:
5830 * @buf: the XML buffer output
5831 * @doc: the document
5832 * @cur: the first node
5833 * @level: the imbrication level for indenting
5834 * @format: is formatting allowed
5835 * @encoding: an optional encoding string
5836 *
5837 * Dump an XML node list, recursive behaviour,children are printed too.
5838 */
5839static void
5840xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5841 xmlNodePtr cur, int level, int format, const char *encoding) {
5842 int i;
5843
5844 if (cur == NULL) {
5845#ifdef DEBUG_TREE
5846 xmlGenericError(xmlGenericErrorContext,
5847 "xmlNodeListDump : node == NULL\n");
5848#endif
5849 return;
5850 }
5851 while (cur != NULL) {
5852 if ((format) && (xmlIndentTreeOutput) &&
5853 (cur->type == XML_ELEMENT_NODE))
5854 for (i = 0;i < level;i++)
5855 xmlOutputBufferWriteString(buf, " ");
5856 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5857 if (format) {
5858 xmlOutputBufferWriteString(buf, "\n");
5859 }
5860 cur = cur->next;
5861 }
5862}
5863
5864/**
5865 * xmlNodeDumpOutput:
5866 * @buf: the XML buffer output
5867 * @doc: the document
5868 * @cur: the current node
5869 * @level: the imbrication level for indenting
5870 * @format: is formatting allowed
5871 * @encoding: an optional encoding string
5872 *
5873 * Dump an XML node, recursive behaviour,children are printed too.
5874 */
5875void
5876xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5877 int level, int format, const char *encoding) {
5878 int i;
5879 xmlNodePtr tmp;
5880
5881 if (cur == NULL) {
5882#ifdef DEBUG_TREE
5883 xmlGenericError(xmlGenericErrorContext,
5884 "xmlNodeDump : node == NULL\n");
5885#endif
5886 return;
5887 }
5888 if (cur->type == XML_XINCLUDE_START)
5889 return;
5890 if (cur->type == XML_XINCLUDE_END)
5891 return;
5892 if (cur->type == XML_DTD_NODE) {
5893 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5894 return;
5895 }
5896 if (cur->type == XML_ELEMENT_DECL) {
5897 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5898 return;
5899 }
5900 if (cur->type == XML_ATTRIBUTE_DECL) {
5901 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5902 return;
5903 }
5904 if (cur->type == XML_ENTITY_DECL) {
5905 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5906 return;
5907 }
5908 if (cur->type == XML_TEXT_NODE) {
5909 if (cur->content != NULL) {
5910 if ((cur->name == xmlStringText) ||
5911 (cur->name != xmlStringTextNoenc)) {
5912 xmlChar *buffer;
5913
5914#ifndef XML_USE_BUFFER_CONTENT
5915 if (encoding == NULL)
5916 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5917 else
5918 buffer = xmlEncodeSpecialChars(doc, cur->content);
5919#else
5920 if (encoding == NULL)
5921 buffer = xmlEncodeEntitiesReentrant(doc,
5922 xmlBufferContent(cur->content));
5923 else
5924 buffer = xmlEncodeSpecialChars(doc,
5925 xmlBufferContent(cur->content));
5926#endif
5927 if (buffer != NULL) {
5928 xmlOutputBufferWriteString(buf, (const char *)buffer);
5929 xmlFree(buffer);
5930 }
5931 } else {
5932 /*
5933 * Disable escaping, needed for XSLT
5934 */
5935#ifndef XML_USE_BUFFER_CONTENT
5936 xmlOutputBufferWriteString(buf, (const char *) cur->content);
5937#else
5938 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5939#endif
5940 }
5941 }
5942
5943 return;
5944 }
5945 if (cur->type == XML_PI_NODE) {
5946 if (cur->content != NULL) {
5947 xmlOutputBufferWriteString(buf, "<?");
5948 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5949 if (cur->content != NULL) {
5950 xmlOutputBufferWriteString(buf, " ");
5951#ifndef XML_USE_BUFFER_CONTENT
5952 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5953#else
5954 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5955#endif
5956 }
5957 xmlOutputBufferWriteString(buf, "?>");
5958 } else {
5959 xmlOutputBufferWriteString(buf, "<?");
5960 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5961 xmlOutputBufferWriteString(buf, "?>");
5962 }
5963 return;
5964 }
5965 if (cur->type == XML_COMMENT_NODE) {
5966 if (cur->content != NULL) {
5967 xmlOutputBufferWriteString(buf, "<!--");
5968#ifndef XML_USE_BUFFER_CONTENT
5969 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5970#else
5971 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5972#endif
5973 xmlOutputBufferWriteString(buf, "-->");
5974 }
5975 return;
5976 }
5977 if (cur->type == XML_ENTITY_REF_NODE) {
5978 xmlOutputBufferWriteString(buf, "&");
5979 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5980 xmlOutputBufferWriteString(buf, ";");
5981 return;
5982 }
5983 if (cur->type == XML_CDATA_SECTION_NODE) {
5984 xmlOutputBufferWriteString(buf, "<![CDATA[");
5985 if (cur->content != NULL)
5986#ifndef XML_USE_BUFFER_CONTENT
5987 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5988#else
5989 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5990#endif
5991 xmlOutputBufferWriteString(buf, "]]>");
5992 return;
5993 }
5994
5995 if (format == 1) {
5996 tmp = cur->children;
5997 while (tmp != NULL) {
5998 if ((tmp->type == XML_TEXT_NODE) ||
5999 (tmp->type == XML_ENTITY_REF_NODE)) {
6000 format = 0;
6001 break;
6002 }
6003 tmp = tmp->next;
6004 }
6005 }
6006 xmlOutputBufferWriteString(buf, "<");
6007 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6008 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6009 xmlOutputBufferWriteString(buf, ":");
6010 }
6011
6012 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6013 if (cur->nsDef)
6014 xmlNsListDumpOutput(buf, cur->nsDef);
6015 if (cur->properties != NULL)
6016 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6017
Daniel Veillard7db37732001-07-12 01:20:08 +00006018 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6019 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006020 xmlOutputBufferWriteString(buf, "/>");
6021 return;
6022 }
6023 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006024 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006025 xmlChar *buffer;
6026
6027#ifndef XML_USE_BUFFER_CONTENT
6028 if (encoding == NULL)
6029 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6030 else
6031 buffer = xmlEncodeSpecialChars(doc, cur->content);
6032#else
6033 if (encoding == NULL)
6034 buffer = xmlEncodeEntitiesReentrant(doc,
6035 xmlBufferContent(cur->content));
6036 else
6037 buffer = xmlEncodeSpecialChars(doc,
6038 xmlBufferContent(cur->content));
6039#endif
6040 if (buffer != NULL) {
6041 xmlOutputBufferWriteString(buf, (const char *)buffer);
6042 xmlFree(buffer);
6043 }
6044 }
6045 if (cur->children != NULL) {
6046 if (format) xmlOutputBufferWriteString(buf, "\n");
6047 xmlNodeListDumpOutput(buf, doc, cur->children,
6048 (level >= 0?level+1:-1), format, encoding);
6049 if ((xmlIndentTreeOutput) && (format))
6050 for (i = 0;i < level;i++)
6051 xmlOutputBufferWriteString(buf, " ");
6052 }
6053 xmlOutputBufferWriteString(buf, "</");
6054 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6055 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6056 xmlOutputBufferWriteString(buf, ":");
6057 }
6058
6059 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6060 xmlOutputBufferWriteString(buf, ">");
6061}
6062
6063/**
6064 * xmlDocContentDumpOutput:
6065 * @buf: the XML buffer output
6066 * @cur: the document
6067 * @encoding: an optional encoding string
6068 * @format: should formatting spaces been added
6069 *
6070 * Dump an XML document.
6071 */
6072static void
6073xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6074 const char *encoding, int format) {
6075 xmlOutputBufferWriteString(buf, "<?xml version=");
6076 if (cur->version != NULL)
6077 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6078 else
6079 xmlOutputBufferWriteString(buf, "\"1.0\"");
6080 if (encoding == NULL) {
6081 if (cur->encoding != NULL)
6082 encoding = (const char *) cur->encoding;
6083 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6084 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6085 }
6086 if (encoding != NULL) {
6087 xmlOutputBufferWriteString(buf, " encoding=");
6088 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6089 }
6090 switch (cur->standalone) {
6091 case 0:
6092 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6093 break;
6094 case 1:
6095 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6096 break;
6097 }
6098 xmlOutputBufferWriteString(buf, "?>\n");
6099 if (cur->children != NULL) {
6100 xmlNodePtr child = cur->children;
6101
6102 while (child != NULL) {
6103 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6104 xmlOutputBufferWriteString(buf, "\n");
6105 child = child->next;
6106 }
6107 }
6108}
6109
6110/************************************************************************
6111 * *
6112 * Saving functions front-ends *
6113 * *
6114 ************************************************************************/
6115
6116/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006117 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006118 * @out_doc: Document to generate XML text from
6119 * @doc_txt_ptr: Memory pointer for allocated XML text
6120 * @doc_txt_len: Length of the generated XML text
6121 * @txt_encoding: Character encoding to use when generating XML text
6122 * @format: should formatting spaces been added
6123 *
6124 * Dump the current DOM tree into memory using the character encoding specified
6125 * by the caller. Note it is up to the caller of this function to free the
6126 * allocated memory.
6127 */
6128
6129void
6130xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006131 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006132 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006133 int dummy = 0;
6134
6135 xmlCharEncoding doc_charset;
6136 xmlOutputBufferPtr out_buff = NULL;
6137 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6138
6139 if (doc_txt_len == NULL) {
6140 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6141 }
6142
6143 if (doc_txt_ptr == NULL) {
6144 *doc_txt_len = 0;
6145 xmlGenericError(xmlGenericErrorContext,
6146 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6147 return;
6148 }
6149
6150 *doc_txt_ptr = NULL;
6151 *doc_txt_len = 0;
6152
6153 if (out_doc == NULL) {
6154 /* No document, no output */
6155 xmlGenericError(xmlGenericErrorContext,
6156 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6157 return;
6158 }
6159
6160 /*
6161 * Validate the encoding value, if provided.
6162 * This logic is copied from xmlSaveFileEnc.
6163 */
6164
6165 if (txt_encoding == NULL)
6166 txt_encoding = (const char *) out_doc->encoding;
6167 if (txt_encoding != NULL) {
6168 doc_charset = xmlParseCharEncoding(txt_encoding);
6169
6170 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6171 xmlGenericError(xmlGenericErrorContext,
6172 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6173 return;
6174
6175 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6176 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6177 if ( conv_hdlr == NULL ) {
6178 xmlGenericError(xmlGenericErrorContext,
6179 "%s: %s %s '%s'\n",
6180 "xmlDocDumpFormatMemoryEnc",
6181 "Failed to identify encoding handler for",
6182 "character set",
6183 txt_encoding);
6184 return;
6185 }
6186 }
6187 }
6188
6189 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6190 xmlGenericError(xmlGenericErrorContext,
6191 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6192 return;
6193 }
6194
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006195 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006196 xmlOutputBufferFlush(out_buff);
6197 if (out_buff->conv != NULL) {
6198 *doc_txt_len = out_buff->conv->use;
6199 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6200 } else {
6201 *doc_txt_len = out_buff->buffer->use;
6202 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6203 }
6204 (void)xmlOutputBufferClose(out_buff);
6205
6206 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6207 *doc_txt_len = 0;
6208 xmlGenericError(xmlGenericErrorContext,
6209 "xmlDocDumpFormatMemoryEnc: %s\n",
6210 "Failed to allocate memory for document text representation.");
6211 }
6212
6213 return;
6214}
6215
6216/**
6217 * xmlDocDumpMemory:
6218 * @cur: the document
6219 * @mem: OUT: the memory pointer
6220 * @size: OUT: the memory lenght
6221 *
6222 * Dump an XML document in memory and return the xmlChar * and it's size.
6223 * It's up to the caller to free the memory.
6224 */
6225void
6226xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6227 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6228}
6229
6230/**
6231 * xmlDocDumpFormatMemory:
6232 * @cur: the document
6233 * @mem: OUT: the memory pointer
6234 * @size: OUT: the memory lenght
6235 * @format: should formatting spaces been added
6236 *
6237 *
6238 * Dump an XML document in memory and return the xmlChar * and it's size.
6239 * It's up to the caller to free the memory.
6240 */
6241void
6242xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6243 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6244}
6245
6246/**
6247 * xmlDocDumpMemoryEnc:
6248 * @out_doc: Document to generate XML text from
6249 * @doc_txt_ptr: Memory pointer for allocated XML text
6250 * @doc_txt_len: Length of the generated XML text
6251 * @txt_encoding: Character encoding to use when generating XML text
6252 *
6253 * Dump the current DOM tree into memory using the character encoding specified
6254 * by the caller. Note it is up to the caller of this function to free the
6255 * allocated memory.
6256 */
6257
6258void
6259xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6260 int * doc_txt_len, const char * txt_encoding) {
6261 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006262 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006263}
6264
6265/**
6266 * xmlGetDocCompressMode:
6267 * @doc: the document
6268 *
6269 * get the compression ratio for a document, ZLIB based
6270 * Returns 0 (uncompressed) to 9 (max compression)
6271 */
6272int
6273xmlGetDocCompressMode (xmlDocPtr doc) {
6274 if (doc == NULL) return(-1);
6275 return(doc->compression);
6276}
6277
6278/**
6279 * xmlSetDocCompressMode:
6280 * @doc: the document
6281 * @mode: the compression ratio
6282 *
6283 * set the compression ratio for a document, ZLIB based
6284 * Correct values: 0 (uncompressed) to 9 (max compression)
6285 */
6286void
6287xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6288 if (doc == NULL) return;
6289 if (mode < 0) doc->compression = 0;
6290 else if (mode > 9) doc->compression = 9;
6291 else doc->compression = mode;
6292}
6293
6294/**
6295 * xmlGetCompressMode:
6296 *
6297 * get the default compression mode used, ZLIB based.
6298 * Returns 0 (uncompressed) to 9 (max compression)
6299 */
6300int
6301 xmlGetCompressMode(void) {
6302 return(xmlCompressMode);
6303}
6304
6305/**
6306 * xmlSetCompressMode:
6307 * @mode: the compression ratio
6308 *
6309 * set the default compression mode used, ZLIB based
6310 * Correct values: 0 (uncompressed) to 9 (max compression)
6311 */
6312void
6313xmlSetCompressMode(int mode) {
6314 if (mode < 0) xmlCompressMode = 0;
6315 else if (mode > 9) xmlCompressMode = 9;
6316 else xmlCompressMode = mode;
6317}
6318
6319/**
6320 * xmlDocDump:
6321 * @f: the FILE*
6322 * @cur: the document
6323 *
6324 * Dump an XML document to an open FILE.
6325 *
6326 * returns: the number of byte written or -1 in case of failure.
6327 */
6328int
6329xmlDocDump(FILE *f, xmlDocPtr cur) {
6330 xmlOutputBufferPtr buf;
6331 const char * encoding;
6332 xmlCharEncodingHandlerPtr handler = NULL;
6333 int ret;
6334
6335 if (cur == NULL) {
6336#ifdef DEBUG_TREE
6337 xmlGenericError(xmlGenericErrorContext,
6338 "xmlDocDump : document == NULL\n");
6339#endif
6340 return(-1);
6341 }
6342 encoding = (const char *) cur->encoding;
6343
6344 if (encoding != NULL) {
6345 xmlCharEncoding enc;
6346
6347 enc = xmlParseCharEncoding(encoding);
6348
6349 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6350 xmlGenericError(xmlGenericErrorContext,
6351 "xmlDocDump: document not in UTF8\n");
6352 return(-1);
6353 }
6354 if (enc != XML_CHAR_ENCODING_UTF8) {
6355 handler = xmlFindCharEncodingHandler(encoding);
6356 if (handler == NULL) {
6357 xmlFree((char *) cur->encoding);
6358 cur->encoding = NULL;
6359 }
6360 }
6361 }
6362 buf = xmlOutputBufferCreateFile(f, handler);
6363 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006364 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006365
6366 ret = xmlOutputBufferClose(buf);
6367 return(ret);
6368}
6369
6370/**
6371 * xmlSaveFileTo:
6372 * @buf: an output I/O buffer
6373 * @cur: the document
6374 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6375 *
6376 * Dump an XML document to an I/O buffer.
6377 *
6378 * returns: the number of byte written or -1 in case of failure.
6379 */
6380int
6381xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
6382 int ret;
6383
6384 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006385 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006386 ret = xmlOutputBufferClose(buf);
6387 return(ret);
6388}
6389
6390/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006391 * xmlSaveFormatFileTo:
6392 * @buf: an output I/O buffer
6393 * @cur: the document
6394 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6395 * @format: should formatting spaces been added
6396 *
6397 * Dump an XML document to an I/O buffer.
6398 *
6399 * returns: the number of byte written or -1 in case of failure.
6400 */
6401int
6402xmlSaveFormatFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding, int format) {
6403 int ret;
6404
6405 if (buf == NULL) return(0);
6406 xmlDocContentDumpOutput(buf, cur, encoding, format);
6407 ret = xmlOutputBufferClose(buf);
6408 return(ret);
6409}
6410
6411/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006412 * xmlSaveFormatFileEnc
6413 * @filename: the filename or URL to output
6414 * @cur: the document being saved
6415 * @encoding: the name of the encoding to use or NULL.
6416 * @format: should formatting spaces be added.
Owen Taylor3473f882001-02-23 17:55:21 +00006417 */
6418int
Daniel Veillardf012a642001-07-23 19:10:52 +00006419xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6420 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006421 xmlOutputBufferPtr buf;
6422 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006423 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006424 int ret;
6425
6426 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006427
6428 enc = xmlParseCharEncoding(encoding);
6429 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6430 xmlGenericError(xmlGenericErrorContext,
6431 "xmlSaveFileEnc: document not in UTF8\n");
6432 return(-1);
6433 }
6434 if (enc != XML_CHAR_ENCODING_UTF8) {
6435 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006436 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006437 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006438 }
6439 }
6440
Daniel Veillardf012a642001-07-23 19:10:52 +00006441#ifdef HAVE_ZLIB_H
6442 if (cur->compression < 0) cur->compression = xmlCompressMode;
6443#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006444 /*
6445 * save the content to a temp buffer.
6446 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006447 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006448 if (buf == NULL) return(-1);
6449
Daniel Veillardf012a642001-07-23 19:10:52 +00006450 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006451
6452 ret = xmlOutputBufferClose(buf);
6453 return(ret);
6454}
6455
Daniel Veillardf012a642001-07-23 19:10:52 +00006456
6457/**
6458 * xmlSaveFileEnc:
6459 * @filename: the filename (or URL)
6460 * @cur: the document
6461 * @encoding: the name of an encoding (or NULL)
6462 *
6463 * Dump an XML document, converting it to the given encoding
6464 *
6465 * returns: the number of byte written or -1 in case of failure.
6466 */
6467int
6468xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6469 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6470}
6471
Owen Taylor3473f882001-02-23 17:55:21 +00006472/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006473 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006474 * @filename: the filename (or URL)
6475 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006476 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006477 *
6478 * Dump an XML document to a file. Will use compression if
6479 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillard67fee942001-04-26 18:59:03 +00006480 * used. If format is set then the document will be indented on output.
6481 *
Owen Taylor3473f882001-02-23 17:55:21 +00006482 * returns: the number of byte written or -1 in case of failure.
6483 */
6484int
Daniel Veillard67fee942001-04-26 18:59:03 +00006485xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006486 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006487}
6488
Daniel Veillard67fee942001-04-26 18:59:03 +00006489/**
6490 * xmlSaveFile:
6491 * @filename: the filename (or URL)
6492 * @cur: the document
6493 *
6494 * Dump an XML document to a file. Will use compression if
6495 * compiled in and enabled. If @filename is "-" the stdout file is
6496 * used.
6497 * returns: the number of byte written or -1 in case of failure.
6498 */
6499int
6500xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006501 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006502}
6503