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