blob: 9d0bc9a59fbe374d6c9a4845fe389ef262dddc7e [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 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002489 if (cur->type == XML_DTD_NODE) {
2490 xmlDocPtr doc;
2491 doc = cur->doc;
2492 if (doc->intSubset == (xmlDtdPtr) cur)
2493 doc->intSubset = NULL;
2494 if (doc->extSubset == (xmlDtdPtr) cur)
2495 doc->extSubset = NULL;
2496 }
Owen Taylor3473f882001-02-23 17:55:21 +00002497 if ((cur->parent != NULL) && (cur->parent->children == cur))
2498 cur->parent->children = cur->next;
2499 if ((cur->parent != NULL) && (cur->parent->last == cur))
2500 cur->parent->last = cur->prev;
2501 if (cur->next != NULL)
2502 cur->next->prev = cur->prev;
2503 if (cur->prev != NULL)
2504 cur->prev->next = cur->next;
2505 cur->next = cur->prev = NULL;
2506 cur->parent = NULL;
2507}
2508
2509/**
2510 * xmlReplaceNode:
2511 * @old: the old node
2512 * @cur: the node
2513 *
2514 * Unlink the old node from it's current context, prune the new one
2515 * at the same place. If cur was already inserted in a document it is
2516 * first unlinked from its existing context.
2517 *
2518 * Returns the old node
2519 */
2520xmlNodePtr
2521xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2522 if (old == NULL) {
2523#ifdef DEBUG_TREE
2524 xmlGenericError(xmlGenericErrorContext,
2525 "xmlReplaceNode : old == NULL\n");
2526#endif
2527 return(NULL);
2528 }
2529 if (cur == NULL) {
2530 xmlUnlinkNode(old);
2531 return(old);
2532 }
2533 if (cur == old) {
2534 return(old);
2535 }
2536 xmlUnlinkNode(cur);
2537 cur->doc = old->doc;
2538 cur->parent = old->parent;
2539 cur->next = old->next;
2540 if (cur->next != NULL)
2541 cur->next->prev = cur;
2542 cur->prev = old->prev;
2543 if (cur->prev != NULL)
2544 cur->prev->next = cur;
2545 if (cur->parent != NULL) {
2546 if (cur->parent->children == old)
2547 cur->parent->children = cur;
2548 if (cur->parent->last == old)
2549 cur->parent->last = cur;
2550 }
2551 old->next = old->prev = NULL;
2552 old->parent = NULL;
2553 return(old);
2554}
2555
2556/************************************************************************
2557 * *
2558 * Copy operations *
2559 * *
2560 ************************************************************************/
2561
2562/**
2563 * xmlCopyNamespace:
2564 * @cur: the namespace
2565 *
2566 * Do a copy of the namespace.
2567 *
2568 * Returns: a new xmlNsPtr, or NULL in case of error.
2569 */
2570xmlNsPtr
2571xmlCopyNamespace(xmlNsPtr cur) {
2572 xmlNsPtr ret;
2573
2574 if (cur == NULL) return(NULL);
2575 switch (cur->type) {
2576 case XML_LOCAL_NAMESPACE:
2577 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2578 break;
2579 default:
2580#ifdef DEBUG_TREE
2581 xmlGenericError(xmlGenericErrorContext,
2582 "xmlCopyNamespace: invalid type %d\n", cur->type);
2583#endif
2584 return(NULL);
2585 }
2586 return(ret);
2587}
2588
2589/**
2590 * xmlCopyNamespaceList:
2591 * @cur: the first namespace
2592 *
2593 * Do a copy of an namespace list.
2594 *
2595 * Returns: a new xmlNsPtr, or NULL in case of error.
2596 */
2597xmlNsPtr
2598xmlCopyNamespaceList(xmlNsPtr cur) {
2599 xmlNsPtr ret = NULL;
2600 xmlNsPtr p = NULL,q;
2601
2602 while (cur != NULL) {
2603 q = xmlCopyNamespace(cur);
2604 if (p == NULL) {
2605 ret = p = q;
2606 } else {
2607 p->next = q;
2608 p = q;
2609 }
2610 cur = cur->next;
2611 }
2612 return(ret);
2613}
2614
2615static xmlNodePtr
2616xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2617/**
2618 * xmlCopyProp:
2619 * @target: the element where the attribute will be grafted
2620 * @cur: the attribute
2621 *
2622 * Do a copy of the attribute.
2623 *
2624 * Returns: a new xmlAttrPtr, or NULL in case of error.
2625 */
2626xmlAttrPtr
2627xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2628 xmlAttrPtr ret;
2629
2630 if (cur == NULL) return(NULL);
2631 if (target != NULL)
2632 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2633 else if (cur->parent != NULL)
2634 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2635 else if (cur->children != NULL)
2636 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2637 else
2638 ret = xmlNewDocProp(NULL, cur->name, NULL);
2639 if (ret == NULL) return(NULL);
2640 ret->parent = target;
2641
2642 if ((cur->ns != NULL) && (target != NULL)) {
2643 xmlNsPtr ns;
2644
2645 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2646 ret->ns = ns;
2647 } else
2648 ret->ns = NULL;
2649
2650 if (cur->children != NULL) {
2651 xmlNodePtr tmp;
2652
2653 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2654 ret->last = NULL;
2655 tmp = ret->children;
2656 while (tmp != NULL) {
2657 /* tmp->parent = (xmlNodePtr)ret; */
2658 if (tmp->next == NULL)
2659 ret->last = tmp;
2660 tmp = tmp->next;
2661 }
2662 }
2663 return(ret);
2664}
2665
2666/**
2667 * xmlCopyPropList:
2668 * @target: the element where the attributes will be grafted
2669 * @cur: the first attribute
2670 *
2671 * Do a copy of an attribute list.
2672 *
2673 * Returns: a new xmlAttrPtr, or NULL in case of error.
2674 */
2675xmlAttrPtr
2676xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2677 xmlAttrPtr ret = NULL;
2678 xmlAttrPtr p = NULL,q;
2679
2680 while (cur != NULL) {
2681 q = xmlCopyProp(target, cur);
2682 if (p == NULL) {
2683 ret = p = q;
2684 } else {
2685 p->next = q;
2686 q->prev = p;
2687 p = q;
2688 }
2689 cur = cur->next;
2690 }
2691 return(ret);
2692}
2693
2694/*
2695 * NOTE abeut the CopyNode operations !
2696 *
2697 * They are splitted into external and internal parts for one
2698 * tricky reason: namespaces. Doing a direct copy of a node
2699 * say RPM:Copyright without changing the namespace pointer to
2700 * something else can produce stale links. One way to do it is
2701 * to keep a reference counter but this doesn't work as soon
2702 * as one move the element or the subtree out of the scope of
2703 * the existing namespace. The actual solution seems to add
2704 * a copy of the namespace at the top of the copied tree if
2705 * not available in the subtree.
2706 * Hence two functions, the public front-end call the inner ones
2707 */
2708
2709static xmlNodePtr
2710xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2711
2712static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002713xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002714 int recursive) {
2715 xmlNodePtr ret;
2716
2717 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002718 switch (node->type) {
2719 case XML_TEXT_NODE:
2720 case XML_CDATA_SECTION_NODE:
2721 case XML_ELEMENT_NODE:
2722 case XML_ENTITY_REF_NODE:
2723 case XML_ENTITY_NODE:
2724 case XML_PI_NODE:
2725 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002726 case XML_XINCLUDE_START:
2727 case XML_XINCLUDE_END:
2728 break;
2729 case XML_ATTRIBUTE_NODE:
2730 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2731 case XML_NAMESPACE_DECL:
2732 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2733
Daniel Veillard39196eb2001-06-19 18:09:42 +00002734 case XML_DOCUMENT_NODE:
2735 case XML_HTML_DOCUMENT_NODE:
2736#ifdef LIBXML_DOCB_ENABLED
2737 case XML_DOCB_DOCUMENT_NODE:
2738#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002739 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002740 case XML_DOCUMENT_TYPE_NODE:
2741 case XML_DOCUMENT_FRAG_NODE:
2742 case XML_NOTATION_NODE:
2743 case XML_DTD_NODE:
2744 case XML_ELEMENT_DECL:
2745 case XML_ATTRIBUTE_DECL:
2746 case XML_ENTITY_DECL:
2747 return(NULL);
2748 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002749
Owen Taylor3473f882001-02-23 17:55:21 +00002750 /*
2751 * Allocate a new node and fill the fields.
2752 */
2753 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2754 if (ret == NULL) {
2755 xmlGenericError(xmlGenericErrorContext,
2756 "xmlStaticCopyNode : malloc failed\n");
2757 return(NULL);
2758 }
2759 memset(ret, 0, sizeof(xmlNode));
2760 ret->type = node->type;
2761
2762 ret->doc = doc;
2763 ret->parent = parent;
2764 if (node->name == xmlStringText)
2765 ret->name = xmlStringText;
2766 else if (node->name == xmlStringTextNoenc)
2767 ret->name = xmlStringTextNoenc;
2768 else if (node->name == xmlStringComment)
2769 ret->name = xmlStringComment;
2770 else if (node->name != NULL)
2771 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002772 if ((node->type != XML_ELEMENT_NODE) &&
2773 (node->content != NULL) &&
2774 (node->type != XML_ENTITY_REF_NODE) &&
2775 (node->type != XML_XINCLUDE_END) &&
2776 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002777#ifndef XML_USE_BUFFER_CONTENT
2778 ret->content = xmlStrdup(node->content);
2779#else
2780 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2781 xmlBufferSetAllocationScheme(ret->content,
2782 xmlGetBufferAllocationScheme());
2783 xmlBufferAdd(ret->content,
2784 xmlBufferContent(node->content),
2785 xmlBufferLength(node->content));
2786#endif
2787 }
2788 if (parent != NULL)
2789 xmlAddChild(parent, ret);
2790
2791 if (!recursive) return(ret);
2792 if (node->nsDef != NULL)
2793 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2794
2795 if (node->ns != NULL) {
2796 xmlNsPtr ns;
2797
2798 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2799 if (ns == NULL) {
2800 /*
2801 * Humm, we are copying an element whose namespace is defined
2802 * out of the new tree scope. Search it in the original tree
2803 * and add it at the top of the new tree
2804 */
2805 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2806 if (ns != NULL) {
2807 xmlNodePtr root = ret;
2808
2809 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002810 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002811 }
2812 } else {
2813 /*
2814 * reference the existing namespace definition in our own tree.
2815 */
2816 ret->ns = ns;
2817 }
2818 }
2819 if (node->properties != NULL)
2820 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002821 if (node->type == XML_ENTITY_REF_NODE) {
2822 if ((doc == NULL) || (node->doc != doc)) {
2823 /*
2824 * The copied node will go into a separate document, so
2825 * to havoid dandling references to the ENTITY_DECL node
2826 * we cannot keep the reference. Try to find it in the
2827 * target document.
2828 */
2829 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2830 } else {
2831 ret->children = node->children;
2832 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002833 ret->last = ret->children;
2834 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002835 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002836 UPDATE_LAST_CHILD_AND_PARENT(ret)
2837 }
Owen Taylor3473f882001-02-23 17:55:21 +00002838 return(ret);
2839}
2840
2841static xmlNodePtr
2842xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2843 xmlNodePtr ret = NULL;
2844 xmlNodePtr p = NULL,q;
2845
2846 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002847 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002848 if (doc == NULL) {
2849 node = node->next;
2850 continue;
2851 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002852 if (doc->intSubset == NULL) {
2853 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2854 q->doc = doc;
2855 q->parent = parent;
2856 doc->intSubset = (xmlDtdPtr) q;
2857 } else {
2858 q = (xmlNodePtr) doc->intSubset;
2859 }
2860 } else
2861 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002862 if (ret == NULL) {
2863 q->prev = NULL;
2864 ret = p = q;
2865 } else {
2866 p->next = q;
2867 q->prev = p;
2868 p = q;
2869 }
2870 node = node->next;
2871 }
2872 return(ret);
2873}
2874
2875/**
2876 * xmlCopyNode:
2877 * @node: the node
2878 * @recursive: if 1 do a recursive copy.
2879 *
2880 * Do a copy of the node.
2881 *
2882 * Returns: a new xmlNodePtr, or NULL in case of error.
2883 */
2884xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002885xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002886 xmlNodePtr ret;
2887
2888 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2889 return(ret);
2890}
2891
2892/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002893 * xmlDocCopyNode:
2894 * @node: the node
2895 * @recursive: if 1 do a recursive copy.
2896 *
2897 * Do a copy of the node to a given document.
2898 *
2899 * Returns: a new xmlNodePtr, or NULL in case of error.
2900 */
2901xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002902xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002903 xmlNodePtr ret;
2904
2905 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2906 return(ret);
2907}
2908
2909/**
Owen Taylor3473f882001-02-23 17:55:21 +00002910 * xmlCopyNodeList:
2911 * @node: the first node in the list.
2912 *
2913 * Do a recursive copy of the node list.
2914 *
2915 * Returns: a new xmlNodePtr, or NULL in case of error.
2916 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002917xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002918 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2919 return(ret);
2920}
2921
2922/**
Owen Taylor3473f882001-02-23 17:55:21 +00002923 * xmlCopyDtd:
2924 * @dtd: the dtd
2925 *
2926 * Do a copy of the dtd.
2927 *
2928 * Returns: a new xmlDtdPtr, or NULL in case of error.
2929 */
2930xmlDtdPtr
2931xmlCopyDtd(xmlDtdPtr dtd) {
2932 xmlDtdPtr ret;
2933
2934 if (dtd == NULL) return(NULL);
2935 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2936 if (ret == NULL) return(NULL);
2937 if (dtd->entities != NULL)
2938 ret->entities = (void *) xmlCopyEntitiesTable(
2939 (xmlEntitiesTablePtr) dtd->entities);
2940 if (dtd->notations != NULL)
2941 ret->notations = (void *) xmlCopyNotationTable(
2942 (xmlNotationTablePtr) dtd->notations);
2943 if (dtd->elements != NULL)
2944 ret->elements = (void *) xmlCopyElementTable(
2945 (xmlElementTablePtr) dtd->elements);
2946 if (dtd->attributes != NULL)
2947 ret->attributes = (void *) xmlCopyAttributeTable(
2948 (xmlAttributeTablePtr) dtd->attributes);
2949 return(ret);
2950}
2951
2952/**
2953 * xmlCopyDoc:
2954 * @doc: the document
2955 * @recursive: if 1 do a recursive copy.
2956 *
2957 * Do a copy of the document info. If recursive, the content tree will
2958 * be copied too as well as Dtd, namespaces and entities.
2959 *
2960 * Returns: a new xmlDocPtr, or NULL in case of error.
2961 */
2962xmlDocPtr
2963xmlCopyDoc(xmlDocPtr doc, int recursive) {
2964 xmlDocPtr ret;
2965
2966 if (doc == NULL) return(NULL);
2967 ret = xmlNewDoc(doc->version);
2968 if (ret == NULL) return(NULL);
2969 if (doc->name != NULL)
2970 ret->name = xmlMemStrdup(doc->name);
2971 if (doc->encoding != NULL)
2972 ret->encoding = xmlStrdup(doc->encoding);
2973 ret->charset = doc->charset;
2974 ret->compression = doc->compression;
2975 ret->standalone = doc->standalone;
2976 if (!recursive) return(ret);
2977
Daniel Veillardb33c2012001-04-25 12:59:04 +00002978 ret->last = NULL;
2979 ret->children = NULL;
2980 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002981 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002982 ret->intSubset->doc = ret;
2983 ret->intSubset->parent = ret;
2984 }
Owen Taylor3473f882001-02-23 17:55:21 +00002985 if (doc->oldNs != NULL)
2986 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2987 if (doc->children != NULL) {
2988 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002989
2990 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2991 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002992 ret->last = NULL;
2993 tmp = ret->children;
2994 while (tmp != NULL) {
2995 if (tmp->next == NULL)
2996 ret->last = tmp;
2997 tmp = tmp->next;
2998 }
2999 }
3000 return(ret);
3001}
3002
3003/************************************************************************
3004 * *
3005 * Content access functions *
3006 * *
3007 ************************************************************************/
3008
3009/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003010 * xmlGetLineNo:
3011 * @node : valid node
3012 *
3013 * Get line number of node. this requires activation of this option
3014 * before inoking the parser by calling xmlLineNumbersDefault(1)
3015 *
3016 * Returns the line number if sucessfull, -1 otherwise
3017 */
3018long
3019xmlGetLineNo(xmlNodePtr node)
3020{
3021 long result = -1;
3022
3023 if (!node)
3024 return result;
3025 if (node->type == XML_ELEMENT_NODE)
3026 result = (long) node->content;
3027 else if ((node->prev != NULL) &&
3028 ((node->prev->type == XML_ELEMENT_NODE) ||
3029 (node->prev->type == XML_TEXT_NODE)))
3030 result = xmlGetLineNo(node->prev);
3031 else if ((node->parent != NULL) &&
3032 ((node->parent->type == XML_ELEMENT_NODE) ||
3033 (node->parent->type == XML_TEXT_NODE)))
3034 result = xmlGetLineNo(node->parent);
3035
3036 return result;
3037}
3038
3039/**
3040 * xmlGetNodePath:
3041 * @node: a node
3042 *
3043 * Build a structure based Path for the given node
3044 *
3045 * Returns the new path or NULL in case of error. The caller must free
3046 * the returned string
3047 */
3048xmlChar *
3049xmlGetNodePath(xmlNodePtr node)
3050{
3051 xmlNodePtr cur, tmp, next;
3052 xmlChar *buffer = NULL, *temp;
3053 size_t buf_len;
3054 xmlChar *buf;
3055 char sep;
3056 const char *name;
3057 char nametemp[100];
3058 int occur = 0;
3059
3060 if (node == NULL)
3061 return (NULL);
3062
3063 buf_len = 500;
3064 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3065 if (buffer == NULL)
3066 return (NULL);
3067 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3068 if (buf == NULL) {
3069 xmlFree(buffer);
3070 return (NULL);
3071 }
3072
3073 buffer[0] = 0;
3074 cur = node;
3075 do {
3076 name = "";
3077 sep = '?';
3078 occur = 0;
3079 if ((cur->type == XML_DOCUMENT_NODE) ||
3080 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3081 if (buffer[0] == '/')
3082 break;
3083 sep = '/';
3084 next = NULL;
3085 } else if (cur->type == XML_ELEMENT_NODE) {
3086 sep = '/';
3087 name = (const char *) cur->name;
3088 if (cur->ns) {
3089 snprintf(nametemp, sizeof(nametemp) - 1,
3090 "%s:%s", cur->ns->prefix, cur->name);
3091 nametemp[sizeof(nametemp) - 1] = 0;
3092 name = nametemp;
3093 }
3094 next = cur->parent;
3095
3096 /*
3097 * Thumbler index computation
3098 */
3099 tmp = cur->prev;
3100 while (tmp != NULL) {
3101 if (xmlStrEqual(cur->name, tmp->name))
3102 occur++;
3103 tmp = tmp->prev;
3104 }
3105 if (occur == 0) {
3106 tmp = cur->next;
3107 while (tmp != NULL) {
3108 if (xmlStrEqual(cur->name, tmp->name))
3109 occur++;
3110 tmp = tmp->next;
3111 }
3112 if (occur != 0)
3113 occur = 1;
3114 } else
3115 occur++;
3116 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3117 sep = '@';
3118 name = (const char *) (((xmlAttrPtr) cur)->name);
3119 next = ((xmlAttrPtr) cur)->parent;
3120 } else {
3121 next = cur->parent;
3122 }
3123
3124 /*
3125 * Make sure there is enough room
3126 */
3127 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3128 buf_len =
3129 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3130 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3131 if (temp == NULL) {
3132 xmlFree(buf);
3133 xmlFree(buffer);
3134 return (NULL);
3135 }
3136 buffer = temp;
3137 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3138 if (temp == NULL) {
3139 xmlFree(buf);
3140 xmlFree(buffer);
3141 return (NULL);
3142 }
3143 buf = temp;
3144 }
3145 if (occur == 0)
3146 snprintf((char *) buf, buf_len, "%c%s%s",
3147 sep, name, (char *) buffer);
3148 else
3149 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3150 sep, name, occur, (char *) buffer);
3151 snprintf((char *) buffer, buf_len, "%s", buf);
3152 cur = next;
3153 } while (cur != NULL);
3154 xmlFree(buf);
3155 return (buffer);
3156}
3157
3158/**
Owen Taylor3473f882001-02-23 17:55:21 +00003159 * xmlDocGetRootElement:
3160 * @doc: the document
3161 *
3162 * Get the root element of the document (doc->children is a list
3163 * containing possibly comments, PIs, etc ...).
3164 *
3165 * Returns the xmlNodePtr for the root or NULL
3166 */
3167xmlNodePtr
3168xmlDocGetRootElement(xmlDocPtr doc) {
3169 xmlNodePtr ret;
3170
3171 if (doc == NULL) return(NULL);
3172 ret = doc->children;
3173 while (ret != NULL) {
3174 if (ret->type == XML_ELEMENT_NODE)
3175 return(ret);
3176 ret = ret->next;
3177 }
3178 return(ret);
3179}
3180
3181/**
3182 * xmlDocSetRootElement:
3183 * @doc: the document
3184 * @root: the new document root element
3185 *
3186 * Set the root element of the document (doc->children is a list
3187 * containing possibly comments, PIs, etc ...).
3188 *
3189 * Returns the old root element if any was found
3190 */
3191xmlNodePtr
3192xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3193 xmlNodePtr old = NULL;
3194
3195 if (doc == NULL) return(NULL);
3196 old = doc->children;
3197 while (old != NULL) {
3198 if (old->type == XML_ELEMENT_NODE)
3199 break;
3200 old = old->next;
3201 }
3202 if (old == NULL) {
3203 if (doc->children == NULL) {
3204 doc->children = root;
3205 doc->last = root;
3206 } else {
3207 xmlAddSibling(doc->children, root);
3208 }
3209 } else {
3210 xmlReplaceNode(old, root);
3211 }
3212 return(old);
3213}
3214
3215/**
3216 * xmlNodeSetLang:
3217 * @cur: the node being changed
3218 * @lang: the langage description
3219 *
3220 * Set the language of a node, i.e. the values of the xml:lang
3221 * attribute.
3222 */
3223void
3224xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3225 if (cur == NULL) return;
3226 switch(cur->type) {
3227 case XML_TEXT_NODE:
3228 case XML_CDATA_SECTION_NODE:
3229 case XML_COMMENT_NODE:
3230 case XML_DOCUMENT_NODE:
3231 case XML_DOCUMENT_TYPE_NODE:
3232 case XML_DOCUMENT_FRAG_NODE:
3233 case XML_NOTATION_NODE:
3234 case XML_HTML_DOCUMENT_NODE:
3235 case XML_DTD_NODE:
3236 case XML_ELEMENT_DECL:
3237 case XML_ATTRIBUTE_DECL:
3238 case XML_ENTITY_DECL:
3239 case XML_PI_NODE:
3240 case XML_ENTITY_REF_NODE:
3241 case XML_ENTITY_NODE:
3242 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003243#ifdef LIBXML_DOCB_ENABLED
3244 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003245#endif
3246 case XML_XINCLUDE_START:
3247 case XML_XINCLUDE_END:
3248 return;
3249 case XML_ELEMENT_NODE:
3250 case XML_ATTRIBUTE_NODE:
3251 break;
3252 }
3253 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3254}
3255
3256/**
3257 * xmlNodeGetLang:
3258 * @cur: the node being checked
3259 *
3260 * Searches the language of a node, i.e. the values of the xml:lang
3261 * attribute or the one carried by the nearest ancestor.
3262 *
3263 * Returns a pointer to the lang value, or NULL if not found
3264 * It's up to the caller to free the memory.
3265 */
3266xmlChar *
3267xmlNodeGetLang(xmlNodePtr cur) {
3268 xmlChar *lang;
3269
3270 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003271 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003272 if (lang != NULL)
3273 return(lang);
3274 cur = cur->parent;
3275 }
3276 return(NULL);
3277}
3278
3279
3280/**
3281 * xmlNodeSetSpacePreserve:
3282 * @cur: the node being changed
3283 * @val: the xml:space value ("0": default, 1: "preserve")
3284 *
3285 * Set (or reset) the space preserving behaviour of a node, i.e. the
3286 * value of the xml:space attribute.
3287 */
3288void
3289xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3290 if (cur == NULL) return;
3291 switch(cur->type) {
3292 case XML_TEXT_NODE:
3293 case XML_CDATA_SECTION_NODE:
3294 case XML_COMMENT_NODE:
3295 case XML_DOCUMENT_NODE:
3296 case XML_DOCUMENT_TYPE_NODE:
3297 case XML_DOCUMENT_FRAG_NODE:
3298 case XML_NOTATION_NODE:
3299 case XML_HTML_DOCUMENT_NODE:
3300 case XML_DTD_NODE:
3301 case XML_ELEMENT_DECL:
3302 case XML_ATTRIBUTE_DECL:
3303 case XML_ENTITY_DECL:
3304 case XML_PI_NODE:
3305 case XML_ENTITY_REF_NODE:
3306 case XML_ENTITY_NODE:
3307 case XML_NAMESPACE_DECL:
3308 case XML_XINCLUDE_START:
3309 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003310#ifdef LIBXML_DOCB_ENABLED
3311 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003312#endif
3313 return;
3314 case XML_ELEMENT_NODE:
3315 case XML_ATTRIBUTE_NODE:
3316 break;
3317 }
3318 switch (val) {
3319 case 0:
3320 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3321 break;
3322 case 1:
3323 xmlSetProp(cur, BAD_CAST "xml:space",
3324 BAD_CAST "preserve");
3325 break;
3326 }
3327}
3328
3329/**
3330 * xmlNodeGetSpacePreserve:
3331 * @cur: the node being checked
3332 *
3333 * Searches the space preserving behaviour of a node, i.e. the values
3334 * of the xml:space attribute or the one carried by the nearest
3335 * ancestor.
3336 *
3337 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
3338 */
3339int
3340xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3341 xmlChar *space;
3342
3343 while (cur != NULL) {
3344 space = xmlGetProp(cur, BAD_CAST "xml:space");
3345 if (space != NULL) {
3346 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3347 xmlFree(space);
3348 return(1);
3349 }
3350 if (xmlStrEqual(space, BAD_CAST "default")) {
3351 xmlFree(space);
3352 return(0);
3353 }
3354 xmlFree(space);
3355 }
3356 cur = cur->parent;
3357 }
3358 return(-1);
3359}
3360
3361/**
3362 * xmlNodeSetName:
3363 * @cur: the node being changed
3364 * @name: the new tag name
3365 *
3366 * Set (or reset) the name of a node.
3367 */
3368void
3369xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3370 if (cur == NULL) return;
3371 if (name == NULL) return;
3372 switch(cur->type) {
3373 case XML_TEXT_NODE:
3374 case XML_CDATA_SECTION_NODE:
3375 case XML_COMMENT_NODE:
3376 case XML_DOCUMENT_TYPE_NODE:
3377 case XML_DOCUMENT_FRAG_NODE:
3378 case XML_NOTATION_NODE:
3379 case XML_HTML_DOCUMENT_NODE:
3380 case XML_NAMESPACE_DECL:
3381 case XML_XINCLUDE_START:
3382 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003383#ifdef LIBXML_DOCB_ENABLED
3384 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003385#endif
3386 return;
3387 case XML_ELEMENT_NODE:
3388 case XML_ATTRIBUTE_NODE:
3389 case XML_PI_NODE:
3390 case XML_ENTITY_REF_NODE:
3391 case XML_ENTITY_NODE:
3392 case XML_DTD_NODE:
3393 case XML_DOCUMENT_NODE:
3394 case XML_ELEMENT_DECL:
3395 case XML_ATTRIBUTE_DECL:
3396 case XML_ENTITY_DECL:
3397 break;
3398 }
3399 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3400 cur->name = xmlStrdup(name);
3401}
3402
3403/**
3404 * xmlNodeSetBase:
3405 * @cur: the node being changed
3406 * @uri: the new base URI
3407 *
3408 * Set (or reset) the base URI of a node, i.e. the value of the
3409 * xml:base attribute.
3410 */
3411void
3412xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3413 if (cur == NULL) return;
3414 switch(cur->type) {
3415 case XML_TEXT_NODE:
3416 case XML_CDATA_SECTION_NODE:
3417 case XML_COMMENT_NODE:
3418 case XML_DOCUMENT_NODE:
3419 case XML_DOCUMENT_TYPE_NODE:
3420 case XML_DOCUMENT_FRAG_NODE:
3421 case XML_NOTATION_NODE:
3422 case XML_HTML_DOCUMENT_NODE:
3423 case XML_DTD_NODE:
3424 case XML_ELEMENT_DECL:
3425 case XML_ATTRIBUTE_DECL:
3426 case XML_ENTITY_DECL:
3427 case XML_PI_NODE:
3428 case XML_ENTITY_REF_NODE:
3429 case XML_ENTITY_NODE:
3430 case XML_NAMESPACE_DECL:
3431 case XML_XINCLUDE_START:
3432 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003433#ifdef LIBXML_DOCB_ENABLED
3434 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003435#endif
3436 return;
3437 case XML_ELEMENT_NODE:
3438 case XML_ATTRIBUTE_NODE:
3439 break;
3440 }
3441 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3442}
3443
3444/**
Owen Taylor3473f882001-02-23 17:55:21 +00003445 * xmlNodeGetBase:
3446 * @doc: the document the node pertains to
3447 * @cur: the node being checked
3448 *
3449 * Searches for the BASE URL. The code should work on both XML
3450 * and HTML document even if base mechanisms are completely different.
3451 * It returns the base as defined in RFC 2396 sections
3452 * 5.1.1. Base URI within Document Content
3453 * and
3454 * 5.1.2. Base URI from the Encapsulating Entity
3455 * However it does not return the document base (5.1.3), use
3456 * xmlDocumentGetBase() for this
3457 *
3458 * Returns a pointer to the base URL, or NULL if not found
3459 * It's up to the caller to free the memory.
3460 */
3461xmlChar *
3462xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003463 xmlChar *oldbase = NULL;
3464 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003465
3466 if ((cur == NULL) && (doc == NULL))
3467 return(NULL);
3468 if (doc == NULL) doc = cur->doc;
3469 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3470 cur = doc->children;
3471 while ((cur != NULL) && (cur->name != NULL)) {
3472 if (cur->type != XML_ELEMENT_NODE) {
3473 cur = cur->next;
3474 continue;
3475 }
3476 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3477 cur = cur->children;
3478 continue;
3479 }
3480 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3481 cur = cur->children;
3482 continue;
3483 }
3484 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3485 return(xmlGetProp(cur, BAD_CAST "href"));
3486 }
3487 cur = cur->next;
3488 }
3489 return(NULL);
3490 }
3491 while (cur != NULL) {
3492 if (cur->type == XML_ENTITY_DECL) {
3493 xmlEntityPtr ent = (xmlEntityPtr) cur;
3494 return(xmlStrdup(ent->URI));
3495 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003496 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003497 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003498 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003499 if (oldbase != NULL) {
3500 newbase = xmlBuildURI(oldbase, base);
3501 if (newbase != NULL) {
3502 xmlFree(oldbase);
3503 xmlFree(base);
3504 oldbase = newbase;
3505 } else {
3506 xmlFree(oldbase);
3507 xmlFree(base);
3508 return(NULL);
3509 }
3510 } else {
3511 oldbase = base;
3512 }
3513 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3514 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3515 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3516 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003517 }
3518 }
Owen Taylor3473f882001-02-23 17:55:21 +00003519 cur = cur->parent;
3520 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003521 if ((doc != NULL) && (doc->URL != NULL)) {
3522 if (oldbase == NULL)
3523 return(xmlStrdup(doc->URL));
3524 newbase = xmlBuildURI(oldbase, doc->URL);
3525 xmlFree(oldbase);
3526 return(newbase);
3527 }
3528 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003529}
3530
3531/**
3532 * xmlNodeGetContent:
3533 * @cur: the node being read
3534 *
3535 * Read the value of a node, this can be either the text carried
3536 * directly by this node if it's a TEXT node or the aggregate string
3537 * of the values carried by this node child's (TEXT and ENTITY_REF).
3538 * Entity references are substitued.
3539 * Returns a new xmlChar * or NULL if no content is available.
3540 * It's up to the caller to free the memory.
3541 */
3542xmlChar *
3543xmlNodeGetContent(xmlNodePtr cur) {
3544 if (cur == NULL) return(NULL);
3545 switch (cur->type) {
3546 case XML_DOCUMENT_FRAG_NODE:
3547 case XML_ELEMENT_NODE: {
3548 xmlNodePtr tmp = cur;
3549 xmlBufferPtr buffer;
3550 xmlChar *ret;
3551
3552 buffer = xmlBufferCreate();
3553 if (buffer == NULL)
3554 return(NULL);
3555 while (tmp != NULL) {
3556 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003557 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003558 case XML_TEXT_NODE:
3559 if (tmp->content != NULL)
3560#ifndef XML_USE_BUFFER_CONTENT
3561 xmlBufferCat(buffer, tmp->content);
3562#else
3563 xmlBufferCat(buffer,
3564 xmlBufferContent(tmp->content));
3565#endif
3566 break;
3567 case XML_ENTITY_REF_NODE: {
3568 xmlEntityPtr ent;
3569
3570 ent = xmlGetDocEntity(cur->doc, tmp->name);
3571 if (ent != NULL)
3572 xmlBufferCat(buffer, ent->content);
3573 }
3574 default:
3575 break;
3576 }
3577 /*
3578 * Skip to next node
3579 */
3580 if (tmp->children != NULL) {
3581 if (tmp->children->type != XML_ENTITY_DECL) {
3582 tmp = tmp->children;
3583 continue;
3584 }
3585 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003586 if (tmp == cur)
3587 break;
3588
Owen Taylor3473f882001-02-23 17:55:21 +00003589 if (tmp->next != NULL) {
3590 tmp = tmp->next;
3591 continue;
3592 }
3593
3594 do {
3595 tmp = tmp->parent;
3596 if (tmp == NULL)
3597 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003598 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003599 tmp = NULL;
3600 break;
3601 }
3602 if (tmp->next != NULL) {
3603 tmp = tmp->next;
3604 break;
3605 }
3606 } while (tmp != NULL);
3607 }
3608 ret = buffer->content;
3609 buffer->content = NULL;
3610 xmlBufferFree(buffer);
3611 return(ret);
3612 }
3613 case XML_ATTRIBUTE_NODE: {
3614 xmlAttrPtr attr = (xmlAttrPtr) cur;
3615 if (attr->parent != NULL)
3616 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3617 else
3618 return(xmlNodeListGetString(NULL, attr->children, 1));
3619 break;
3620 }
3621 case XML_COMMENT_NODE:
3622 case XML_PI_NODE:
3623 if (cur->content != NULL)
3624#ifndef XML_USE_BUFFER_CONTENT
3625 return(xmlStrdup(cur->content));
3626#else
3627 return(xmlStrdup(xmlBufferContent(cur->content)));
3628#endif
3629 return(NULL);
3630 case XML_ENTITY_REF_NODE:
3631 /*
3632 * Locate the entity, and get it's content
3633 * @@@
3634 */
3635 return(NULL);
3636 case XML_ENTITY_NODE:
3637 case XML_DOCUMENT_NODE:
3638 case XML_HTML_DOCUMENT_NODE:
3639 case XML_DOCUMENT_TYPE_NODE:
3640 case XML_NOTATION_NODE:
3641 case XML_DTD_NODE:
3642 case XML_XINCLUDE_START:
3643 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003644#ifdef LIBXML_DOCB_ENABLED
3645 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003646#endif
3647 return(NULL);
3648 case XML_NAMESPACE_DECL:
3649 return(xmlStrdup(((xmlNsPtr)cur)->href));
3650 case XML_ELEMENT_DECL:
3651 /* TODO !!! */
3652 return(NULL);
3653 case XML_ATTRIBUTE_DECL:
3654 /* TODO !!! */
3655 return(NULL);
3656 case XML_ENTITY_DECL:
3657 /* TODO !!! */
3658 return(NULL);
3659 case XML_CDATA_SECTION_NODE:
3660 case XML_TEXT_NODE:
3661 if (cur->content != NULL)
3662#ifndef XML_USE_BUFFER_CONTENT
3663 return(xmlStrdup(cur->content));
3664#else
3665 return(xmlStrdup(xmlBufferContent(cur->content)));
3666#endif
3667 return(NULL);
3668 }
3669 return(NULL);
3670}
3671
3672/**
3673 * xmlNodeSetContent:
3674 * @cur: the node being modified
3675 * @content: the new value of the content
3676 *
3677 * Replace the content of a node.
3678 */
3679void
3680xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3681 if (cur == NULL) {
3682#ifdef DEBUG_TREE
3683 xmlGenericError(xmlGenericErrorContext,
3684 "xmlNodeSetContent : node == NULL\n");
3685#endif
3686 return;
3687 }
3688 switch (cur->type) {
3689 case XML_DOCUMENT_FRAG_NODE:
3690 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003691 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3692 cur->children = xmlStringGetNodeList(cur->doc, content);
3693 UPDATE_LAST_CHILD_AND_PARENT(cur)
3694 break;
3695 case XML_ATTRIBUTE_NODE:
3696 break;
3697 case XML_TEXT_NODE:
3698 case XML_CDATA_SECTION_NODE:
3699 case XML_ENTITY_REF_NODE:
3700 case XML_ENTITY_NODE:
3701 case XML_PI_NODE:
3702 case XML_COMMENT_NODE:
3703 if (cur->content != NULL) {
3704#ifndef XML_USE_BUFFER_CONTENT
3705 xmlFree(cur->content);
3706#else
3707 xmlBufferFree(cur->content);
3708#endif
3709 }
3710 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3711 cur->last = cur->children = NULL;
3712 if (content != NULL) {
3713#ifndef XML_USE_BUFFER_CONTENT
3714 cur->content = xmlStrdup(content);
3715#else
3716 cur->content = xmlBufferCreateSize(0);
3717 xmlBufferSetAllocationScheme(cur->content,
3718 xmlGetBufferAllocationScheme());
3719 xmlBufferAdd(cur->content, content, -1);
3720#endif
3721 } else
3722 cur->content = NULL;
3723 break;
3724 case XML_DOCUMENT_NODE:
3725 case XML_HTML_DOCUMENT_NODE:
3726 case XML_DOCUMENT_TYPE_NODE:
3727 case XML_XINCLUDE_START:
3728 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003729#ifdef LIBXML_DOCB_ENABLED
3730 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003731#endif
3732 break;
3733 case XML_NOTATION_NODE:
3734 break;
3735 case XML_DTD_NODE:
3736 break;
3737 case XML_NAMESPACE_DECL:
3738 break;
3739 case XML_ELEMENT_DECL:
3740 /* TODO !!! */
3741 break;
3742 case XML_ATTRIBUTE_DECL:
3743 /* TODO !!! */
3744 break;
3745 case XML_ENTITY_DECL:
3746 /* TODO !!! */
3747 break;
3748 }
3749}
3750
3751/**
3752 * xmlNodeSetContentLen:
3753 * @cur: the node being modified
3754 * @content: the new value of the content
3755 * @len: the size of @content
3756 *
3757 * Replace the content of a node.
3758 */
3759void
3760xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3761 if (cur == NULL) {
3762#ifdef DEBUG_TREE
3763 xmlGenericError(xmlGenericErrorContext,
3764 "xmlNodeSetContentLen : node == NULL\n");
3765#endif
3766 return;
3767 }
3768 switch (cur->type) {
3769 case XML_DOCUMENT_FRAG_NODE:
3770 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003771 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3772 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3773 UPDATE_LAST_CHILD_AND_PARENT(cur)
3774 break;
3775 case XML_ATTRIBUTE_NODE:
3776 break;
3777 case XML_TEXT_NODE:
3778 case XML_CDATA_SECTION_NODE:
3779 case XML_ENTITY_REF_NODE:
3780 case XML_ENTITY_NODE:
3781 case XML_PI_NODE:
3782 case XML_COMMENT_NODE:
3783 case XML_NOTATION_NODE:
3784 if (cur->content != NULL) {
3785#ifndef XML_USE_BUFFER_CONTENT
3786 xmlFree(cur->content);
3787#else
3788 xmlBufferFree(cur->content);
3789#endif
3790 }
3791 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3792 cur->children = cur->last = NULL;
3793 if (content != NULL) {
3794#ifndef XML_USE_BUFFER_CONTENT
3795 cur->content = xmlStrndup(content, len);
3796#else
3797 cur->content = xmlBufferCreateSize(len);
3798 xmlBufferSetAllocationScheme(cur->content,
3799 xmlGetBufferAllocationScheme());
3800 xmlBufferAdd(cur->content, content, len);
3801#endif
3802 } else
3803 cur->content = NULL;
3804 break;
3805 case XML_DOCUMENT_NODE:
3806 case XML_DTD_NODE:
3807 case XML_HTML_DOCUMENT_NODE:
3808 case XML_DOCUMENT_TYPE_NODE:
3809 case XML_NAMESPACE_DECL:
3810 case XML_XINCLUDE_START:
3811 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003812#ifdef LIBXML_DOCB_ENABLED
3813 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003814#endif
3815 break;
3816 case XML_ELEMENT_DECL:
3817 /* TODO !!! */
3818 break;
3819 case XML_ATTRIBUTE_DECL:
3820 /* TODO !!! */
3821 break;
3822 case XML_ENTITY_DECL:
3823 /* TODO !!! */
3824 break;
3825 }
3826}
3827
3828/**
3829 * xmlNodeAddContentLen:
3830 * @cur: the node being modified
3831 * @content: extra content
3832 * @len: the size of @content
3833 *
3834 * Append the extra substring to the node content.
3835 */
3836void
3837xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3838 if (cur == NULL) {
3839#ifdef DEBUG_TREE
3840 xmlGenericError(xmlGenericErrorContext,
3841 "xmlNodeAddContentLen : node == NULL\n");
3842#endif
3843 return;
3844 }
3845 if (len <= 0) return;
3846 switch (cur->type) {
3847 case XML_DOCUMENT_FRAG_NODE:
3848 case XML_ELEMENT_NODE: {
Daniel Veillard7db37732001-07-12 01:20:08 +00003849 xmlNodePtr last, newNode;
Owen Taylor3473f882001-02-23 17:55:21 +00003850
Daniel Veillard7db37732001-07-12 01:20:08 +00003851 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003852 newNode = xmlNewTextLen(content, len);
3853 if (newNode != NULL) {
3854 xmlAddChild(cur, newNode);
3855 if ((last != NULL) && (last->next == newNode)) {
3856 xmlTextMerge(last, newNode);
3857 }
3858 }
3859 break;
3860 }
3861 case XML_ATTRIBUTE_NODE:
3862 break;
3863 case XML_TEXT_NODE:
3864 case XML_CDATA_SECTION_NODE:
3865 case XML_ENTITY_REF_NODE:
3866 case XML_ENTITY_NODE:
3867 case XML_PI_NODE:
3868 case XML_COMMENT_NODE:
3869 case XML_NOTATION_NODE:
3870 if (content != NULL) {
3871#ifndef XML_USE_BUFFER_CONTENT
3872 cur->content = xmlStrncat(cur->content, content, len);
3873#else
3874 xmlBufferAdd(cur->content, content, len);
3875#endif
3876 }
3877 case XML_DOCUMENT_NODE:
3878 case XML_DTD_NODE:
3879 case XML_HTML_DOCUMENT_NODE:
3880 case XML_DOCUMENT_TYPE_NODE:
3881 case XML_NAMESPACE_DECL:
3882 case XML_XINCLUDE_START:
3883 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003884#ifdef LIBXML_DOCB_ENABLED
3885 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003886#endif
3887 break;
3888 case XML_ELEMENT_DECL:
3889 case XML_ATTRIBUTE_DECL:
3890 case XML_ENTITY_DECL:
3891 break;
3892 }
3893}
3894
3895/**
3896 * xmlNodeAddContent:
3897 * @cur: the node being modified
3898 * @content: extra content
3899 *
3900 * Append the extra substring to the node content.
3901 */
3902void
3903xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3904 int len;
3905
3906 if (cur == NULL) {
3907#ifdef DEBUG_TREE
3908 xmlGenericError(xmlGenericErrorContext,
3909 "xmlNodeAddContent : node == NULL\n");
3910#endif
3911 return;
3912 }
3913 if (content == NULL) return;
3914 len = xmlStrlen(content);
3915 xmlNodeAddContentLen(cur, content, len);
3916}
3917
3918/**
3919 * xmlTextMerge:
3920 * @first: the first text node
3921 * @second: the second text node being merged
3922 *
3923 * Merge two text nodes into one
3924 * Returns the first text node augmented
3925 */
3926xmlNodePtr
3927xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3928 if (first == NULL) return(second);
3929 if (second == NULL) return(first);
3930 if (first->type != XML_TEXT_NODE) return(first);
3931 if (second->type != XML_TEXT_NODE) return(first);
3932 if (second->name != first->name)
3933 return(first);
3934#ifndef XML_USE_BUFFER_CONTENT
3935 xmlNodeAddContent(first, second->content);
3936#else
3937 xmlNodeAddContent(first, xmlBufferContent(second->content));
3938#endif
3939 xmlUnlinkNode(second);
3940 xmlFreeNode(second);
3941 return(first);
3942}
3943
3944/**
3945 * xmlGetNsList:
3946 * @doc: the document
3947 * @node: the current node
3948 *
3949 * Search all the namespace applying to a given element.
3950 * Returns an NULL terminated array of all the xmlNsPtr found
3951 * that need to be freed by the caller or NULL if no
3952 * namespace if defined
3953 */
3954xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003955xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3956{
Owen Taylor3473f882001-02-23 17:55:21 +00003957 xmlNsPtr cur;
3958 xmlNsPtr *ret = NULL;
3959 int nbns = 0;
3960 int maxns = 10;
3961 int i;
3962
3963 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00003964 if (node->type == XML_ELEMENT_NODE) {
3965 cur = node->nsDef;
3966 while (cur != NULL) {
3967 if (ret == NULL) {
3968 ret =
3969 (xmlNsPtr *) xmlMalloc((maxns + 1) *
3970 sizeof(xmlNsPtr));
3971 if (ret == NULL) {
3972 xmlGenericError(xmlGenericErrorContext,
3973 "xmlGetNsList : out of memory!\n");
3974 return (NULL);
3975 }
3976 ret[nbns] = NULL;
3977 }
3978 for (i = 0; i < nbns; i++) {
3979 if ((cur->prefix == ret[i]->prefix) ||
3980 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
3981 break;
3982 }
3983 if (i >= nbns) {
3984 if (nbns >= maxns) {
3985 maxns *= 2;
3986 ret = (xmlNsPtr *) xmlRealloc(ret,
3987 (maxns +
3988 1) *
3989 sizeof(xmlNsPtr));
3990 if (ret == NULL) {
3991 xmlGenericError(xmlGenericErrorContext,
3992 "xmlGetNsList : realloc failed!\n");
3993 return (NULL);
3994 }
3995 }
3996 ret[nbns++] = cur;
3997 ret[nbns] = NULL;
3998 }
Owen Taylor3473f882001-02-23 17:55:21 +00003999
Daniel Veillard77044732001-06-29 21:31:07 +00004000 cur = cur->next;
4001 }
4002 }
4003 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004004 }
Daniel Veillard77044732001-06-29 21:31:07 +00004005 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004006}
4007
4008/**
4009 * xmlSearchNs:
4010 * @doc: the document
4011 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004012 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004013 *
4014 * Search a Ns registered under a given name space for a document.
4015 * recurse on the parents until it finds the defined namespace
4016 * or return NULL otherwise.
4017 * @nameSpace can be NULL, this is a search for the default namespace.
4018 * We don't allow to cross entities boundaries. If you don't declare
4019 * the namespace within those you will be in troubles !!! A warning
4020 * is generated to cover this case.
4021 *
4022 * Returns the namespace pointer or NULL.
4023 */
4024xmlNsPtr
4025xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4026 xmlNsPtr cur;
4027
4028 if (node == NULL) return(NULL);
4029 if ((nameSpace != NULL) &&
4030 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
4031 if (doc->oldNs == NULL) {
4032 /*
4033 * Allocate a new Namespace and fill the fields.
4034 */
4035 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4036 if (doc->oldNs == NULL) {
4037 xmlGenericError(xmlGenericErrorContext,
4038 "xmlSearchNsByHref : malloc failed\n");
4039 return(NULL);
4040 }
4041 memset(doc->oldNs, 0, sizeof(xmlNs));
4042 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4043
4044 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4045 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4046 }
4047 return(doc->oldNs);
4048 }
4049 while (node != NULL) {
4050 if ((node->type == XML_ENTITY_REF_NODE) ||
4051 (node->type == XML_ENTITY_NODE) ||
4052 (node->type == XML_ENTITY_DECL))
4053 return(NULL);
4054 if (node->type == XML_ELEMENT_NODE) {
4055 cur = node->nsDef;
4056 while (cur != NULL) {
4057 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4058 (cur->href != NULL))
4059 return(cur);
4060 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4061 (cur->href != NULL) &&
4062 (xmlStrEqual(cur->prefix, nameSpace)))
4063 return(cur);
4064 cur = cur->next;
4065 }
4066 }
4067 node = node->parent;
4068 }
4069 return(NULL);
4070}
4071
4072/**
4073 * xmlSearchNsByHref:
4074 * @doc: the document
4075 * @node: the current node
4076 * @href: the namespace value
4077 *
4078 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4079 * the defined namespace or return NULL otherwise.
4080 * Returns the namespace pointer or NULL.
4081 */
4082xmlNsPtr
4083xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4084 xmlNsPtr cur;
4085 xmlNodePtr orig = node;
4086
4087 if ((node == NULL) || (href == NULL)) return(NULL);
4088 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
4089 if (doc->oldNs == NULL) {
4090 /*
4091 * Allocate a new Namespace and fill the fields.
4092 */
4093 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4094 if (doc->oldNs == NULL) {
4095 xmlGenericError(xmlGenericErrorContext,
4096 "xmlSearchNsByHref : malloc failed\n");
4097 return(NULL);
4098 }
4099 memset(doc->oldNs, 0, sizeof(xmlNs));
4100 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4101
4102 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4103 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4104 }
4105 return(doc->oldNs);
4106 }
4107 while (node != NULL) {
4108 cur = node->nsDef;
4109 while (cur != NULL) {
4110 if ((cur->href != NULL) && (href != NULL) &&
4111 (xmlStrEqual(cur->href, href))) {
4112 /*
4113 * Check that the prefix is not shadowed between orig and node
4114 */
4115 xmlNodePtr check = orig;
4116 xmlNsPtr tst;
4117
4118 while (check != node) {
4119 tst = check->nsDef;
4120 while (tst != NULL) {
4121 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4122 goto shadowed;
4123 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4124 (xmlStrEqual(tst->prefix, cur->prefix)))
4125 goto shadowed;
4126 tst = tst->next;
4127 }
4128 check = check->parent;
4129 }
4130 return(cur);
4131 }
4132shadowed:
4133 cur = cur->next;
4134 }
4135 node = node->parent;
4136 }
4137 return(NULL);
4138}
4139
4140/**
4141 * xmlNewReconciliedNs
4142 * @doc: the document
4143 * @tree: a node expected to hold the new namespace
4144 * @ns: the original namespace
4145 *
4146 * This function tries to locate a namespace definition in a tree
4147 * ancestors, or create a new namespace definition node similar to
4148 * @ns trying to reuse the same prefix. However if the given prefix is
4149 * null (default namespace) or reused within the subtree defined by
4150 * @tree or on one of its ancestors then a new prefix is generated.
4151 * Returns the (new) namespace definition or NULL in case of error
4152 */
4153xmlNsPtr
4154xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4155 xmlNsPtr def;
4156 xmlChar prefix[50];
4157 int counter = 1;
4158
4159 if (tree == NULL) {
4160#ifdef DEBUG_TREE
4161 xmlGenericError(xmlGenericErrorContext,
4162 "xmlNewReconciliedNs : tree == NULL\n");
4163#endif
4164 return(NULL);
4165 }
4166 if (ns == NULL) {
4167#ifdef DEBUG_TREE
4168 xmlGenericError(xmlGenericErrorContext,
4169 "xmlNewReconciliedNs : ns == NULL\n");
4170#endif
4171 return(NULL);
4172 }
4173 /*
4174 * Search an existing namespace definition inherited.
4175 */
4176 def = xmlSearchNsByHref(doc, tree, ns->href);
4177 if (def != NULL)
4178 return(def);
4179
4180 /*
4181 * Find a close prefix which is not already in use.
4182 * Let's strip namespace prefixes longer than 20 chars !
4183 */
4184 sprintf((char *) prefix, "%.20s", ns->prefix);
4185 def = xmlSearchNs(doc, tree, prefix);
4186 while (def != NULL) {
4187 if (counter > 1000) return(NULL);
4188 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4189 def = xmlSearchNs(doc, tree, prefix);
4190 }
4191
4192 /*
4193 * Ok, now we are ready to create a new one.
4194 */
4195 def = xmlNewNs(tree, ns->href, prefix);
4196 return(def);
4197}
4198
4199/**
4200 * xmlReconciliateNs
4201 * @doc: the document
4202 * @tree: a node defining the subtree to reconciliate
4203 *
4204 * This function checks that all the namespaces declared within the given
4205 * tree are properly declared. This is needed for example after Copy or Cut
4206 * and then paste operations. The subtree may still hold pointers to
4207 * namespace declarations outside the subtree or invalid/masked. As much
4208 * as possible the function try tu reuse the existing namespaces found in
4209 * the new environment. If not possible the new namespaces are redeclared
4210 * on @tree at the top of the given subtree.
4211 * Returns the number of namespace declarations created or -1 in case of error.
4212 */
4213int
4214xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4215 xmlNsPtr *oldNs = NULL;
4216 xmlNsPtr *newNs = NULL;
4217 int sizeCache = 0;
4218 int nbCache = 0;
4219
4220 xmlNsPtr n;
4221 xmlNodePtr node = tree;
4222 xmlAttrPtr attr;
4223 int ret = 0, i;
4224
4225 while (node != NULL) {
4226 /*
4227 * Reconciliate the node namespace
4228 */
4229 if (node->ns != NULL) {
4230 /*
4231 * initialize the cache if needed
4232 */
4233 if (sizeCache == 0) {
4234 sizeCache = 10;
4235 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4236 sizeof(xmlNsPtr));
4237 if (oldNs == NULL) {
4238 xmlGenericError(xmlGenericErrorContext,
4239 "xmlReconciliateNs : memory pbm\n");
4240 return(-1);
4241 }
4242 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4243 sizeof(xmlNsPtr));
4244 if (newNs == NULL) {
4245 xmlGenericError(xmlGenericErrorContext,
4246 "xmlReconciliateNs : memory pbm\n");
4247 xmlFree(oldNs);
4248 return(-1);
4249 }
4250 }
4251 for (i = 0;i < nbCache;i++) {
4252 if (oldNs[i] == node->ns) {
4253 node->ns = newNs[i];
4254 break;
4255 }
4256 }
4257 if (i == nbCache) {
4258 /*
4259 * Ok we need to recreate a new namespace definition
4260 */
4261 n = xmlNewReconciliedNs(doc, tree, node->ns);
4262 if (n != NULL) { /* :-( what if else ??? */
4263 /*
4264 * check if we need to grow the cache buffers.
4265 */
4266 if (sizeCache <= nbCache) {
4267 sizeCache *= 2;
4268 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4269 sizeof(xmlNsPtr));
4270 if (oldNs == NULL) {
4271 xmlGenericError(xmlGenericErrorContext,
4272 "xmlReconciliateNs : memory pbm\n");
4273 xmlFree(newNs);
4274 return(-1);
4275 }
4276 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4277 sizeof(xmlNsPtr));
4278 if (newNs == NULL) {
4279 xmlGenericError(xmlGenericErrorContext,
4280 "xmlReconciliateNs : memory pbm\n");
4281 xmlFree(oldNs);
4282 return(-1);
4283 }
4284 }
4285 newNs[nbCache] = n;
4286 oldNs[nbCache++] = node->ns;
4287 node->ns = n;
4288 }
4289 }
4290 }
4291 /*
4292 * now check for namespace hold by attributes on the node.
4293 */
4294 attr = node->properties;
4295 while (attr != NULL) {
4296 if (attr->ns != NULL) {
4297 /*
4298 * initialize the cache if needed
4299 */
4300 if (sizeCache == 0) {
4301 sizeCache = 10;
4302 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4303 sizeof(xmlNsPtr));
4304 if (oldNs == NULL) {
4305 xmlGenericError(xmlGenericErrorContext,
4306 "xmlReconciliateNs : memory pbm\n");
4307 return(-1);
4308 }
4309 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4310 sizeof(xmlNsPtr));
4311 if (newNs == NULL) {
4312 xmlGenericError(xmlGenericErrorContext,
4313 "xmlReconciliateNs : memory pbm\n");
4314 xmlFree(oldNs);
4315 return(-1);
4316 }
4317 }
4318 for (i = 0;i < nbCache;i++) {
4319 if (oldNs[i] == attr->ns) {
4320 node->ns = newNs[i];
4321 break;
4322 }
4323 }
4324 if (i == nbCache) {
4325 /*
4326 * Ok we need to recreate a new namespace definition
4327 */
4328 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4329 if (n != NULL) { /* :-( what if else ??? */
4330 /*
4331 * check if we need to grow the cache buffers.
4332 */
4333 if (sizeCache <= nbCache) {
4334 sizeCache *= 2;
4335 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4336 sizeof(xmlNsPtr));
4337 if (oldNs == NULL) {
4338 xmlGenericError(xmlGenericErrorContext,
4339 "xmlReconciliateNs : memory pbm\n");
4340 xmlFree(newNs);
4341 return(-1);
4342 }
4343 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4344 sizeof(xmlNsPtr));
4345 if (newNs == NULL) {
4346 xmlGenericError(xmlGenericErrorContext,
4347 "xmlReconciliateNs : memory pbm\n");
4348 xmlFree(oldNs);
4349 return(-1);
4350 }
4351 }
4352 newNs[nbCache] = n;
4353 oldNs[nbCache++] = attr->ns;
4354 attr->ns = n;
4355 }
4356 }
4357 }
4358 attr = attr->next;
4359 }
4360
4361 /*
4362 * Browse the full subtree, deep first
4363 */
4364 if (node->children != NULL) {
4365 /* deep first */
4366 node = node->children;
4367 } else if ((node != tree) && (node->next != NULL)) {
4368 /* then siblings */
4369 node = node->next;
4370 } else if (node != tree) {
4371 /* go up to parents->next if needed */
4372 while (node != tree) {
4373 if (node->parent != NULL)
4374 node = node->parent;
4375 if ((node != tree) && (node->next != NULL)) {
4376 node = node->next;
4377 break;
4378 }
4379 if (node->parent == NULL) {
4380 node = NULL;
4381 break;
4382 }
4383 }
4384 /* exit condition */
4385 if (node == tree)
4386 node = NULL;
4387 }
4388 }
4389 return(ret);
4390}
4391
4392/**
4393 * xmlHasProp:
4394 * @node: the node
4395 * @name: the attribute name
4396 *
4397 * Search an attribute associated to a node
4398 * This function also looks in DTD attribute declaration for #FIXED or
4399 * default declaration values unless DTD use has been turned off.
4400 *
4401 * Returns the attribute or the attribute declaration or NULL if
4402 * neither was found.
4403 */
4404xmlAttrPtr
4405xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4406 xmlAttrPtr prop;
4407 xmlDocPtr doc;
4408
4409 if ((node == NULL) || (name == NULL)) return(NULL);
4410 /*
4411 * Check on the properties attached to the node
4412 */
4413 prop = node->properties;
4414 while (prop != NULL) {
4415 if (xmlStrEqual(prop->name, name)) {
4416 return(prop);
4417 }
4418 prop = prop->next;
4419 }
4420 if (!xmlCheckDTD) return(NULL);
4421
4422 /*
4423 * Check if there is a default declaration in the internal
4424 * or external subsets
4425 */
4426 doc = node->doc;
4427 if (doc != NULL) {
4428 xmlAttributePtr attrDecl;
4429 if (doc->intSubset != NULL) {
4430 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4431 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4432 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4433 if (attrDecl != NULL)
4434 return((xmlAttrPtr) attrDecl);
4435 }
4436 }
4437 return(NULL);
4438}
4439
4440/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004441 * xmlHasNsProp:
4442 * @node: the node
4443 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004444 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004445 *
4446 * Search for an attribute associated to a node
4447 * This attribute has to be anchored in the namespace specified.
4448 * This does the entity substitution.
4449 * This function looks in DTD attribute declaration for #FIXED or
4450 * default declaration values unless DTD use has been turned off.
4451 *
4452 * Returns the attribute or the attribute declaration or NULL
4453 * if neither was found.
4454 */
4455xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004456xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004457 xmlAttrPtr prop;
4458 xmlDocPtr doc;
4459 xmlNsPtr ns;
4460
4461 if (node == NULL)
4462 return(NULL);
4463
4464 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004465 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004466 return(xmlHasProp(node, name));
4467 while (prop != NULL) {
4468 /*
4469 * One need to have
4470 * - same attribute names
4471 * - and the attribute carrying that namespace
4472 * or
4473 * no namespace on the attribute and the element carrying it
4474 */
4475 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004476 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4477 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004478 }
4479 prop = prop->next;
4480 }
4481 if (!xmlCheckDTD) return(NULL);
4482
4483 /*
4484 * Check if there is a default declaration in the internal
4485 * or external subsets
4486 */
4487 doc = node->doc;
4488 if (doc != NULL) {
4489 if (doc->intSubset != NULL) {
4490 xmlAttributePtr attrDecl;
4491
4492 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4493 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4494 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4495
4496 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4497 /*
4498 * The DTD declaration only allows a prefix search
4499 */
4500 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004501 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004502 return((xmlAttrPtr) attrDecl);
4503 }
4504 }
4505 }
4506 return(NULL);
4507}
4508
4509/**
Owen Taylor3473f882001-02-23 17:55:21 +00004510 * xmlGetProp:
4511 * @node: the node
4512 * @name: the attribute name
4513 *
4514 * Search and get the value of an attribute associated to a node
4515 * This does the entity substitution.
4516 * This function looks in DTD attribute declaration for #FIXED or
4517 * default declaration values unless DTD use has been turned off.
4518 *
4519 * Returns the attribute value or NULL if not found.
4520 * It's up to the caller to free the memory.
4521 */
4522xmlChar *
4523xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4524 xmlAttrPtr prop;
4525 xmlDocPtr doc;
4526
4527 if ((node == NULL) || (name == NULL)) return(NULL);
4528 /*
4529 * Check on the properties attached to the node
4530 */
4531 prop = node->properties;
4532 while (prop != NULL) {
4533 if (xmlStrEqual(prop->name, name)) {
4534 xmlChar *ret;
4535
4536 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4537 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4538 return(ret);
4539 }
4540 prop = prop->next;
4541 }
4542 if (!xmlCheckDTD) return(NULL);
4543
4544 /*
4545 * Check if there is a default declaration in the internal
4546 * or external subsets
4547 */
4548 doc = node->doc;
4549 if (doc != NULL) {
4550 xmlAttributePtr attrDecl;
4551 if (doc->intSubset != NULL) {
4552 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4553 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4554 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4555 if (attrDecl != NULL)
4556 return(xmlStrdup(attrDecl->defaultValue));
4557 }
4558 }
4559 return(NULL);
4560}
4561
4562/**
4563 * xmlGetNsProp:
4564 * @node: the node
4565 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004566 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004567 *
4568 * Search and get the value of an attribute associated to a node
4569 * This attribute has to be anchored in the namespace specified.
4570 * This does the entity substitution.
4571 * This function looks in DTD attribute declaration for #FIXED or
4572 * default declaration values unless DTD use has been turned off.
4573 *
4574 * Returns the attribute value or NULL if not found.
4575 * It's up to the caller to free the memory.
4576 */
4577xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004578xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004579 xmlAttrPtr prop;
4580 xmlDocPtr doc;
4581 xmlNsPtr ns;
4582
4583 if (node == NULL)
4584 return(NULL);
4585
4586 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004587 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004588 return(xmlGetProp(node, name));
4589 while (prop != NULL) {
4590 /*
4591 * One need to have
4592 * - same attribute names
4593 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004594 */
4595 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004596 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004597 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004598 xmlChar *ret;
4599
4600 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4601 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4602 return(ret);
4603 }
4604 prop = prop->next;
4605 }
4606 if (!xmlCheckDTD) return(NULL);
4607
4608 /*
4609 * Check if there is a default declaration in the internal
4610 * or external subsets
4611 */
4612 doc = node->doc;
4613 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004614 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004615 xmlAttributePtr attrDecl;
4616
Owen Taylor3473f882001-02-23 17:55:21 +00004617 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4618 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4619 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4620
4621 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4622 /*
4623 * The DTD declaration only allows a prefix search
4624 */
4625 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004626 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004627 return(xmlStrdup(attrDecl->defaultValue));
4628 }
4629 }
4630 }
4631 return(NULL);
4632}
4633
4634/**
4635 * xmlSetProp:
4636 * @node: the node
4637 * @name: the attribute name
4638 * @value: the attribute value
4639 *
4640 * Set (or reset) an attribute carried by a node.
4641 * Returns the attribute pointer.
4642 */
4643xmlAttrPtr
4644xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004645 xmlAttrPtr prop;
4646 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004647
4648 if ((node == NULL) || (name == NULL))
4649 return(NULL);
4650 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004651 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004652 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004653 if ((xmlStrEqual(prop->name, name)) &&
4654 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004655 xmlNodePtr oldprop = prop->children;
4656
Owen Taylor3473f882001-02-23 17:55:21 +00004657 prop->children = NULL;
4658 prop->last = NULL;
4659 if (value != NULL) {
4660 xmlChar *buffer;
4661 xmlNodePtr tmp;
4662
4663 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4664 prop->children = xmlStringGetNodeList(node->doc, buffer);
4665 prop->last = NULL;
4666 prop->doc = doc;
4667 tmp = prop->children;
4668 while (tmp != NULL) {
4669 tmp->parent = (xmlNodePtr) prop;
4670 tmp->doc = doc;
4671 if (tmp->next == NULL)
4672 prop->last = tmp;
4673 tmp = tmp->next;
4674 }
4675 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004676 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004677 if (oldprop != NULL)
4678 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004679 return(prop);
4680 }
4681 prop = prop->next;
4682 }
4683 prop = xmlNewProp(node, name, value);
4684 return(prop);
4685}
4686
4687/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004688 * xmlUnsetProp:
4689 * @node: the node
4690 * @name: the attribute name
4691 *
4692 * Remove an attribute carried by a node.
4693 * Returns 0 if successful, -1 if not found
4694 */
4695int
4696xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4697 xmlAttrPtr prop = node->properties, prev = NULL;;
4698
4699 if ((node == NULL) || (name == NULL))
4700 return(-1);
4701 while (prop != NULL) {
4702 if ((xmlStrEqual(prop->name, name)) &&
4703 (prop->ns == NULL)) {
4704 if (prev == NULL)
4705 node->properties = prop->next;
4706 else
4707 prev->next = prop->next;
4708 xmlFreeProp(prop);
4709 return(0);
4710 }
4711 prev = prop;
4712 prop = prop->next;
4713 }
4714 return(-1);
4715}
4716
4717/**
Owen Taylor3473f882001-02-23 17:55:21 +00004718 * xmlSetNsProp:
4719 * @node: the node
4720 * @ns: the namespace definition
4721 * @name: the attribute name
4722 * @value: the attribute value
4723 *
4724 * Set (or reset) an attribute carried by a node.
4725 * The ns structure must be in scope, this is not checked.
4726 *
4727 * Returns the attribute pointer.
4728 */
4729xmlAttrPtr
4730xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4731 const xmlChar *value) {
4732 xmlAttrPtr prop;
4733
4734 if ((node == NULL) || (name == NULL))
4735 return(NULL);
4736
4737 if (ns == NULL)
4738 return(xmlSetProp(node, name, value));
4739 if (ns->href == NULL)
4740 return(NULL);
4741 prop = node->properties;
4742
4743 while (prop != NULL) {
4744 /*
4745 * One need to have
4746 * - same attribute names
4747 * - and the attribute carrying that namespace
4748 * or
4749 * no namespace on the attribute and the element carrying it
4750 */
4751 if ((xmlStrEqual(prop->name, name)) &&
4752 (((prop->ns == NULL) && (node->ns != NULL) &&
4753 (xmlStrEqual(node->ns->href, ns->href))) ||
4754 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4755 if (prop->children != NULL)
4756 xmlFreeNodeList(prop->children);
4757 prop->children = NULL;
4758 prop->last = NULL;
4759 prop->ns = ns;
4760 if (value != NULL) {
4761 xmlChar *buffer;
4762 xmlNodePtr tmp;
4763
4764 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4765 prop->children = xmlStringGetNodeList(node->doc, buffer);
4766 prop->last = NULL;
4767 tmp = prop->children;
4768 while (tmp != NULL) {
4769 tmp->parent = (xmlNodePtr) prop;
4770 if (tmp->next == NULL)
4771 prop->last = tmp;
4772 tmp = tmp->next;
4773 }
4774 xmlFree(buffer);
4775 }
4776 return(prop);
4777 }
4778 prop = prop->next;
4779 }
4780 prop = xmlNewNsProp(node, ns, name, value);
4781 return(prop);
4782}
4783
4784/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004785 * xmlUnsetNsProp:
4786 * @node: the node
4787 * @ns: the namespace definition
4788 * @name: the attribute name
4789 *
4790 * Remove an attribute carried by a node.
4791 * Returns 0 if successful, -1 if not found
4792 */
4793int
4794xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4795 xmlAttrPtr prop = node->properties, prev = NULL;;
4796
4797 if ((node == NULL) || (name == NULL))
4798 return(-1);
4799 if (ns == NULL)
4800 return(xmlUnsetProp(node, name));
4801 if (ns->href == NULL)
4802 return(-1);
4803 while (prop != NULL) {
4804 if ((xmlStrEqual(prop->name, name)) &&
4805 (((prop->ns == NULL) && (node->ns != NULL) &&
4806 (xmlStrEqual(node->ns->href, ns->href))) ||
4807 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4808 if (prev == NULL)
4809 node->properties = prop->next;
4810 else
4811 prev->next = prop->next;
4812 xmlFreeProp(prop);
4813 return(0);
4814 }
4815 prev = prop;
4816 prop = prop->next;
4817 }
4818 return(-1);
4819}
4820
4821/**
Owen Taylor3473f882001-02-23 17:55:21 +00004822 * xmlNodeIsText:
4823 * @node: the node
4824 *
4825 * Is this node a Text node ?
4826 * Returns 1 yes, 0 no
4827 */
4828int
4829xmlNodeIsText(xmlNodePtr node) {
4830 if (node == NULL) return(0);
4831
4832 if (node->type == XML_TEXT_NODE) return(1);
4833 return(0);
4834}
4835
4836/**
4837 * xmlIsBlankNode:
4838 * @node: the node
4839 *
4840 * Checks whether this node is an empty or whitespace only
4841 * (and possibly ignorable) text-node.
4842 *
4843 * Returns 1 yes, 0 no
4844 */
4845int
4846xmlIsBlankNode(xmlNodePtr node) {
4847 const xmlChar *cur;
4848 if (node == NULL) return(0);
4849
Daniel Veillard7db37732001-07-12 01:20:08 +00004850 if ((node->type != XML_TEXT_NODE) &&
4851 (node->type != XML_CDATA_SECTION_NODE))
4852 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004853 if (node->content == NULL) return(1);
4854#ifndef XML_USE_BUFFER_CONTENT
4855 cur = node->content;
4856#else
4857 cur = xmlBufferContent(node->content);
4858#endif
4859 while (*cur != 0) {
4860 if (!IS_BLANK(*cur)) return(0);
4861 cur++;
4862 }
4863
4864 return(1);
4865}
4866
4867/**
4868 * xmlTextConcat:
4869 * @node: the node
4870 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00004871 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00004872 *
4873 * Concat the given string at the end of the existing node content
4874 */
4875
4876void
4877xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4878 if (node == NULL) return;
4879
4880 if ((node->type != XML_TEXT_NODE) &&
4881 (node->type != XML_CDATA_SECTION_NODE)) {
4882#ifdef DEBUG_TREE
4883 xmlGenericError(xmlGenericErrorContext,
4884 "xmlTextConcat: node is not text nor cdata\n");
4885#endif
4886 return;
4887 }
4888#ifndef XML_USE_BUFFER_CONTENT
4889 node->content = xmlStrncat(node->content, content, len);
4890#else
4891 xmlBufferAdd(node->content, content, len);
4892#endif
4893}
4894
4895/************************************************************************
4896 * *
4897 * Output : to a FILE or in memory *
4898 * *
4899 ************************************************************************/
4900
Owen Taylor3473f882001-02-23 17:55:21 +00004901/**
4902 * xmlBufferCreate:
4903 *
4904 * routine to create an XML buffer.
4905 * returns the new structure.
4906 */
4907xmlBufferPtr
4908xmlBufferCreate(void) {
4909 xmlBufferPtr ret;
4910
4911 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4912 if (ret == NULL) {
4913 xmlGenericError(xmlGenericErrorContext,
4914 "xmlBufferCreate : out of memory!\n");
4915 return(NULL);
4916 }
4917 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004918 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004919 ret->alloc = xmlBufferAllocScheme;
4920 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4921 if (ret->content == NULL) {
4922 xmlGenericError(xmlGenericErrorContext,
4923 "xmlBufferCreate : out of memory!\n");
4924 xmlFree(ret);
4925 return(NULL);
4926 }
4927 ret->content[0] = 0;
4928 return(ret);
4929}
4930
4931/**
4932 * xmlBufferCreateSize:
4933 * @size: initial size of buffer
4934 *
4935 * routine to create an XML buffer.
4936 * returns the new structure.
4937 */
4938xmlBufferPtr
4939xmlBufferCreateSize(size_t size) {
4940 xmlBufferPtr ret;
4941
4942 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4943 if (ret == NULL) {
4944 xmlGenericError(xmlGenericErrorContext,
4945 "xmlBufferCreate : out of memory!\n");
4946 return(NULL);
4947 }
4948 ret->use = 0;
4949 ret->alloc = xmlBufferAllocScheme;
4950 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4951 if (ret->size){
4952 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4953 if (ret->content == NULL) {
4954 xmlGenericError(xmlGenericErrorContext,
4955 "xmlBufferCreate : out of memory!\n");
4956 xmlFree(ret);
4957 return(NULL);
4958 }
4959 ret->content[0] = 0;
4960 } else
4961 ret->content = NULL;
4962 return(ret);
4963}
4964
4965/**
4966 * xmlBufferSetAllocationScheme:
4967 * @buf: the buffer to free
4968 * @scheme: allocation scheme to use
4969 *
4970 * Sets the allocation scheme for this buffer
4971 */
4972void
4973xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4974 xmlBufferAllocationScheme scheme) {
4975 if (buf == NULL) {
4976#ifdef DEBUG_BUFFER
4977 xmlGenericError(xmlGenericErrorContext,
4978 "xmlBufferSetAllocationScheme: buf == NULL\n");
4979#endif
4980 return;
4981 }
4982
4983 buf->alloc = scheme;
4984}
4985
4986/**
4987 * xmlBufferFree:
4988 * @buf: the buffer to free
4989 *
4990 * Frees an XML buffer.
4991 */
4992void
4993xmlBufferFree(xmlBufferPtr buf) {
4994 if (buf == NULL) {
4995#ifdef DEBUG_BUFFER
4996 xmlGenericError(xmlGenericErrorContext,
4997 "xmlBufferFree: buf == NULL\n");
4998#endif
4999 return;
5000 }
5001 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005002 xmlFree(buf->content);
5003 }
Owen Taylor3473f882001-02-23 17:55:21 +00005004 xmlFree(buf);
5005}
5006
5007/**
5008 * xmlBufferEmpty:
5009 * @buf: the buffer
5010 *
5011 * empty a buffer.
5012 */
5013void
5014xmlBufferEmpty(xmlBufferPtr buf) {
5015 if (buf->content == NULL) return;
5016 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005017 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005018}
5019
5020/**
5021 * xmlBufferShrink:
5022 * @buf: the buffer to dump
5023 * @len: the number of xmlChar to remove
5024 *
5025 * Remove the beginning of an XML buffer.
5026 *
5027 * Returns the number of xmlChar removed, or -1 in case of failure.
5028 */
5029int
5030xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5031 if (len == 0) return(0);
5032 if (len > buf->use) return(-1);
5033
5034 buf->use -= len;
5035 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5036
5037 buf->content[buf->use] = 0;
5038 return(len);
5039}
5040
5041/**
5042 * xmlBufferGrow:
5043 * @buf: the buffer
5044 * @len: the minimum free size to allocate
5045 *
5046 * Grow the available space of an XML buffer.
5047 *
5048 * Returns the new available space or -1 in case of error
5049 */
5050int
5051xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5052 int size;
5053 xmlChar *newbuf;
5054
5055 if (len + buf->use < buf->size) return(0);
5056
5057 size = buf->use + len + 100;
5058
5059 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5060 if (newbuf == NULL) return(-1);
5061 buf->content = newbuf;
5062 buf->size = size;
5063 return(buf->size - buf->use);
5064}
5065
5066/**
5067 * xmlBufferDump:
5068 * @file: the file output
5069 * @buf: the buffer to dump
5070 *
5071 * Dumps an XML buffer to a FILE *.
5072 * Returns the number of xmlChar written
5073 */
5074int
5075xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5076 int ret;
5077
5078 if (buf == NULL) {
5079#ifdef DEBUG_BUFFER
5080 xmlGenericError(xmlGenericErrorContext,
5081 "xmlBufferDump: buf == NULL\n");
5082#endif
5083 return(0);
5084 }
5085 if (buf->content == NULL) {
5086#ifdef DEBUG_BUFFER
5087 xmlGenericError(xmlGenericErrorContext,
5088 "xmlBufferDump: buf->content == NULL\n");
5089#endif
5090 return(0);
5091 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005092 if (file == NULL)
5093 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005094 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5095 return(ret);
5096}
5097
5098/**
5099 * xmlBufferContent:
5100 * @buf: the buffer
5101 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005102 * Function to extract the content of a buffer
5103 *
Owen Taylor3473f882001-02-23 17:55:21 +00005104 * Returns the internal content
5105 */
5106
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005107const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005108xmlBufferContent(const xmlBufferPtr buf)
5109{
5110 if(!buf)
5111 return NULL;
5112
5113 return buf->content;
5114}
5115
5116/**
5117 * xmlBufferLength:
5118 * @buf: the buffer
5119 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005120 * Function to get the length of a buffer
5121 *
Owen Taylor3473f882001-02-23 17:55:21 +00005122 * Returns the length of data in the internal content
5123 */
5124
5125int
5126xmlBufferLength(const xmlBufferPtr buf)
5127{
5128 if(!buf)
5129 return 0;
5130
5131 return buf->use;
5132}
5133
5134/**
5135 * xmlBufferResize:
5136 * @buf: the buffer to resize
5137 * @size: the desired size
5138 *
5139 * Resize a buffer to accomodate minimum size of @size.
5140 *
5141 * Returns 0 in case of problems, 1 otherwise
5142 */
5143int
5144xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5145{
5146 unsigned int newSize;
5147 xmlChar* rebuf = NULL;
5148
5149 /*take care of empty case*/
5150 newSize = (buf->size ? buf->size*2 : size);
5151
5152 /* Don't resize if we don't have to */
5153 if (size < buf->size)
5154 return 1;
5155
5156 /* figure out new size */
5157 switch (buf->alloc){
5158 case XML_BUFFER_ALLOC_DOUBLEIT:
5159 while (size > newSize) newSize *= 2;
5160 break;
5161 case XML_BUFFER_ALLOC_EXACT:
5162 newSize = size+10;
5163 break;
5164 default:
5165 newSize = size+10;
5166 break;
5167 }
5168
5169 if (buf->content == NULL)
5170 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5171 else
5172 rebuf = (xmlChar *) xmlRealloc(buf->content,
5173 newSize * sizeof(xmlChar));
5174 if (rebuf == NULL) {
5175 xmlGenericError(xmlGenericErrorContext,
5176 "xmlBufferAdd : out of memory!\n");
5177 return 0;
5178 }
5179 buf->content = rebuf;
5180 buf->size = newSize;
5181
5182 return 1;
5183}
5184
5185/**
5186 * xmlBufferAdd:
5187 * @buf: the buffer to dump
5188 * @str: the xmlChar string
5189 * @len: the number of xmlChar to add
5190 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005191 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005192 * str is recomputed.
5193 */
5194void
5195xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5196 unsigned int needSize;
5197
5198 if (str == NULL) {
5199#ifdef DEBUG_BUFFER
5200 xmlGenericError(xmlGenericErrorContext,
5201 "xmlBufferAdd: str == NULL\n");
5202#endif
5203 return;
5204 }
5205 if (len < -1) {
5206#ifdef DEBUG_BUFFER
5207 xmlGenericError(xmlGenericErrorContext,
5208 "xmlBufferAdd: len < 0\n");
5209#endif
5210 return;
5211 }
5212 if (len == 0) return;
5213
5214 if (len < 0)
5215 len = xmlStrlen(str);
5216
5217 if (len <= 0) return;
5218
5219 needSize = buf->use + len + 2;
5220 if (needSize > buf->size){
5221 if (!xmlBufferResize(buf, needSize)){
5222 xmlGenericError(xmlGenericErrorContext,
5223 "xmlBufferAdd : out of memory!\n");
5224 return;
5225 }
5226 }
5227
5228 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5229 buf->use += len;
5230 buf->content[buf->use] = 0;
5231}
5232
5233/**
5234 * xmlBufferAddHead:
5235 * @buf: the buffer
5236 * @str: the xmlChar string
5237 * @len: the number of xmlChar to add
5238 *
5239 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005240 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005241 */
5242void
5243xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5244 unsigned int needSize;
5245
5246 if (str == NULL) {
5247#ifdef DEBUG_BUFFER
5248 xmlGenericError(xmlGenericErrorContext,
5249 "xmlBufferAdd: str == NULL\n");
5250#endif
5251 return;
5252 }
5253 if (len < -1) {
5254#ifdef DEBUG_BUFFER
5255 xmlGenericError(xmlGenericErrorContext,
5256 "xmlBufferAdd: len < 0\n");
5257#endif
5258 return;
5259 }
5260 if (len == 0) return;
5261
5262 if (len < 0)
5263 len = xmlStrlen(str);
5264
5265 if (len <= 0) return;
5266
5267 needSize = buf->use + len + 2;
5268 if (needSize > buf->size){
5269 if (!xmlBufferResize(buf, needSize)){
5270 xmlGenericError(xmlGenericErrorContext,
5271 "xmlBufferAddHead : out of memory!\n");
5272 return;
5273 }
5274 }
5275
5276 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5277 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5278 buf->use += len;
5279 buf->content[buf->use] = 0;
5280}
5281
5282/**
5283 * xmlBufferCat:
5284 * @buf: the buffer to dump
5285 * @str: the xmlChar string
5286 *
5287 * Append a zero terminated string to an XML buffer.
5288 */
5289void
5290xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5291 if (str != NULL)
5292 xmlBufferAdd(buf, str, -1);
5293}
5294
5295/**
5296 * xmlBufferCCat:
5297 * @buf: the buffer to dump
5298 * @str: the C char string
5299 *
5300 * Append a zero terminated C string to an XML buffer.
5301 */
5302void
5303xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5304 const char *cur;
5305
5306 if (str == NULL) {
5307#ifdef DEBUG_BUFFER
5308 xmlGenericError(xmlGenericErrorContext,
5309 "xmlBufferAdd: str == NULL\n");
5310#endif
5311 return;
5312 }
5313 for (cur = str;*cur != 0;cur++) {
5314 if (buf->use + 10 >= buf->size) {
5315 if (!xmlBufferResize(buf, buf->use+10)){
5316 xmlGenericError(xmlGenericErrorContext,
5317 "xmlBufferCCat : out of memory!\n");
5318 return;
5319 }
5320 }
5321 buf->content[buf->use++] = *cur;
5322 }
5323 buf->content[buf->use] = 0;
5324}
5325
5326/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005327 * xmlBufferWriteXmlCHAR:
5328 * @buf: the XML buffer
5329 * @string: the string to add
5330 *
5331 * For VMS only.
5332 * routine which manages and grows an output buffer. This one adds
5333 * xmlChars at the end of the buffer.
5334 */
5335/**
Owen Taylor3473f882001-02-23 17:55:21 +00005336 * xmlBufferWriteCHAR:
5337 * @buf: the XML buffer
5338 * @string: the string to add
5339 *
5340 * routine which manages and grows an output buffer. This one adds
5341 * xmlChars at the end of the buffer.
5342 */
5343void
5344#ifdef VMS
5345xmlBufferWriteXmlCHAR
5346#else
5347xmlBufferWriteCHAR
5348#endif
5349(xmlBufferPtr buf, const xmlChar *string) {
5350 xmlBufferCat(buf, string);
5351}
5352
5353/**
5354 * xmlBufferWriteChar:
5355 * @buf: the XML buffer output
5356 * @string: the string to add
5357 *
5358 * routine which manage and grows an output buffer. This one add
5359 * C chars at the end of the array.
5360 */
5361void
5362xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5363 xmlBufferCCat(buf, string);
5364}
5365
5366
5367/**
5368 * xmlBufferWriteQuotedString:
5369 * @buf: the XML buffer output
5370 * @string: the string to add
5371 *
5372 * routine which manage and grows an output buffer. This one writes
5373 * a quoted or double quoted xmlChar string, checking first if it holds
5374 * quote or double-quotes internally
5375 */
5376void
5377xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5378 if (xmlStrchr(string, '"')) {
5379 if (xmlStrchr(string, '\'')) {
5380#ifdef DEBUG_BUFFER
5381 xmlGenericError(xmlGenericErrorContext,
5382 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5383#endif
5384 }
5385 xmlBufferCCat(buf, "'");
5386 xmlBufferCat(buf, string);
5387 xmlBufferCCat(buf, "'");
5388 } else {
5389 xmlBufferCCat(buf, "\"");
5390 xmlBufferCat(buf, string);
5391 xmlBufferCCat(buf, "\"");
5392 }
5393}
5394
5395
5396/************************************************************************
5397 * *
5398 * Dumping XML tree content to a simple buffer *
5399 * *
5400 ************************************************************************/
5401
5402void
5403xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5404 int format);
5405static void
5406xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5407 int format);
5408void
5409htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5410
5411/**
5412 * xmlNsDump:
5413 * @buf: the XML buffer output
5414 * @cur: a namespace
5415 *
5416 * Dump a local Namespace definition.
5417 * Should be called in the context of attributes dumps.
5418 */
5419static void
5420xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5421 if (cur == NULL) {
5422#ifdef DEBUG_TREE
5423 xmlGenericError(xmlGenericErrorContext,
5424 "xmlNsDump : Ns == NULL\n");
5425#endif
5426 return;
5427 }
5428 if (cur->type == XML_LOCAL_NAMESPACE) {
5429 /* Within the context of an element attributes */
5430 if (cur->prefix != NULL) {
5431 xmlBufferWriteChar(buf, " xmlns:");
5432 xmlBufferWriteCHAR(buf, cur->prefix);
5433 } else
5434 xmlBufferWriteChar(buf, " xmlns");
5435 xmlBufferWriteChar(buf, "=");
5436 xmlBufferWriteQuotedString(buf, cur->href);
5437 }
5438}
5439
5440/**
5441 * xmlNsListDump:
5442 * @buf: the XML buffer output
5443 * @cur: the first namespace
5444 *
5445 * Dump a list of local Namespace definitions.
5446 * Should be called in the context of attributes dumps.
5447 */
5448static void
5449xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5450 while (cur != NULL) {
5451 xmlNsDump(buf, cur);
5452 cur = cur->next;
5453 }
5454}
5455
5456/**
5457 * xmlDtdDump:
5458 * @buf: the XML buffer output
5459 * @doc: the document
5460 *
5461 * Dump the XML document DTD, if any.
5462 */
5463static void
5464xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5465 if (dtd == NULL) {
5466#ifdef DEBUG_TREE
5467 xmlGenericError(xmlGenericErrorContext,
5468 "xmlDtdDump : no internal subset\n");
5469#endif
5470 return;
5471 }
5472 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5473 xmlBufferWriteCHAR(buf, dtd->name);
5474 if (dtd->ExternalID != NULL) {
5475 xmlBufferWriteChar(buf, " PUBLIC ");
5476 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5477 xmlBufferWriteChar(buf, " ");
5478 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5479 } else if (dtd->SystemID != NULL) {
5480 xmlBufferWriteChar(buf, " SYSTEM ");
5481 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5482 }
5483 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5484 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5485 xmlBufferWriteChar(buf, ">");
5486 return;
5487 }
5488 xmlBufferWriteChar(buf, " [\n");
5489 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5490#if 0
5491 if (dtd->entities != NULL)
5492 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5493 if (dtd->notations != NULL)
5494 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5495 if (dtd->elements != NULL)
5496 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5497 if (dtd->attributes != NULL)
5498 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5499#endif
5500 xmlBufferWriteChar(buf, "]>");
5501}
5502
5503/**
5504 * xmlAttrDump:
5505 * @buf: the XML buffer output
5506 * @doc: the document
5507 * @cur: the attribute pointer
5508 *
5509 * Dump an XML attribute
5510 */
5511static void
5512xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5513 xmlChar *value;
5514
5515 if (cur == NULL) {
5516#ifdef DEBUG_TREE
5517 xmlGenericError(xmlGenericErrorContext,
5518 "xmlAttrDump : property == NULL\n");
5519#endif
5520 return;
5521 }
5522 xmlBufferWriteChar(buf, " ");
5523 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5524 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5525 xmlBufferWriteChar(buf, ":");
5526 }
5527 xmlBufferWriteCHAR(buf, cur->name);
5528 value = xmlNodeListGetString(doc, cur->children, 0);
5529 if (value != NULL) {
5530 xmlBufferWriteChar(buf, "=");
5531 xmlBufferWriteQuotedString(buf, value);
5532 xmlFree(value);
5533 } else {
5534 xmlBufferWriteChar(buf, "=\"\"");
5535 }
5536}
5537
5538/**
5539 * xmlAttrListDump:
5540 * @buf: the XML buffer output
5541 * @doc: the document
5542 * @cur: the first attribute pointer
5543 *
5544 * Dump a list of XML attributes
5545 */
5546static void
5547xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5548 if (cur == NULL) {
5549#ifdef DEBUG_TREE
5550 xmlGenericError(xmlGenericErrorContext,
5551 "xmlAttrListDump : property == NULL\n");
5552#endif
5553 return;
5554 }
5555 while (cur != NULL) {
5556 xmlAttrDump(buf, doc, cur);
5557 cur = cur->next;
5558 }
5559}
5560
5561
5562
5563/**
5564 * xmlNodeListDump:
5565 * @buf: the XML buffer output
5566 * @doc: the document
5567 * @cur: the first node
5568 * @level: the imbrication level for indenting
5569 * @format: is formatting allowed
5570 *
5571 * Dump an XML node list, recursive behaviour,children are printed too.
5572 */
5573static void
5574xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5575 int format) {
5576 int i;
5577
5578 if (cur == NULL) {
5579#ifdef DEBUG_TREE
5580 xmlGenericError(xmlGenericErrorContext,
5581 "xmlNodeListDump : node == NULL\n");
5582#endif
5583 return;
5584 }
5585 while (cur != NULL) {
5586 if ((format) && (xmlIndentTreeOutput) &&
5587 (cur->type == XML_ELEMENT_NODE))
5588 for (i = 0;i < level;i++)
5589 xmlBufferWriteChar(buf, " ");
5590 xmlNodeDump(buf, doc, cur, level, format);
5591 if (format) {
5592 xmlBufferWriteChar(buf, "\n");
5593 }
5594 cur = cur->next;
5595 }
5596}
5597
5598/**
5599 * xmlNodeDump:
5600 * @buf: the XML buffer output
5601 * @doc: the document
5602 * @cur: the current node
5603 * @level: the imbrication level for indenting
5604 * @format: is formatting allowed
5605 *
5606 * Dump an XML node, recursive behaviour,children are printed too.
5607 */
5608void
5609xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5610 int format) {
5611 int i;
5612 xmlNodePtr tmp;
5613
5614 if (cur == NULL) {
5615#ifdef DEBUG_TREE
5616 xmlGenericError(xmlGenericErrorContext,
5617 "xmlNodeDump : node == NULL\n");
5618#endif
5619 return;
5620 }
5621 if (cur->type == XML_XINCLUDE_START)
5622 return;
5623 if (cur->type == XML_XINCLUDE_END)
5624 return;
5625 if (cur->type == XML_DTD_NODE) {
5626 xmlDtdDump(buf, (xmlDtdPtr) cur);
5627 return;
5628 }
5629 if (cur->type == XML_ELEMENT_DECL) {
5630 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5631 return;
5632 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005633 if (cur->type == XML_ATTRIBUTE_NODE){
5634 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5635 return;
5636 }
Owen Taylor3473f882001-02-23 17:55:21 +00005637 if (cur->type == XML_ATTRIBUTE_DECL) {
5638 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5639 return;
5640 }
5641 if (cur->type == XML_ENTITY_DECL) {
5642 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5643 return;
5644 }
5645 if (cur->type == XML_TEXT_NODE) {
5646 if (cur->content != NULL) {
5647 if ((cur->name == xmlStringText) ||
5648 (cur->name != xmlStringTextNoenc)) {
5649 xmlChar *buffer;
5650
5651#ifndef XML_USE_BUFFER_CONTENT
5652 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5653#else
5654 buffer = xmlEncodeEntitiesReentrant(doc,
5655 xmlBufferContent(cur->content));
5656#endif
5657 if (buffer != NULL) {
5658 xmlBufferWriteCHAR(buf, buffer);
5659 xmlFree(buffer);
5660 }
5661 } else {
5662 /*
5663 * Disable escaping, needed for XSLT
5664 */
5665#ifndef XML_USE_BUFFER_CONTENT
5666 xmlBufferWriteCHAR(buf, cur->content);
5667#else
5668 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5669#endif
5670 }
5671 }
5672 return;
5673 }
5674 if (cur->type == XML_PI_NODE) {
5675 if (cur->content != NULL) {
5676 xmlBufferWriteChar(buf, "<?");
5677 xmlBufferWriteCHAR(buf, cur->name);
5678 if (cur->content != NULL) {
5679 xmlBufferWriteChar(buf, " ");
5680#ifndef XML_USE_BUFFER_CONTENT
5681 xmlBufferWriteCHAR(buf, cur->content);
5682#else
5683 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5684#endif
5685 }
5686 xmlBufferWriteChar(buf, "?>");
5687 } else {
5688 xmlBufferWriteChar(buf, "<?");
5689 xmlBufferWriteCHAR(buf, cur->name);
5690 xmlBufferWriteChar(buf, "?>");
5691 }
5692 return;
5693 }
5694 if (cur->type == XML_COMMENT_NODE) {
5695 if (cur->content != NULL) {
5696 xmlBufferWriteChar(buf, "<!--");
5697#ifndef XML_USE_BUFFER_CONTENT
5698 xmlBufferWriteCHAR(buf, cur->content);
5699#else
5700 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5701#endif
5702 xmlBufferWriteChar(buf, "-->");
5703 }
5704 return;
5705 }
5706 if (cur->type == XML_ENTITY_REF_NODE) {
5707 xmlBufferWriteChar(buf, "&");
5708 xmlBufferWriteCHAR(buf, cur->name);
5709 xmlBufferWriteChar(buf, ";");
5710 return;
5711 }
5712 if (cur->type == XML_CDATA_SECTION_NODE) {
5713 xmlBufferWriteChar(buf, "<![CDATA[");
5714 if (cur->content != NULL)
5715#ifndef XML_USE_BUFFER_CONTENT
5716 xmlBufferWriteCHAR(buf, cur->content);
5717#else
5718 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5719#endif
5720 xmlBufferWriteChar(buf, "]]>");
5721 return;
5722 }
5723
5724 if (format == 1) {
5725 tmp = cur->children;
5726 while (tmp != NULL) {
5727 if ((tmp->type == XML_TEXT_NODE) ||
5728 (tmp->type == XML_ENTITY_REF_NODE)) {
5729 format = 0;
5730 break;
5731 }
5732 tmp = tmp->next;
5733 }
5734 }
5735 xmlBufferWriteChar(buf, "<");
5736 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5737 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5738 xmlBufferWriteChar(buf, ":");
5739 }
5740
5741 xmlBufferWriteCHAR(buf, cur->name);
5742 if (cur->nsDef)
5743 xmlNsListDump(buf, cur->nsDef);
5744 if (cur->properties != NULL)
5745 xmlAttrListDump(buf, doc, cur->properties);
5746
Daniel Veillard7db37732001-07-12 01:20:08 +00005747 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5748 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005749 (!xmlSaveNoEmptyTags)) {
5750 xmlBufferWriteChar(buf, "/>");
5751 return;
5752 }
5753 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005754 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005755 xmlChar *buffer;
5756
5757#ifndef XML_USE_BUFFER_CONTENT
5758 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5759#else
5760 buffer = xmlEncodeEntitiesReentrant(doc,
5761 xmlBufferContent(cur->content));
5762#endif
5763 if (buffer != NULL) {
5764 xmlBufferWriteCHAR(buf, buffer);
5765 xmlFree(buffer);
5766 }
5767 }
5768 if (cur->children != NULL) {
5769 if (format) xmlBufferWriteChar(buf, "\n");
5770 xmlNodeListDump(buf, doc, cur->children,
5771 (level >= 0?level+1:-1), format);
5772 if ((xmlIndentTreeOutput) && (format))
5773 for (i = 0;i < level;i++)
5774 xmlBufferWriteChar(buf, " ");
5775 }
5776 xmlBufferWriteChar(buf, "</");
5777 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5778 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5779 xmlBufferWriteChar(buf, ":");
5780 }
5781
5782 xmlBufferWriteCHAR(buf, cur->name);
5783 xmlBufferWriteChar(buf, ">");
5784}
5785
5786/**
5787 * xmlElemDump:
5788 * @f: the FILE * for the output
5789 * @doc: the document
5790 * @cur: the current node
5791 *
5792 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5793 */
5794void
5795xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5796 xmlBufferPtr buf;
5797
5798 if (cur == NULL) {
5799#ifdef DEBUG_TREE
5800 xmlGenericError(xmlGenericErrorContext,
5801 "xmlElemDump : cur == NULL\n");
5802#endif
5803 return;
5804 }
Owen Taylor3473f882001-02-23 17:55:21 +00005805#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005806 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005807 xmlGenericError(xmlGenericErrorContext,
5808 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005809 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005810#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005811
Owen Taylor3473f882001-02-23 17:55:21 +00005812 buf = xmlBufferCreate();
5813 if (buf == NULL) return;
5814 if ((doc != NULL) &&
5815 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5816#ifdef LIBXML_HTML_ENABLED
5817 htmlNodeDump(buf, doc, cur);
5818#else
5819 xmlGenericError(xmlGenericErrorContext,
5820 "HTML support not compiled in\n");
5821#endif /* LIBXML_HTML_ENABLED */
5822 } else
5823 xmlNodeDump(buf, doc, cur, 0, 1);
5824 xmlBufferDump(f, buf);
5825 xmlBufferFree(buf);
5826}
5827
5828/************************************************************************
5829 * *
5830 * Dumping XML tree content to an I/O output buffer *
5831 * *
5832 ************************************************************************/
5833
5834void
5835xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5836 int level, int format, const char *encoding);
5837static void
5838xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5839 int level, int format, const char *encoding);
5840/**
5841 * xmlNsDumpOutput:
5842 * @buf: the XML buffer output
5843 * @cur: a namespace
5844 *
5845 * Dump a local Namespace definition.
5846 * Should be called in the context of attributes dumps.
5847 */
5848static void
5849xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5850 if (cur == NULL) {
5851#ifdef DEBUG_TREE
5852 xmlGenericError(xmlGenericErrorContext,
5853 "xmlNsDump : Ns == NULL\n");
5854#endif
5855 return;
5856 }
5857 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5858 /* Within the context of an element attributes */
5859 if (cur->prefix != NULL) {
5860 xmlOutputBufferWriteString(buf, " xmlns:");
5861 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5862 } else
5863 xmlOutputBufferWriteString(buf, " xmlns");
5864 xmlOutputBufferWriteString(buf, "=");
5865 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5866 }
5867}
5868
5869/**
5870 * xmlNsListDumpOutput:
5871 * @buf: the XML buffer output
5872 * @cur: the first namespace
5873 *
5874 * Dump a list of local Namespace definitions.
5875 * Should be called in the context of attributes dumps.
5876 */
5877static void
5878xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5879 while (cur != NULL) {
5880 xmlNsDumpOutput(buf, cur);
5881 cur = cur->next;
5882 }
5883}
5884
5885/**
5886 * xmlDtdDumpOutput:
5887 * @buf: the XML buffer output
5888 * @doc: the document
5889 * @encoding: an optional encoding string
5890 *
5891 * Dump the XML document DTD, if any.
5892 */
5893static void
5894xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5895 if (dtd == NULL) {
5896#ifdef DEBUG_TREE
5897 xmlGenericError(xmlGenericErrorContext,
5898 "xmlDtdDump : no internal subset\n");
5899#endif
5900 return;
5901 }
5902 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5903 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5904 if (dtd->ExternalID != NULL) {
5905 xmlOutputBufferWriteString(buf, " PUBLIC ");
5906 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5907 xmlOutputBufferWriteString(buf, " ");
5908 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5909 } else if (dtd->SystemID != NULL) {
5910 xmlOutputBufferWriteString(buf, " SYSTEM ");
5911 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5912 }
5913 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5914 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5915 xmlOutputBufferWriteString(buf, ">");
5916 return;
5917 }
5918 xmlOutputBufferWriteString(buf, " [\n");
5919 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5920 xmlOutputBufferWriteString(buf, "]>");
5921}
5922
5923/**
5924 * xmlAttrDumpOutput:
5925 * @buf: the XML buffer output
5926 * @doc: the document
5927 * @cur: the attribute pointer
5928 * @encoding: an optional encoding string
5929 *
5930 * Dump an XML attribute
5931 */
5932static void
5933xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005934 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005935 xmlChar *value;
5936
5937 if (cur == NULL) {
5938#ifdef DEBUG_TREE
5939 xmlGenericError(xmlGenericErrorContext,
5940 "xmlAttrDump : property == NULL\n");
5941#endif
5942 return;
5943 }
5944 xmlOutputBufferWriteString(buf, " ");
5945 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5946 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5947 xmlOutputBufferWriteString(buf, ":");
5948 }
5949 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5950 value = xmlNodeListGetString(doc, cur->children, 0);
5951 if (value) {
5952 xmlOutputBufferWriteString(buf, "=");
5953 xmlBufferWriteQuotedString(buf->buffer, value);
5954 xmlFree(value);
5955 } else {
5956 xmlOutputBufferWriteString(buf, "=\"\"");
5957 }
5958}
5959
5960/**
5961 * xmlAttrListDumpOutput:
5962 * @buf: the XML buffer output
5963 * @doc: the document
5964 * @cur: the first attribute pointer
5965 * @encoding: an optional encoding string
5966 *
5967 * Dump a list of XML attributes
5968 */
5969static void
5970xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5971 xmlAttrPtr cur, const char *encoding) {
5972 if (cur == NULL) {
5973#ifdef DEBUG_TREE
5974 xmlGenericError(xmlGenericErrorContext,
5975 "xmlAttrListDump : property == NULL\n");
5976#endif
5977 return;
5978 }
5979 while (cur != NULL) {
5980 xmlAttrDumpOutput(buf, doc, cur, encoding);
5981 cur = cur->next;
5982 }
5983}
5984
5985
5986
5987/**
5988 * xmlNodeListDumpOutput:
5989 * @buf: the XML buffer output
5990 * @doc: the document
5991 * @cur: the first node
5992 * @level: the imbrication level for indenting
5993 * @format: is formatting allowed
5994 * @encoding: an optional encoding string
5995 *
5996 * Dump an XML node list, recursive behaviour,children are printed too.
5997 */
5998static void
5999xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6000 xmlNodePtr cur, int level, int format, const char *encoding) {
6001 int i;
6002
6003 if (cur == NULL) {
6004#ifdef DEBUG_TREE
6005 xmlGenericError(xmlGenericErrorContext,
6006 "xmlNodeListDump : node == NULL\n");
6007#endif
6008 return;
6009 }
6010 while (cur != NULL) {
6011 if ((format) && (xmlIndentTreeOutput) &&
6012 (cur->type == XML_ELEMENT_NODE))
6013 for (i = 0;i < level;i++)
6014 xmlOutputBufferWriteString(buf, " ");
6015 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6016 if (format) {
6017 xmlOutputBufferWriteString(buf, "\n");
6018 }
6019 cur = cur->next;
6020 }
6021}
6022
6023/**
6024 * xmlNodeDumpOutput:
6025 * @buf: the XML buffer output
6026 * @doc: the document
6027 * @cur: the current node
6028 * @level: the imbrication level for indenting
6029 * @format: is formatting allowed
6030 * @encoding: an optional encoding string
6031 *
6032 * Dump an XML node, recursive behaviour,children are printed too.
6033 */
6034void
6035xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6036 int level, int format, const char *encoding) {
6037 int i;
6038 xmlNodePtr tmp;
6039
6040 if (cur == NULL) {
6041#ifdef DEBUG_TREE
6042 xmlGenericError(xmlGenericErrorContext,
6043 "xmlNodeDump : node == NULL\n");
6044#endif
6045 return;
6046 }
6047 if (cur->type == XML_XINCLUDE_START)
6048 return;
6049 if (cur->type == XML_XINCLUDE_END)
6050 return;
6051 if (cur->type == XML_DTD_NODE) {
6052 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6053 return;
6054 }
6055 if (cur->type == XML_ELEMENT_DECL) {
6056 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6057 return;
6058 }
6059 if (cur->type == XML_ATTRIBUTE_DECL) {
6060 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6061 return;
6062 }
6063 if (cur->type == XML_ENTITY_DECL) {
6064 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6065 return;
6066 }
6067 if (cur->type == XML_TEXT_NODE) {
6068 if (cur->content != NULL) {
6069 if ((cur->name == xmlStringText) ||
6070 (cur->name != xmlStringTextNoenc)) {
6071 xmlChar *buffer;
6072
6073#ifndef XML_USE_BUFFER_CONTENT
6074 if (encoding == NULL)
6075 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6076 else
6077 buffer = xmlEncodeSpecialChars(doc, cur->content);
6078#else
6079 if (encoding == NULL)
6080 buffer = xmlEncodeEntitiesReentrant(doc,
6081 xmlBufferContent(cur->content));
6082 else
6083 buffer = xmlEncodeSpecialChars(doc,
6084 xmlBufferContent(cur->content));
6085#endif
6086 if (buffer != NULL) {
6087 xmlOutputBufferWriteString(buf, (const char *)buffer);
6088 xmlFree(buffer);
6089 }
6090 } else {
6091 /*
6092 * Disable escaping, needed for XSLT
6093 */
6094#ifndef XML_USE_BUFFER_CONTENT
6095 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6096#else
6097 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6098#endif
6099 }
6100 }
6101
6102 return;
6103 }
6104 if (cur->type == XML_PI_NODE) {
6105 if (cur->content != NULL) {
6106 xmlOutputBufferWriteString(buf, "<?");
6107 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6108 if (cur->content != NULL) {
6109 xmlOutputBufferWriteString(buf, " ");
6110#ifndef XML_USE_BUFFER_CONTENT
6111 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6112#else
6113 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6114#endif
6115 }
6116 xmlOutputBufferWriteString(buf, "?>");
6117 } else {
6118 xmlOutputBufferWriteString(buf, "<?");
6119 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6120 xmlOutputBufferWriteString(buf, "?>");
6121 }
6122 return;
6123 }
6124 if (cur->type == XML_COMMENT_NODE) {
6125 if (cur->content != NULL) {
6126 xmlOutputBufferWriteString(buf, "<!--");
6127#ifndef XML_USE_BUFFER_CONTENT
6128 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6129#else
6130 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6131#endif
6132 xmlOutputBufferWriteString(buf, "-->");
6133 }
6134 return;
6135 }
6136 if (cur->type == XML_ENTITY_REF_NODE) {
6137 xmlOutputBufferWriteString(buf, "&");
6138 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6139 xmlOutputBufferWriteString(buf, ";");
6140 return;
6141 }
6142 if (cur->type == XML_CDATA_SECTION_NODE) {
6143 xmlOutputBufferWriteString(buf, "<![CDATA[");
6144 if (cur->content != NULL)
6145#ifndef XML_USE_BUFFER_CONTENT
6146 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6147#else
6148 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6149#endif
6150 xmlOutputBufferWriteString(buf, "]]>");
6151 return;
6152 }
6153
6154 if (format == 1) {
6155 tmp = cur->children;
6156 while (tmp != NULL) {
6157 if ((tmp->type == XML_TEXT_NODE) ||
6158 (tmp->type == XML_ENTITY_REF_NODE)) {
6159 format = 0;
6160 break;
6161 }
6162 tmp = tmp->next;
6163 }
6164 }
6165 xmlOutputBufferWriteString(buf, "<");
6166 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6167 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6168 xmlOutputBufferWriteString(buf, ":");
6169 }
6170
6171 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6172 if (cur->nsDef)
6173 xmlNsListDumpOutput(buf, cur->nsDef);
6174 if (cur->properties != NULL)
6175 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6176
Daniel Veillard7db37732001-07-12 01:20:08 +00006177 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6178 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006179 xmlOutputBufferWriteString(buf, "/>");
6180 return;
6181 }
6182 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006183 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006184 xmlChar *buffer;
6185
6186#ifndef XML_USE_BUFFER_CONTENT
6187 if (encoding == NULL)
6188 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6189 else
6190 buffer = xmlEncodeSpecialChars(doc, cur->content);
6191#else
6192 if (encoding == NULL)
6193 buffer = xmlEncodeEntitiesReentrant(doc,
6194 xmlBufferContent(cur->content));
6195 else
6196 buffer = xmlEncodeSpecialChars(doc,
6197 xmlBufferContent(cur->content));
6198#endif
6199 if (buffer != NULL) {
6200 xmlOutputBufferWriteString(buf, (const char *)buffer);
6201 xmlFree(buffer);
6202 }
6203 }
6204 if (cur->children != NULL) {
6205 if (format) xmlOutputBufferWriteString(buf, "\n");
6206 xmlNodeListDumpOutput(buf, doc, cur->children,
6207 (level >= 0?level+1:-1), format, encoding);
6208 if ((xmlIndentTreeOutput) && (format))
6209 for (i = 0;i < level;i++)
6210 xmlOutputBufferWriteString(buf, " ");
6211 }
6212 xmlOutputBufferWriteString(buf, "</");
6213 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6214 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6215 xmlOutputBufferWriteString(buf, ":");
6216 }
6217
6218 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6219 xmlOutputBufferWriteString(buf, ">");
6220}
6221
6222/**
6223 * xmlDocContentDumpOutput:
6224 * @buf: the XML buffer output
6225 * @cur: the document
6226 * @encoding: an optional encoding string
6227 * @format: should formatting spaces been added
6228 *
6229 * Dump an XML document.
6230 */
6231static void
6232xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6233 const char *encoding, int format) {
6234 xmlOutputBufferWriteString(buf, "<?xml version=");
6235 if (cur->version != NULL)
6236 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6237 else
6238 xmlOutputBufferWriteString(buf, "\"1.0\"");
6239 if (encoding == NULL) {
6240 if (cur->encoding != NULL)
6241 encoding = (const char *) cur->encoding;
6242 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6243 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6244 }
6245 if (encoding != NULL) {
6246 xmlOutputBufferWriteString(buf, " encoding=");
6247 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6248 }
6249 switch (cur->standalone) {
6250 case 0:
6251 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6252 break;
6253 case 1:
6254 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6255 break;
6256 }
6257 xmlOutputBufferWriteString(buf, "?>\n");
6258 if (cur->children != NULL) {
6259 xmlNodePtr child = cur->children;
6260
6261 while (child != NULL) {
6262 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6263 xmlOutputBufferWriteString(buf, "\n");
6264 child = child->next;
6265 }
6266 }
6267}
6268
6269/************************************************************************
6270 * *
6271 * Saving functions front-ends *
6272 * *
6273 ************************************************************************/
6274
6275/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006276 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006277 * @out_doc: Document to generate XML text from
6278 * @doc_txt_ptr: Memory pointer for allocated XML text
6279 * @doc_txt_len: Length of the generated XML text
6280 * @txt_encoding: Character encoding to use when generating XML text
6281 * @format: should formatting spaces been added
6282 *
6283 * Dump the current DOM tree into memory using the character encoding specified
6284 * by the caller. Note it is up to the caller of this function to free the
6285 * allocated memory.
6286 */
6287
6288void
6289xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006290 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006291 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006292 int dummy = 0;
6293
6294 xmlCharEncoding doc_charset;
6295 xmlOutputBufferPtr out_buff = NULL;
6296 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6297
6298 if (doc_txt_len == NULL) {
6299 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6300 }
6301
6302 if (doc_txt_ptr == NULL) {
6303 *doc_txt_len = 0;
6304 xmlGenericError(xmlGenericErrorContext,
6305 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6306 return;
6307 }
6308
6309 *doc_txt_ptr = NULL;
6310 *doc_txt_len = 0;
6311
6312 if (out_doc == NULL) {
6313 /* No document, no output */
6314 xmlGenericError(xmlGenericErrorContext,
6315 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6316 return;
6317 }
6318
6319 /*
6320 * Validate the encoding value, if provided.
6321 * This logic is copied from xmlSaveFileEnc.
6322 */
6323
6324 if (txt_encoding == NULL)
6325 txt_encoding = (const char *) out_doc->encoding;
6326 if (txt_encoding != NULL) {
6327 doc_charset = xmlParseCharEncoding(txt_encoding);
6328
6329 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6330 xmlGenericError(xmlGenericErrorContext,
6331 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6332 return;
6333
6334 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6335 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6336 if ( conv_hdlr == NULL ) {
6337 xmlGenericError(xmlGenericErrorContext,
6338 "%s: %s %s '%s'\n",
6339 "xmlDocDumpFormatMemoryEnc",
6340 "Failed to identify encoding handler for",
6341 "character set",
6342 txt_encoding);
6343 return;
6344 }
6345 }
6346 }
6347
6348 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6349 xmlGenericError(xmlGenericErrorContext,
6350 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6351 return;
6352 }
6353
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006354 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006355 xmlOutputBufferFlush(out_buff);
6356 if (out_buff->conv != NULL) {
6357 *doc_txt_len = out_buff->conv->use;
6358 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6359 } else {
6360 *doc_txt_len = out_buff->buffer->use;
6361 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6362 }
6363 (void)xmlOutputBufferClose(out_buff);
6364
6365 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6366 *doc_txt_len = 0;
6367 xmlGenericError(xmlGenericErrorContext,
6368 "xmlDocDumpFormatMemoryEnc: %s\n",
6369 "Failed to allocate memory for document text representation.");
6370 }
6371
6372 return;
6373}
6374
6375/**
6376 * xmlDocDumpMemory:
6377 * @cur: the document
6378 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006379 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006380 *
6381 * Dump an XML document in memory and return the xmlChar * and it's size.
6382 * It's up to the caller to free the memory.
6383 */
6384void
6385xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6386 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6387}
6388
6389/**
6390 * xmlDocDumpFormatMemory:
6391 * @cur: the document
6392 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006393 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006394 * @format: should formatting spaces been added
6395 *
6396 *
6397 * Dump an XML document in memory and return the xmlChar * and it's size.
6398 * It's up to the caller to free the memory.
6399 */
6400void
6401xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6402 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6403}
6404
6405/**
6406 * xmlDocDumpMemoryEnc:
6407 * @out_doc: Document to generate XML text from
6408 * @doc_txt_ptr: Memory pointer for allocated XML text
6409 * @doc_txt_len: Length of the generated XML text
6410 * @txt_encoding: Character encoding to use when generating XML text
6411 *
6412 * Dump the current DOM tree into memory using the character encoding specified
6413 * by the caller. Note it is up to the caller of this function to free the
6414 * allocated memory.
6415 */
6416
6417void
6418xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6419 int * doc_txt_len, const char * txt_encoding) {
6420 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006421 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006422}
6423
6424/**
6425 * xmlGetDocCompressMode:
6426 * @doc: the document
6427 *
6428 * get the compression ratio for a document, ZLIB based
6429 * Returns 0 (uncompressed) to 9 (max compression)
6430 */
6431int
6432xmlGetDocCompressMode (xmlDocPtr doc) {
6433 if (doc == NULL) return(-1);
6434 return(doc->compression);
6435}
6436
6437/**
6438 * xmlSetDocCompressMode:
6439 * @doc: the document
6440 * @mode: the compression ratio
6441 *
6442 * set the compression ratio for a document, ZLIB based
6443 * Correct values: 0 (uncompressed) to 9 (max compression)
6444 */
6445void
6446xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6447 if (doc == NULL) return;
6448 if (mode < 0) doc->compression = 0;
6449 else if (mode > 9) doc->compression = 9;
6450 else doc->compression = mode;
6451}
6452
6453/**
6454 * xmlGetCompressMode:
6455 *
6456 * get the default compression mode used, ZLIB based.
6457 * Returns 0 (uncompressed) to 9 (max compression)
6458 */
6459int
6460 xmlGetCompressMode(void) {
6461 return(xmlCompressMode);
6462}
6463
6464/**
6465 * xmlSetCompressMode:
6466 * @mode: the compression ratio
6467 *
6468 * set the default compression mode used, ZLIB based
6469 * Correct values: 0 (uncompressed) to 9 (max compression)
6470 */
6471void
6472xmlSetCompressMode(int mode) {
6473 if (mode < 0) xmlCompressMode = 0;
6474 else if (mode > 9) xmlCompressMode = 9;
6475 else xmlCompressMode = mode;
6476}
6477
6478/**
6479 * xmlDocDump:
6480 * @f: the FILE*
6481 * @cur: the document
6482 *
6483 * Dump an XML document to an open FILE.
6484 *
6485 * returns: the number of byte written or -1 in case of failure.
6486 */
6487int
6488xmlDocDump(FILE *f, xmlDocPtr cur) {
6489 xmlOutputBufferPtr buf;
6490 const char * encoding;
6491 xmlCharEncodingHandlerPtr handler = NULL;
6492 int ret;
6493
6494 if (cur == NULL) {
6495#ifdef DEBUG_TREE
6496 xmlGenericError(xmlGenericErrorContext,
6497 "xmlDocDump : document == NULL\n");
6498#endif
6499 return(-1);
6500 }
6501 encoding = (const char *) cur->encoding;
6502
6503 if (encoding != NULL) {
6504 xmlCharEncoding enc;
6505
6506 enc = xmlParseCharEncoding(encoding);
6507
6508 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6509 xmlGenericError(xmlGenericErrorContext,
6510 "xmlDocDump: document not in UTF8\n");
6511 return(-1);
6512 }
6513 if (enc != XML_CHAR_ENCODING_UTF8) {
6514 handler = xmlFindCharEncodingHandler(encoding);
6515 if (handler == NULL) {
6516 xmlFree((char *) cur->encoding);
6517 cur->encoding = NULL;
6518 }
6519 }
6520 }
6521 buf = xmlOutputBufferCreateFile(f, handler);
6522 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006523 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006524
6525 ret = xmlOutputBufferClose(buf);
6526 return(ret);
6527}
6528
6529/**
6530 * xmlSaveFileTo:
6531 * @buf: an output I/O buffer
6532 * @cur: the document
6533 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6534 *
6535 * Dump an XML document to an I/O buffer.
6536 *
6537 * returns: the number of byte written or -1 in case of failure.
6538 */
6539int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006540xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006541 int ret;
6542
6543 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006544 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006545 ret = xmlOutputBufferClose(buf);
6546 return(ret);
6547}
6548
6549/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006550 * xmlSaveFormatFileTo:
6551 * @buf: an output I/O buffer
6552 * @cur: the document
6553 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
6554 * @format: should formatting spaces been added
6555 *
6556 * Dump an XML document to an I/O buffer.
6557 *
6558 * returns: the number of byte written or -1 in case of failure.
6559 */
6560int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006561xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006562 int ret;
6563
6564 if (buf == NULL) return(0);
6565 xmlDocContentDumpOutput(buf, cur, encoding, format);
6566 ret = xmlOutputBufferClose(buf);
6567 return(ret);
6568}
6569
6570/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006571 * xmlSaveFormatFileEnc
6572 * @filename: the filename or URL to output
6573 * @cur: the document being saved
6574 * @encoding: the name of the encoding to use or NULL.
6575 * @format: should formatting spaces be added.
Owen Taylor3473f882001-02-23 17:55:21 +00006576 */
6577int
Daniel Veillardf012a642001-07-23 19:10:52 +00006578xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6579 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006580 xmlOutputBufferPtr buf;
6581 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006582 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006583 int ret;
6584
6585 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006586
6587 enc = xmlParseCharEncoding(encoding);
6588 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6589 xmlGenericError(xmlGenericErrorContext,
6590 "xmlSaveFileEnc: document not in UTF8\n");
6591 return(-1);
6592 }
6593 if (enc != XML_CHAR_ENCODING_UTF8) {
6594 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006595 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006596 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006597 }
6598 }
6599
Daniel Veillardf012a642001-07-23 19:10:52 +00006600#ifdef HAVE_ZLIB_H
6601 if (cur->compression < 0) cur->compression = xmlCompressMode;
6602#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006603 /*
6604 * save the content to a temp buffer.
6605 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006606 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006607 if (buf == NULL) return(-1);
6608
Daniel Veillardf012a642001-07-23 19:10:52 +00006609 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006610
6611 ret = xmlOutputBufferClose(buf);
6612 return(ret);
6613}
6614
Daniel Veillardf012a642001-07-23 19:10:52 +00006615
6616/**
6617 * xmlSaveFileEnc:
6618 * @filename: the filename (or URL)
6619 * @cur: the document
6620 * @encoding: the name of an encoding (or NULL)
6621 *
6622 * Dump an XML document, converting it to the given encoding
6623 *
6624 * returns: the number of byte written or -1 in case of failure.
6625 */
6626int
6627xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6628 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6629}
6630
Owen Taylor3473f882001-02-23 17:55:21 +00006631/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006632 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006633 * @filename: the filename (or URL)
6634 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006635 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006636 *
6637 * Dump an XML document to a file. Will use compression if
6638 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillard67fee942001-04-26 18:59:03 +00006639 * used. If format is set then the document will be indented on output.
6640 *
Owen Taylor3473f882001-02-23 17:55:21 +00006641 * returns: the number of byte written or -1 in case of failure.
6642 */
6643int
Daniel Veillard67fee942001-04-26 18:59:03 +00006644xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006645 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006646}
6647
Daniel Veillard67fee942001-04-26 18:59:03 +00006648/**
6649 * xmlSaveFile:
6650 * @filename: the filename (or URL)
6651 * @cur: the document
6652 *
6653 * Dump an XML document to a file. Will use compression if
6654 * compiled in and enabled. If @filename is "-" the stdout file is
6655 * used.
6656 * returns: the number of byte written or -1 in case of failure.
6657 */
6658int
6659xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006660 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006661}
6662