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