blob: b4ebf8b0aefefcf2db715db6310673c0180ebd3e [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
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.
Daniel Veillardd1640922001-12-17 15:30:10 +0000118 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000119 */
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,
Daniel Veillardd1640922001-12-17 15:30:10 +0000344 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000345 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 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000416 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000417 * 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
Owen Taylor3473f882001-02-23 17:55:21 +0000485 *
486 * Free up all the structures used by a document, tree included.
487 */
488void
489xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000490 xmlDtdPtr extSubset, intSubset;
491
Owen Taylor3473f882001-02-23 17:55:21 +0000492 if (cur == NULL) {
493#ifdef DEBUG_TREE
494 xmlGenericError(xmlGenericErrorContext,
495 "xmlFreeDoc : document == NULL\n");
496#endif
497 return;
498 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000499 /*
500 * Do this before freeing the children list to avoid ID lookups
501 */
502 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
503 cur->ids = NULL;
504 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
505 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000506 extSubset = cur->extSubset;
507 intSubset = cur->intSubset;
508 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000509 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000510 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000511 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000512 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000513 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000514 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000515 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000516 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000517 }
518
519 if (cur->children != NULL) xmlFreeNodeList(cur->children);
520
Owen Taylor3473f882001-02-23 17:55:21 +0000521 if (cur->version != NULL) xmlFree((char *) cur->version);
522 if (cur->name != NULL) xmlFree((char *) cur->name);
523 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000524 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000525 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000526 xmlFree(cur);
527}
528
529/**
530 * xmlStringLenGetNodeList:
531 * @doc: the document
532 * @value: the value of the text
533 * @len: the length of the string value
534 *
535 * Parse the value string and build the node list associated. Should
536 * produce a flat tree with only TEXTs and ENTITY_REFs.
537 * Returns a pointer to the first child
538 */
539xmlNodePtr
540xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
541 xmlNodePtr ret = NULL, last = NULL;
542 xmlNodePtr node;
543 xmlChar *val;
544 const xmlChar *cur = value;
545 const xmlChar *q;
546 xmlEntityPtr ent;
547
548 if (value == NULL) return(NULL);
549
550 q = cur;
551 while ((*cur != 0) && (cur - value < len)) {
552 if (*cur == '&') {
553 /*
554 * Save the current text.
555 */
556 if (cur != q) {
557 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
558 xmlNodeAddContentLen(last, q, cur - q);
559 } else {
560 node = xmlNewDocTextLen(doc, q, cur - q);
561 if (node == NULL) return(ret);
562 if (last == NULL)
563 last = ret = node;
564 else {
565 last->next = node;
566 node->prev = last;
567 last = node;
568 }
569 }
570 }
571 /*
572 * Read the entity string
573 */
574 cur++;
575 q = cur;
576 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
577 if ((*cur == 0) || (cur - value >= len)) {
578#ifdef DEBUG_TREE
579 xmlGenericError(xmlGenericErrorContext,
580 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
581#endif
582 return(ret);
583 }
584 if (cur != q) {
585 /*
586 * Predefined entities don't generate nodes
587 */
588 val = xmlStrndup(q, cur - q);
589 ent = xmlGetDocEntity(doc, val);
590 if ((ent != NULL) &&
591 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
592 if (last == NULL) {
593 node = xmlNewDocText(doc, ent->content);
594 last = ret = node;
595 } else
596 xmlNodeAddContent(last, ent->content);
597
598 } else {
599 /*
600 * Create a new REFERENCE_REF node
601 */
602 node = xmlNewReference(doc, val);
603 if (node == NULL) {
604 if (val != NULL) xmlFree(val);
605 return(ret);
606 }
607 if (last == NULL)
608 last = ret = node;
609 else {
610 last->next = node;
611 node->prev = last;
612 last = node;
613 }
614 }
615 xmlFree(val);
616 }
617 cur++;
618 q = cur;
619 } else
620 cur++;
621 }
622 if (cur != q) {
623 /*
624 * Handle the last piece of text.
625 */
626 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
627 xmlNodeAddContentLen(last, q, cur - q);
628 } else {
629 node = xmlNewDocTextLen(doc, q, cur - q);
630 if (node == NULL) return(ret);
631 if (last == NULL)
632 last = ret = node;
633 else {
634 last->next = node;
635 node->prev = last;
636 last = node;
637 }
638 }
639 }
640 return(ret);
641}
642
643/**
644 * xmlStringGetNodeList:
645 * @doc: the document
646 * @value: the value of the attribute
647 *
648 * Parse the value string and build the node list associated. Should
649 * produce a flat tree with only TEXTs and ENTITY_REFs.
650 * Returns a pointer to the first child
651 */
652xmlNodePtr
653xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
654 xmlNodePtr ret = NULL, last = NULL;
655 xmlNodePtr node;
656 xmlChar *val;
657 const xmlChar *cur = value;
658 const xmlChar *q;
659 xmlEntityPtr ent;
660
661 if (value == NULL) return(NULL);
662
663 q = cur;
664 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000665 if (cur[0] == '&') {
666 int charval = 0;
667 xmlChar tmp;
668
Owen Taylor3473f882001-02-23 17:55:21 +0000669 /*
670 * Save the current text.
671 */
672 if (cur != q) {
673 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
674 xmlNodeAddContentLen(last, q, cur - q);
675 } else {
676 node = xmlNewDocTextLen(doc, q, cur - q);
677 if (node == NULL) return(ret);
678 if (last == NULL)
679 last = ret = node;
680 else {
681 last->next = node;
682 node->prev = last;
683 last = node;
684 }
685 }
686 }
Owen Taylor3473f882001-02-23 17:55:21 +0000687 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000688 if ((cur[1] == '#') && (cur[2] == 'x')) {
689 cur += 3;
690 tmp = *cur;
691 while (tmp != ';') { /* Non input consuming loop */
692 if ((tmp >= '0') && (tmp <= '9'))
693 charval = charval * 16 + (tmp - '0');
694 else if ((tmp >= 'a') && (tmp <= 'f'))
695 charval = charval * 16 + (tmp - 'a') + 10;
696 else if ((tmp >= 'A') && (tmp <= 'F'))
697 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000698 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000699 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000700 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000701 charval = 0;
702 break;
703 }
704 cur++;
705 tmp = *cur;
706 }
707 if (tmp == ';')
708 cur++;
709 q = cur;
710 } else if (cur[1] == '#') {
711 cur += 2;
712 tmp = *cur;
713 while (tmp != ';') { /* Non input consuming loops */
714 if ((tmp >= '0') && (tmp <= '9'))
715 charval = charval * 10 + (tmp - '0');
716 else {
717 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000718 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000719 charval = 0;
720 break;
721 }
722 cur++;
723 tmp = *cur;
724 }
725 if (tmp == ';')
726 cur++;
727 q = cur;
728 } else {
729 /*
730 * Read the entity string
731 */
732 cur++;
733 q = cur;
734 while ((*cur != 0) && (*cur != ';')) cur++;
735 if (*cur == 0) {
736#ifdef DEBUG_TREE
737 xmlGenericError(xmlGenericErrorContext,
738 "xmlStringGetNodeList: unterminated entity %30s\n", q);
739#endif
740 return(ret);
741 }
742 if (cur != q) {
743 /*
744 * Predefined entities don't generate nodes
745 */
746 val = xmlStrndup(q, cur - q);
747 ent = xmlGetDocEntity(doc, val);
748 if ((ent != NULL) &&
749 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
750 if (last == NULL) {
751 node = xmlNewDocText(doc, ent->content);
752 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000753 } else if (last->type != XML_TEXT_NODE) {
754 node = xmlNewDocText(doc, ent->content);
755 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000756 } else
757 xmlNodeAddContent(last, ent->content);
758
759 } else {
760 /*
761 * Create a new REFERENCE_REF node
762 */
763 node = xmlNewReference(doc, val);
764 if (node == NULL) {
765 if (val != NULL) xmlFree(val);
766 return(ret);
767 }
768 if (last == NULL) {
769 last = ret = node;
770 } else {
771 last = xmlAddNextSibling(last, node);
772 }
773 }
774 xmlFree(val);
775 }
776 cur++;
777 q = cur;
778 }
779 if (charval != 0) {
780 xmlChar buf[10];
781 int len;
782
783 len = xmlCopyCharMultiByte(buf, charval);
784 buf[len] = 0;
785 node = xmlNewDocText(doc, buf);
786 if (node != NULL) {
787 if (last == NULL) {
788 last = ret = node;
789 } else {
790 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000791 }
792 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000793
794 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000795 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000796 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000797 cur++;
798 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000799 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000800 /*
801 * Handle the last piece of text.
802 */
803 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
804 xmlNodeAddContentLen(last, q, cur - q);
805 } else {
806 node = xmlNewDocTextLen(doc, q, cur - q);
807 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000808 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000809 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000810 } else {
811 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000812 }
813 }
814 }
815 return(ret);
816}
817
818/**
819 * xmlNodeListGetString:
820 * @doc: the document
821 * @list: a Node list
822 * @inLine: should we replace entity contents or show their external form
823 *
824 * Returns the string equivalent to the text contained in the Node list
825 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000826 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000827 */
828xmlChar *
829xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
830 xmlNodePtr node = list;
831 xmlChar *ret = NULL;
832 xmlEntityPtr ent;
833
834 if (list == NULL) return(NULL);
835
836 while (node != NULL) {
837 if ((node->type == XML_TEXT_NODE) ||
838 (node->type == XML_CDATA_SECTION_NODE)) {
839 if (inLine) {
840#ifndef XML_USE_BUFFER_CONTENT
841 ret = xmlStrcat(ret, node->content);
842#else
843 ret = xmlStrcat(ret, xmlBufferContent(node->content));
844#endif
845 } else {
846 xmlChar *buffer;
847
848#ifndef XML_USE_BUFFER_CONTENT
849 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
850#else
851 buffer = xmlEncodeEntitiesReentrant(doc,
852 xmlBufferContent(node->content));
853#endif
854 if (buffer != NULL) {
855 ret = xmlStrcat(ret, buffer);
856 xmlFree(buffer);
857 }
858 }
859 } else if (node->type == XML_ENTITY_REF_NODE) {
860 if (inLine) {
861 ent = xmlGetDocEntity(doc, node->name);
862 if (ent != NULL)
863 ret = xmlStrcat(ret, ent->content);
864 else {
865#ifndef XML_USE_BUFFER_CONTENT
866 ret = xmlStrcat(ret, node->content);
867#else
868 ret = xmlStrcat(ret, xmlBufferContent(node->content));
869#endif
870 }
871 } else {
872 xmlChar buf[2];
873 buf[0] = '&'; buf[1] = 0;
874 ret = xmlStrncat(ret, buf, 1);
875 ret = xmlStrcat(ret, node->name);
876 buf[0] = ';'; buf[1] = 0;
877 ret = xmlStrncat(ret, buf, 1);
878 }
879 }
880#if 0
881 else {
882 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000883 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000884 node->type);
885 }
886#endif
887 node = node->next;
888 }
889 return(ret);
890}
891
892/**
893 * xmlNodeListGetRawString:
894 * @doc: the document
895 * @list: a Node list
896 * @inLine: should we replace entity contents or show their external form
897 *
898 * Returns the string equivalent to the text contained in the Node list
899 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
900 * this function doesn't do any character encoding handling.
901 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000902 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000903 */
904xmlChar *
905xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
906 xmlNodePtr node = list;
907 xmlChar *ret = NULL;
908 xmlEntityPtr ent;
909
910 if (list == NULL) return(NULL);
911
912 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000913 if ((node->type == XML_TEXT_NODE) ||
914 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000915 if (inLine) {
916#ifndef XML_USE_BUFFER_CONTENT
917 ret = xmlStrcat(ret, node->content);
918#else
919 ret = xmlStrcat(ret, xmlBufferContent(node->content));
920#endif
921 } else {
922 xmlChar *buffer;
923
924#ifndef XML_USE_BUFFER_CONTENT
925 buffer = xmlEncodeSpecialChars(doc, node->content);
926#else
927 buffer = xmlEncodeSpecialChars(doc,
928 xmlBufferContent(node->content));
929#endif
930 if (buffer != NULL) {
931 ret = xmlStrcat(ret, buffer);
932 xmlFree(buffer);
933 }
934 }
935 } else if (node->type == XML_ENTITY_REF_NODE) {
936 if (inLine) {
937 ent = xmlGetDocEntity(doc, node->name);
938 if (ent != NULL)
939 ret = xmlStrcat(ret, ent->content);
940 else {
941#ifndef XML_USE_BUFFER_CONTENT
942 ret = xmlStrcat(ret, node->content);
943#else
944 ret = xmlStrcat(ret, xmlBufferContent(node->content));
945#endif
946 }
947 } else {
948 xmlChar buf[2];
949 buf[0] = '&'; buf[1] = 0;
950 ret = xmlStrncat(ret, buf, 1);
951 ret = xmlStrcat(ret, node->name);
952 buf[0] = ';'; buf[1] = 0;
953 ret = xmlStrncat(ret, buf, 1);
954 }
955 }
956#if 0
957 else {
958 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000959 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000960 node->type);
961 }
962#endif
963 node = node->next;
964 }
965 return(ret);
966}
967
968/**
969 * xmlNewProp:
970 * @node: the holding node
971 * @name: the name of the attribute
972 * @value: the value of the attribute
973 *
974 * Create a new property carried by a node.
975 * Returns a pointer to the attribute
976 */
977xmlAttrPtr
978xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
979 xmlAttrPtr cur;
980 xmlDocPtr doc = NULL;
981
982 if (name == NULL) {
983#ifdef DEBUG_TREE
984 xmlGenericError(xmlGenericErrorContext,
985 "xmlNewProp : name == NULL\n");
986#endif
987 return(NULL);
988 }
989
990 /*
991 * Allocate a new property and fill the fields.
992 */
993 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
994 if (cur == NULL) {
995 xmlGenericError(xmlGenericErrorContext,
996 "xmlNewProp : malloc failed\n");
997 return(NULL);
998 }
999 memset(cur, 0, sizeof(xmlAttr));
1000 cur->type = XML_ATTRIBUTE_NODE;
1001
1002 cur->parent = node;
1003 if (node != NULL) {
1004 doc = node->doc;
1005 cur->doc = doc;
1006 }
1007 cur->name = xmlStrdup(name);
1008 if (value != NULL) {
1009 xmlChar *buffer;
1010 xmlNodePtr tmp;
1011
1012 buffer = xmlEncodeEntitiesReentrant(doc, value);
1013 cur->children = xmlStringGetNodeList(doc, buffer);
1014 cur->last = NULL;
1015 tmp = cur->children;
1016 while (tmp != NULL) {
1017 tmp->parent = (xmlNodePtr) cur;
1018 tmp->doc = doc;
1019 if (tmp->next == NULL)
1020 cur->last = tmp;
1021 tmp = tmp->next;
1022 }
1023 xmlFree(buffer);
1024 }
1025
1026 /*
1027 * Add it at the end to preserve parsing order ...
1028 */
1029 if (node != NULL) {
1030 if (node->properties == NULL) {
1031 node->properties = cur;
1032 } else {
1033 xmlAttrPtr prev = node->properties;
1034
1035 while (prev->next != NULL) prev = prev->next;
1036 prev->next = cur;
1037 cur->prev = prev;
1038 }
1039 }
1040 return(cur);
1041}
1042
1043/**
1044 * xmlNewNsProp:
1045 * @node: the holding node
1046 * @ns: the namespace
1047 * @name: the name of the attribute
1048 * @value: the value of the attribute
1049 *
1050 * Create a new property tagged with a namespace and carried by a node.
1051 * Returns a pointer to the attribute
1052 */
1053xmlAttrPtr
1054xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1055 const xmlChar *value) {
1056 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001057 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001058
1059 if (name == NULL) {
1060#ifdef DEBUG_TREE
1061 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001062 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001063#endif
1064 return(NULL);
1065 }
1066
1067 /*
1068 * Allocate a new property and fill the fields.
1069 */
1070 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1071 if (cur == NULL) {
1072 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001073 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001074 return(NULL);
1075 }
1076 memset(cur, 0, sizeof(xmlAttr));
1077 cur->type = XML_ATTRIBUTE_NODE;
1078
1079 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001080 if (node != NULL) {
1081 doc = node->doc;
1082 cur->doc = doc;
1083 }
Owen Taylor3473f882001-02-23 17:55:21 +00001084 cur->ns = ns;
1085 cur->name = xmlStrdup(name);
1086 if (value != NULL) {
1087 xmlChar *buffer;
1088 xmlNodePtr tmp;
1089
Daniel Veillarda682b212001-06-07 19:59:42 +00001090 buffer = xmlEncodeEntitiesReentrant(doc, value);
1091 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001092 cur->last = NULL;
1093 tmp = cur->children;
1094 while (tmp != NULL) {
1095 tmp->parent = (xmlNodePtr) cur;
1096 if (tmp->next == NULL)
1097 cur->last = tmp;
1098 tmp = tmp->next;
1099 }
1100 xmlFree(buffer);
1101 }
1102
1103 /*
1104 * Add it at the end to preserve parsing order ...
1105 */
1106 if (node != NULL) {
1107 if (node->properties == NULL) {
1108 node->properties = cur;
1109 } else {
1110 xmlAttrPtr prev = node->properties;
1111
1112 while (prev->next != NULL) prev = prev->next;
1113 prev->next = cur;
1114 cur->prev = prev;
1115 }
1116 }
1117 return(cur);
1118}
1119
1120/**
1121 * xmlNewDocProp:
1122 * @doc: the document
1123 * @name: the name of the attribute
1124 * @value: the value of the attribute
1125 *
1126 * Create a new property carried by a document.
1127 * Returns a pointer to the attribute
1128 */
1129xmlAttrPtr
1130xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1131 xmlAttrPtr cur;
1132
1133 if (name == NULL) {
1134#ifdef DEBUG_TREE
1135 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001136 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001137#endif
1138 return(NULL);
1139 }
1140
1141 /*
1142 * Allocate a new property and fill the fields.
1143 */
1144 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1145 if (cur == NULL) {
1146 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001147 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001148 return(NULL);
1149 }
1150 memset(cur, 0, sizeof(xmlAttr));
1151 cur->type = XML_ATTRIBUTE_NODE;
1152
1153 cur->name = xmlStrdup(name);
1154 cur->doc = doc;
1155 if (value != NULL) {
1156 xmlNodePtr tmp;
1157
1158 cur->children = xmlStringGetNodeList(doc, value);
1159 cur->last = NULL;
1160
1161 tmp = cur->children;
1162 while (tmp != NULL) {
1163 tmp->parent = (xmlNodePtr) cur;
1164 if (tmp->next == NULL)
1165 cur->last = tmp;
1166 tmp = tmp->next;
1167 }
1168 }
1169 return(cur);
1170}
1171
1172/**
1173 * xmlFreePropList:
1174 * @cur: the first property in the list
1175 *
1176 * Free a property and all its siblings, all the children are freed too.
1177 */
1178void
1179xmlFreePropList(xmlAttrPtr cur) {
1180 xmlAttrPtr next;
1181 if (cur == NULL) {
1182#ifdef DEBUG_TREE
1183 xmlGenericError(xmlGenericErrorContext,
1184 "xmlFreePropList : property == NULL\n");
1185#endif
1186 return;
1187 }
1188 while (cur != NULL) {
1189 next = cur->next;
1190 xmlFreeProp(cur);
1191 cur = next;
1192 }
1193}
1194
1195/**
1196 * xmlFreeProp:
1197 * @cur: an attribute
1198 *
1199 * Free one attribute, all the content is freed too
1200 */
1201void
1202xmlFreeProp(xmlAttrPtr cur) {
1203 if (cur == NULL) {
1204#ifdef DEBUG_TREE
1205 xmlGenericError(xmlGenericErrorContext,
1206 "xmlFreeProp : property == NULL\n");
1207#endif
1208 return;
1209 }
1210 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001211 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1212 ((cur->parent->doc->intSubset != NULL) ||
1213 (cur->parent->doc->extSubset != NULL))) {
1214 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1215 xmlRemoveID(cur->parent->doc, cur);
1216 }
Owen Taylor3473f882001-02-23 17:55:21 +00001217 if (cur->name != NULL) xmlFree((char *) cur->name);
1218 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001219 xmlFree(cur);
1220}
1221
1222/**
1223 * xmlRemoveProp:
1224 * @cur: an attribute
1225 *
1226 * Unlink and free one attribute, all the content is freed too
1227 * Note this doesn't work for namespace definition attributes
1228 *
1229 * Returns 0 if success and -1 in case of error.
1230 */
1231int
1232xmlRemoveProp(xmlAttrPtr cur) {
1233 xmlAttrPtr tmp;
1234 if (cur == NULL) {
1235#ifdef DEBUG_TREE
1236 xmlGenericError(xmlGenericErrorContext,
1237 "xmlRemoveProp : cur == NULL\n");
1238#endif
1239 return(-1);
1240 }
1241 if (cur->parent == NULL) {
1242#ifdef DEBUG_TREE
1243 xmlGenericError(xmlGenericErrorContext,
1244 "xmlRemoveProp : cur->parent == NULL\n");
1245#endif
1246 return(-1);
1247 }
1248 tmp = cur->parent->properties;
1249 if (tmp == cur) {
1250 cur->parent->properties = cur->next;
1251 xmlFreeProp(cur);
1252 return(0);
1253 }
1254 while (tmp != NULL) {
1255 if (tmp->next == cur) {
1256 tmp->next = cur->next;
1257 if (tmp->next != NULL)
1258 tmp->next->prev = tmp;
1259 xmlFreeProp(cur);
1260 return(0);
1261 }
1262 tmp = tmp->next;
1263 }
1264#ifdef DEBUG_TREE
1265 xmlGenericError(xmlGenericErrorContext,
1266 "xmlRemoveProp : attribute not owned by its node\n");
1267#endif
1268 return(-1);
1269}
1270
1271/**
1272 * xmlNewPI:
1273 * @name: the processing instruction name
1274 * @content: the PI content
1275 *
1276 * Creation of a processing instruction element.
1277 * Returns a pointer to the new node object.
1278 */
1279xmlNodePtr
1280xmlNewPI(const xmlChar *name, const xmlChar *content) {
1281 xmlNodePtr cur;
1282
1283 if (name == NULL) {
1284#ifdef DEBUG_TREE
1285 xmlGenericError(xmlGenericErrorContext,
1286 "xmlNewPI : name == NULL\n");
1287#endif
1288 return(NULL);
1289 }
1290
1291 /*
1292 * Allocate a new node and fill the fields.
1293 */
1294 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1295 if (cur == NULL) {
1296 xmlGenericError(xmlGenericErrorContext,
1297 "xmlNewPI : malloc failed\n");
1298 return(NULL);
1299 }
1300 memset(cur, 0, sizeof(xmlNode));
1301 cur->type = XML_PI_NODE;
1302
1303 cur->name = xmlStrdup(name);
1304 if (content != NULL) {
1305#ifndef XML_USE_BUFFER_CONTENT
1306 cur->content = xmlStrdup(content);
1307#else
1308 cur->content = xmlBufferCreateSize(0);
1309 xmlBufferSetAllocationScheme(cur->content,
1310 xmlGetBufferAllocationScheme());
1311 xmlBufferAdd(cur->content, content, -1);
1312#endif
1313 }
1314 return(cur);
1315}
1316
1317/**
1318 * xmlNewNode:
1319 * @ns: namespace if any
1320 * @name: the node name
1321 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001322 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001323 *
1324 * Returns a pointer to the new node object.
1325 */
1326xmlNodePtr
1327xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1328 xmlNodePtr cur;
1329
1330 if (name == NULL) {
1331#ifdef DEBUG_TREE
1332 xmlGenericError(xmlGenericErrorContext,
1333 "xmlNewNode : name == NULL\n");
1334#endif
1335 return(NULL);
1336 }
1337
1338 /*
1339 * Allocate a new node and fill the fields.
1340 */
1341 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1342 if (cur == NULL) {
1343 xmlGenericError(xmlGenericErrorContext,
1344 "xmlNewNode : malloc failed\n");
1345 return(NULL);
1346 }
1347 memset(cur, 0, sizeof(xmlNode));
1348 cur->type = XML_ELEMENT_NODE;
1349
1350 cur->name = xmlStrdup(name);
1351 cur->ns = ns;
1352 return(cur);
1353}
1354
1355/**
1356 * xmlNewDocNode:
1357 * @doc: the document
1358 * @ns: namespace if any
1359 * @name: the node name
1360 * @content: the XML text content if any
1361 *
1362 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001363 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001364 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1365 * references, but XML special chars need to be escaped first by using
1366 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1367 * need entities support.
1368 *
1369 * Returns a pointer to the new node object.
1370 */
1371xmlNodePtr
1372xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1373 const xmlChar *name, const xmlChar *content) {
1374 xmlNodePtr cur;
1375
1376 cur = xmlNewNode(ns, name);
1377 if (cur != NULL) {
1378 cur->doc = doc;
1379 if (content != NULL) {
1380 cur->children = xmlStringGetNodeList(doc, content);
1381 UPDATE_LAST_CHILD_AND_PARENT(cur)
1382 }
1383 }
1384 return(cur);
1385}
1386
1387
1388/**
1389 * xmlNewDocRawNode:
1390 * @doc: the document
1391 * @ns: namespace if any
1392 * @name: the node name
1393 * @content: the text content if any
1394 *
1395 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001396 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001397 *
1398 * Returns a pointer to the new node object.
1399 */
1400xmlNodePtr
1401xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1402 const xmlChar *name, const xmlChar *content) {
1403 xmlNodePtr cur;
1404
1405 cur = xmlNewNode(ns, name);
1406 if (cur != NULL) {
1407 cur->doc = doc;
1408 if (content != NULL) {
1409 cur->children = xmlNewDocText(doc, content);
1410 UPDATE_LAST_CHILD_AND_PARENT(cur)
1411 }
1412 }
1413 return(cur);
1414}
1415
1416/**
1417 * xmlNewDocFragment:
1418 * @doc: the document owning the fragment
1419 *
1420 * Creation of a new Fragment node.
1421 * Returns a pointer to the new node object.
1422 */
1423xmlNodePtr
1424xmlNewDocFragment(xmlDocPtr doc) {
1425 xmlNodePtr cur;
1426
1427 /*
1428 * Allocate a new DocumentFragment node and fill the fields.
1429 */
1430 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1431 if (cur == NULL) {
1432 xmlGenericError(xmlGenericErrorContext,
1433 "xmlNewDocFragment : malloc failed\n");
1434 return(NULL);
1435 }
1436 memset(cur, 0, sizeof(xmlNode));
1437 cur->type = XML_DOCUMENT_FRAG_NODE;
1438
1439 cur->doc = doc;
1440 return(cur);
1441}
1442
1443/**
1444 * xmlNewText:
1445 * @content: the text content
1446 *
1447 * Creation of a new text node.
1448 * Returns a pointer to the new node object.
1449 */
1450xmlNodePtr
1451xmlNewText(const xmlChar *content) {
1452 xmlNodePtr cur;
1453
1454 /*
1455 * Allocate a new node and fill the fields.
1456 */
1457 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1458 if (cur == NULL) {
1459 xmlGenericError(xmlGenericErrorContext,
1460 "xmlNewText : malloc failed\n");
1461 return(NULL);
1462 }
1463 memset(cur, 0, sizeof(xmlNode));
1464 cur->type = XML_TEXT_NODE;
1465
1466 cur->name = xmlStringText;
1467 if (content != NULL) {
1468#ifndef XML_USE_BUFFER_CONTENT
1469 cur->content = xmlStrdup(content);
1470#else
1471 cur->content = xmlBufferCreateSize(0);
1472 xmlBufferSetAllocationScheme(cur->content,
1473 xmlGetBufferAllocationScheme());
1474 xmlBufferAdd(cur->content, content, -1);
1475#endif
1476 }
1477 return(cur);
1478}
1479
1480/**
1481 * xmlNewTextChild:
1482 * @parent: the parent node
1483 * @ns: a namespace if any
1484 * @name: the name of the child
1485 * @content: the text content of the child if any.
1486 *
1487 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001488 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001489 * a child TEXT node will be created containing the string content.
1490 *
1491 * Returns a pointer to the new node object.
1492 */
1493xmlNodePtr
1494xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1495 const xmlChar *name, const xmlChar *content) {
1496 xmlNodePtr cur, prev;
1497
1498 if (parent == NULL) {
1499#ifdef DEBUG_TREE
1500 xmlGenericError(xmlGenericErrorContext,
1501 "xmlNewTextChild : parent == NULL\n");
1502#endif
1503 return(NULL);
1504 }
1505
1506 if (name == NULL) {
1507#ifdef DEBUG_TREE
1508 xmlGenericError(xmlGenericErrorContext,
1509 "xmlNewTextChild : name == NULL\n");
1510#endif
1511 return(NULL);
1512 }
1513
1514 /*
1515 * Allocate a new node
1516 */
1517 if (ns == NULL)
1518 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1519 else
1520 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1521 if (cur == NULL) return(NULL);
1522
1523 /*
1524 * add the new element at the end of the children list.
1525 */
1526 cur->type = XML_ELEMENT_NODE;
1527 cur->parent = parent;
1528 cur->doc = parent->doc;
1529 if (parent->children == NULL) {
1530 parent->children = cur;
1531 parent->last = cur;
1532 } else {
1533 prev = parent->last;
1534 prev->next = cur;
1535 cur->prev = prev;
1536 parent->last = cur;
1537 }
1538
1539 return(cur);
1540}
1541
1542/**
1543 * xmlNewCharRef:
1544 * @doc: the document
1545 * @name: the char ref string, starting with # or "&# ... ;"
1546 *
1547 * Creation of a new character reference node.
1548 * Returns a pointer to the new node object.
1549 */
1550xmlNodePtr
1551xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1552 xmlNodePtr cur;
1553
1554 /*
1555 * Allocate a new node and fill the fields.
1556 */
1557 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1558 if (cur == NULL) {
1559 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001560 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001561 return(NULL);
1562 }
1563 memset(cur, 0, sizeof(xmlNode));
1564 cur->type = XML_ENTITY_REF_NODE;
1565
1566 cur->doc = doc;
1567 if (name[0] == '&') {
1568 int len;
1569 name++;
1570 len = xmlStrlen(name);
1571 if (name[len - 1] == ';')
1572 cur->name = xmlStrndup(name, len - 1);
1573 else
1574 cur->name = xmlStrndup(name, len);
1575 } else
1576 cur->name = xmlStrdup(name);
1577 return(cur);
1578}
1579
1580/**
1581 * xmlNewReference:
1582 * @doc: the document
1583 * @name: the reference name, or the reference string with & and ;
1584 *
1585 * Creation of a new reference node.
1586 * Returns a pointer to the new node object.
1587 */
1588xmlNodePtr
1589xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1590 xmlNodePtr cur;
1591 xmlEntityPtr ent;
1592
1593 /*
1594 * Allocate a new node and fill the fields.
1595 */
1596 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1597 if (cur == NULL) {
1598 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001599 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001600 return(NULL);
1601 }
1602 memset(cur, 0, sizeof(xmlNode));
1603 cur->type = XML_ENTITY_REF_NODE;
1604
1605 cur->doc = doc;
1606 if (name[0] == '&') {
1607 int len;
1608 name++;
1609 len = xmlStrlen(name);
1610 if (name[len - 1] == ';')
1611 cur->name = xmlStrndup(name, len - 1);
1612 else
1613 cur->name = xmlStrndup(name, len);
1614 } else
1615 cur->name = xmlStrdup(name);
1616
1617 ent = xmlGetDocEntity(doc, cur->name);
1618 if (ent != NULL) {
1619#ifndef XML_USE_BUFFER_CONTENT
1620 cur->content = ent->content;
1621#else
1622 /*
1623 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1624 * a copy of this pointer. Let's hope we don't manipulate it
1625 * later
1626 */
1627 cur->content = xmlBufferCreateSize(0);
1628 xmlBufferSetAllocationScheme(cur->content,
1629 xmlGetBufferAllocationScheme());
1630 if (ent->content != NULL)
1631 xmlBufferAdd(cur->content, ent->content, -1);
1632#endif
1633 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001634 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001635 * updated. Not sure if this is 100% correct.
1636 * -George
1637 */
1638 cur->children = (xmlNodePtr) ent;
1639 cur->last = (xmlNodePtr) ent;
1640 }
1641 return(cur);
1642}
1643
1644/**
1645 * xmlNewDocText:
1646 * @doc: the document
1647 * @content: the text content
1648 *
1649 * Creation of a new text node within a document.
1650 * Returns a pointer to the new node object.
1651 */
1652xmlNodePtr
1653xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1654 xmlNodePtr cur;
1655
1656 cur = xmlNewText(content);
1657 if (cur != NULL) cur->doc = doc;
1658 return(cur);
1659}
1660
1661/**
1662 * xmlNewTextLen:
1663 * @content: the text content
1664 * @len: the text len.
1665 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001666 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001667 * Returns a pointer to the new node object.
1668 */
1669xmlNodePtr
1670xmlNewTextLen(const xmlChar *content, int len) {
1671 xmlNodePtr cur;
1672
1673 /*
1674 * Allocate a new node and fill the fields.
1675 */
1676 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1677 if (cur == NULL) {
1678 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001679 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001680 return(NULL);
1681 }
1682 memset(cur, 0, sizeof(xmlNode));
1683 cur->type = XML_TEXT_NODE;
1684
1685 cur->name = xmlStringText;
1686 if (content != NULL) {
1687#ifndef XML_USE_BUFFER_CONTENT
1688 cur->content = xmlStrndup(content, len);
1689#else
1690 cur->content = xmlBufferCreateSize(len);
1691 xmlBufferSetAllocationScheme(cur->content,
1692 xmlGetBufferAllocationScheme());
1693 xmlBufferAdd(cur->content, content, len);
1694#endif
1695 }
1696 return(cur);
1697}
1698
1699/**
1700 * xmlNewDocTextLen:
1701 * @doc: the document
1702 * @content: the text content
1703 * @len: the text len.
1704 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001705 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001706 * text node pertain to a given document.
1707 * Returns a pointer to the new node object.
1708 */
1709xmlNodePtr
1710xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1711 xmlNodePtr cur;
1712
1713 cur = xmlNewTextLen(content, len);
1714 if (cur != NULL) cur->doc = doc;
1715 return(cur);
1716}
1717
1718/**
1719 * xmlNewComment:
1720 * @content: the comment content
1721 *
1722 * Creation of a new node containing a comment.
1723 * Returns a pointer to the new node object.
1724 */
1725xmlNodePtr
1726xmlNewComment(const xmlChar *content) {
1727 xmlNodePtr cur;
1728
1729 /*
1730 * Allocate a new node and fill the fields.
1731 */
1732 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1733 if (cur == NULL) {
1734 xmlGenericError(xmlGenericErrorContext,
1735 "xmlNewComment : malloc failed\n");
1736 return(NULL);
1737 }
1738 memset(cur, 0, sizeof(xmlNode));
1739 cur->type = XML_COMMENT_NODE;
1740
1741 cur->name = xmlStringComment;
1742 if (content != NULL) {
1743#ifndef XML_USE_BUFFER_CONTENT
1744 cur->content = xmlStrdup(content);
1745#else
1746 cur->content = xmlBufferCreateSize(0);
1747 xmlBufferSetAllocationScheme(cur->content,
1748 xmlGetBufferAllocationScheme());
1749 xmlBufferAdd(cur->content, content, -1);
1750#endif
1751 }
1752 return(cur);
1753}
1754
1755/**
1756 * xmlNewCDataBlock:
1757 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001758 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001759 * @len: the length of the block
1760 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001761 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001762 * Returns a pointer to the new node object.
1763 */
1764xmlNodePtr
1765xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1766 xmlNodePtr cur;
1767
1768 /*
1769 * Allocate a new node and fill the fields.
1770 */
1771 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1772 if (cur == NULL) {
1773 xmlGenericError(xmlGenericErrorContext,
1774 "xmlNewCDataBlock : malloc failed\n");
1775 return(NULL);
1776 }
1777 memset(cur, 0, sizeof(xmlNode));
1778 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001779 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001780
1781 if (content != NULL) {
1782#ifndef XML_USE_BUFFER_CONTENT
1783 cur->content = xmlStrndup(content, len);
1784#else
1785 cur->content = xmlBufferCreateSize(len);
1786 xmlBufferSetAllocationScheme(cur->content,
1787 xmlGetBufferAllocationScheme());
1788 xmlBufferAdd(cur->content, content, len);
1789#endif
1790 }
1791 return(cur);
1792}
1793
1794/**
1795 * xmlNewDocComment:
1796 * @doc: the document
1797 * @content: the comment content
1798 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001799 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001800 * Returns a pointer to the new node object.
1801 */
1802xmlNodePtr
1803xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1804 xmlNodePtr cur;
1805
1806 cur = xmlNewComment(content);
1807 if (cur != NULL) cur->doc = doc;
1808 return(cur);
1809}
1810
1811/**
1812 * xmlSetTreeDoc:
1813 * @tree: the top element
1814 * @doc: the document
1815 *
1816 * update all nodes under the tree to point to the right document
1817 */
1818void
1819xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001820 xmlAttrPtr prop;
1821
Owen Taylor3473f882001-02-23 17:55:21 +00001822 if (tree == NULL)
1823 return;
1824 if (tree->type == XML_ENTITY_DECL)
1825 return;
1826 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00001827 if(tree->type == XML_ELEMENT_NODE) {
1828 prop = tree->properties;
1829 while (prop != NULL) {
1830 prop->doc = doc;
1831 xmlSetListDoc(prop->children, doc);
1832 prop = prop->next;
1833 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00001834 }
Owen Taylor3473f882001-02-23 17:55:21 +00001835 if (tree->children != NULL)
1836 xmlSetListDoc(tree->children, doc);
1837 tree->doc = doc;
1838 }
1839}
1840
1841/**
1842 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001843 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001844 * @doc: the document
1845 *
1846 * update all nodes in the list to point to the right document
1847 */
1848void
1849xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1850 xmlNodePtr cur;
1851
1852 if (list == NULL)
1853 return;
1854 cur = list;
1855 while (cur != NULL) {
1856 if (cur->doc != doc)
1857 xmlSetTreeDoc(cur, doc);
1858 cur = cur->next;
1859 }
1860}
1861
1862
1863/**
1864 * xmlNewChild:
1865 * @parent: the parent node
1866 * @ns: a namespace if any
1867 * @name: the name of the child
1868 * @content: the XML content of the child if any.
1869 *
1870 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001871 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001872 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1873 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1874 * references, but XML special chars need to be escaped first by using
1875 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1876 * support is not needed.
1877 *
1878 * Returns a pointer to the new node object.
1879 */
1880xmlNodePtr
1881xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1882 const xmlChar *name, const xmlChar *content) {
1883 xmlNodePtr cur, prev;
1884
1885 if (parent == NULL) {
1886#ifdef DEBUG_TREE
1887 xmlGenericError(xmlGenericErrorContext,
1888 "xmlNewChild : parent == NULL\n");
1889#endif
1890 return(NULL);
1891 }
1892
1893 if (name == NULL) {
1894#ifdef DEBUG_TREE
1895 xmlGenericError(xmlGenericErrorContext,
1896 "xmlNewChild : name == NULL\n");
1897#endif
1898 return(NULL);
1899 }
1900
1901 /*
1902 * Allocate a new node
1903 */
1904 if (ns == NULL)
1905 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1906 else
1907 cur = xmlNewDocNode(parent->doc, ns, name, content);
1908 if (cur == NULL) return(NULL);
1909
1910 /*
1911 * add the new element at the end of the children list.
1912 */
1913 cur->type = XML_ELEMENT_NODE;
1914 cur->parent = parent;
1915 cur->doc = parent->doc;
1916 if (parent->children == NULL) {
1917 parent->children = cur;
1918 parent->last = cur;
1919 } else {
1920 prev = parent->last;
1921 prev->next = cur;
1922 cur->prev = prev;
1923 parent->last = cur;
1924 }
1925
1926 return(cur);
1927}
1928
1929/**
1930 * xmlAddNextSibling:
1931 * @cur: the child node
1932 * @elem: the new node
1933 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001934 * Add a new node @elem as the next sibling of @cur
1935 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00001936 * first unlinked from its existing context.
1937 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001938 * If the new node is ATTRIBUTE, it is added into properties instead of children.
1939 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00001940 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001941 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001942 */
1943xmlNodePtr
1944xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1945 if (cur == NULL) {
1946#ifdef DEBUG_TREE
1947 xmlGenericError(xmlGenericErrorContext,
1948 "xmlAddNextSibling : cur == NULL\n");
1949#endif
1950 return(NULL);
1951 }
1952 if (elem == NULL) {
1953#ifdef DEBUG_TREE
1954 xmlGenericError(xmlGenericErrorContext,
1955 "xmlAddNextSibling : elem == NULL\n");
1956#endif
1957 return(NULL);
1958 }
1959
1960 xmlUnlinkNode(elem);
1961
1962 if (elem->type == XML_TEXT_NODE) {
1963 if (cur->type == XML_TEXT_NODE) {
1964#ifndef XML_USE_BUFFER_CONTENT
1965 xmlNodeAddContent(cur, elem->content);
1966#else
1967 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1968#endif
1969 xmlFreeNode(elem);
1970 return(cur);
1971 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001972 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1973 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001974#ifndef XML_USE_BUFFER_CONTENT
1975 xmlChar *tmp;
1976
1977 tmp = xmlStrdup(elem->content);
1978 tmp = xmlStrcat(tmp, cur->next->content);
1979 xmlNodeSetContent(cur->next, tmp);
1980 xmlFree(tmp);
1981#else
1982 xmlBufferAddHead(cur->next->content,
1983 xmlBufferContent(elem->content),
1984 xmlBufferLength(elem->content));
1985#endif
1986 xmlFreeNode(elem);
1987 return(cur->next);
1988 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001989 } else if (elem->type == XML_ATTRIBUTE_NODE) {
1990 /* check if an attribute with the same name exists */
1991 xmlAttrPtr attr;
1992
1993 if (elem->ns == NULL)
1994 attr = xmlHasProp(cur->parent, elem->name);
1995 else
1996 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
1997 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
1998 /* different instance, destroy it (attributes must be unique) */
1999 xmlFreeProp(attr);
2000 }
Owen Taylor3473f882001-02-23 17:55:21 +00002001 }
2002
2003 if (elem->doc != cur->doc) {
2004 xmlSetTreeDoc(elem, cur->doc);
2005 }
2006 elem->parent = cur->parent;
2007 elem->prev = cur;
2008 elem->next = cur->next;
2009 cur->next = elem;
2010 if (elem->next != NULL)
2011 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002012 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002013 elem->parent->last = elem;
2014 return(elem);
2015}
2016
2017/**
2018 * xmlAddPrevSibling:
2019 * @cur: the child node
2020 * @elem: the new node
2021 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002022 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002023 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002024 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002025 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002026 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2027 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002028 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002029 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002030 */
2031xmlNodePtr
2032xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2033 if (cur == NULL) {
2034#ifdef DEBUG_TREE
2035 xmlGenericError(xmlGenericErrorContext,
2036 "xmlAddPrevSibling : cur == NULL\n");
2037#endif
2038 return(NULL);
2039 }
2040 if (elem == NULL) {
2041#ifdef DEBUG_TREE
2042 xmlGenericError(xmlGenericErrorContext,
2043 "xmlAddPrevSibling : elem == NULL\n");
2044#endif
2045 return(NULL);
2046 }
2047
2048 xmlUnlinkNode(elem);
2049
2050 if (elem->type == XML_TEXT_NODE) {
2051 if (cur->type == XML_TEXT_NODE) {
2052#ifndef XML_USE_BUFFER_CONTENT
2053 xmlChar *tmp;
2054
2055 tmp = xmlStrdup(elem->content);
2056 tmp = xmlStrcat(tmp, cur->content);
2057 xmlNodeSetContent(cur, tmp);
2058 xmlFree(tmp);
2059#else
2060 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2061 xmlBufferLength(elem->content));
2062#endif
2063 xmlFreeNode(elem);
2064 return(cur);
2065 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002066 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2067 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002068#ifndef XML_USE_BUFFER_CONTENT
2069 xmlNodeAddContent(cur->prev, elem->content);
2070#else
2071 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2072#endif
2073 xmlFreeNode(elem);
2074 return(cur->prev);
2075 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002076 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2077 /* check if an attribute with the same name exists */
2078 xmlAttrPtr attr;
2079
2080 if (elem->ns == NULL)
2081 attr = xmlHasProp(cur->parent, elem->name);
2082 else
2083 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2084 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2085 /* different instance, destroy it (attributes must be unique) */
2086 xmlFreeProp(attr);
2087 }
Owen Taylor3473f882001-02-23 17:55:21 +00002088 }
2089
2090 if (elem->doc != cur->doc) {
2091 xmlSetTreeDoc(elem, cur->doc);
2092 }
2093 elem->parent = cur->parent;
2094 elem->next = cur;
2095 elem->prev = cur->prev;
2096 cur->prev = elem;
2097 if (elem->prev != NULL)
2098 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002099 if (elem->parent != NULL) {
2100 if (elem->type == XML_ATTRIBUTE_NODE) {
2101 if (elem->parent->properties == (xmlAttrPtr) cur) {
2102 elem->parent->properties = (xmlAttrPtr) elem;
2103 }
2104 } else {
2105 if (elem->parent->children == cur) {
2106 elem->parent->children = elem;
2107 }
2108 }
2109 }
Owen Taylor3473f882001-02-23 17:55:21 +00002110 return(elem);
2111}
2112
2113/**
2114 * xmlAddSibling:
2115 * @cur: the child node
2116 * @elem: the new node
2117 *
2118 * Add a new element @elem to the list of siblings of @cur
2119 * merging adjacent TEXT nodes (@elem may be freed)
2120 * If the new element was already inserted in a document it is
2121 * first unlinked from its existing context.
2122 *
2123 * Returns the new element or NULL in case of error.
2124 */
2125xmlNodePtr
2126xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2127 xmlNodePtr parent;
2128
2129 if (cur == NULL) {
2130#ifdef DEBUG_TREE
2131 xmlGenericError(xmlGenericErrorContext,
2132 "xmlAddSibling : cur == NULL\n");
2133#endif
2134 return(NULL);
2135 }
2136
2137 if (elem == NULL) {
2138#ifdef DEBUG_TREE
2139 xmlGenericError(xmlGenericErrorContext,
2140 "xmlAddSibling : elem == NULL\n");
2141#endif
2142 return(NULL);
2143 }
2144
2145 /*
2146 * Constant time is we can rely on the ->parent->last to find
2147 * the last sibling.
2148 */
2149 if ((cur->parent != NULL) &&
2150 (cur->parent->children != NULL) &&
2151 (cur->parent->last != NULL) &&
2152 (cur->parent->last->next == NULL)) {
2153 cur = cur->parent->last;
2154 } else {
2155 while (cur->next != NULL) cur = cur->next;
2156 }
2157
2158 xmlUnlinkNode(elem);
2159
2160 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2161#ifndef XML_USE_BUFFER_CONTENT
2162 xmlNodeAddContent(cur, elem->content);
2163#else
2164 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2165#endif
2166 xmlFreeNode(elem);
2167 return(cur);
2168 }
2169
2170 if (elem->doc != cur->doc) {
2171 xmlSetTreeDoc(elem, cur->doc);
2172 }
2173 parent = cur->parent;
2174 elem->prev = cur;
2175 elem->next = NULL;
2176 elem->parent = parent;
2177 cur->next = elem;
2178 if (parent != NULL)
2179 parent->last = elem;
2180
2181 return(elem);
2182}
2183
2184/**
2185 * xmlAddChildList:
2186 * @parent: the parent node
2187 * @cur: the first node in the list
2188 *
2189 * Add a list of node at the end of the child list of the parent
2190 * merging adjacent TEXT nodes (@cur may be freed)
2191 *
2192 * Returns the last child or NULL in case of error.
2193 */
2194xmlNodePtr
2195xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2196 xmlNodePtr prev;
2197
2198 if (parent == NULL) {
2199#ifdef DEBUG_TREE
2200 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002201 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002202#endif
2203 return(NULL);
2204 }
2205
2206 if (cur == NULL) {
2207#ifdef DEBUG_TREE
2208 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002209 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002210#endif
2211 return(NULL);
2212 }
2213
2214 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2215 (cur->doc != parent->doc)) {
2216#ifdef DEBUG_TREE
2217 xmlGenericError(xmlGenericErrorContext,
2218 "Elements moved to a different document\n");
2219#endif
2220 }
2221
2222 /*
2223 * add the first element at the end of the children list.
2224 */
2225 if (parent->children == NULL) {
2226 parent->children = cur;
2227 } else {
2228 /*
2229 * If cur and parent->last both are TEXT nodes, then merge them.
2230 */
2231 if ((cur->type == XML_TEXT_NODE) &&
2232 (parent->last->type == XML_TEXT_NODE) &&
2233 (cur->name == parent->last->name)) {
2234#ifndef XML_USE_BUFFER_CONTENT
2235 xmlNodeAddContent(parent->last, cur->content);
2236#else
2237 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2238#endif
2239 /*
2240 * if it's the only child, nothing more to be done.
2241 */
2242 if (cur->next == NULL) {
2243 xmlFreeNode(cur);
2244 return(parent->last);
2245 }
2246 prev = cur;
2247 cur = cur->next;
2248 xmlFreeNode(prev);
2249 }
2250 prev = parent->last;
2251 prev->next = cur;
2252 cur->prev = prev;
2253 }
2254 while (cur->next != NULL) {
2255 cur->parent = parent;
2256 if (cur->doc != parent->doc) {
2257 xmlSetTreeDoc(cur, parent->doc);
2258 }
2259 cur = cur->next;
2260 }
2261 cur->parent = parent;
2262 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2263 parent->last = cur;
2264
2265 return(cur);
2266}
2267
2268/**
2269 * xmlAddChild:
2270 * @parent: the parent node
2271 * @cur: the child node
2272 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002273 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002274 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002275 * If the new node was already inserted in a document it is
2276 * first unlinked from its existing context.
2277 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2278 * If there is an attribute with equal name, it is first destroyed.
2279 *
Owen Taylor3473f882001-02-23 17:55:21 +00002280 * Returns the child or NULL in case of error.
2281 */
2282xmlNodePtr
2283xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2284 xmlNodePtr prev;
2285
2286 if (parent == NULL) {
2287#ifdef DEBUG_TREE
2288 xmlGenericError(xmlGenericErrorContext,
2289 "xmlAddChild : parent == NULL\n");
2290#endif
2291 return(NULL);
2292 }
2293
2294 if (cur == NULL) {
2295#ifdef DEBUG_TREE
2296 xmlGenericError(xmlGenericErrorContext,
2297 "xmlAddChild : child == NULL\n");
2298#endif
2299 return(NULL);
2300 }
2301
Owen Taylor3473f882001-02-23 17:55:21 +00002302 /*
2303 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002304 * cur is then freed.
2305 */
2306 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002307 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002308 (parent->content != NULL)) {
2309#ifndef XML_USE_BUFFER_CONTENT
2310 xmlNodeAddContent(parent, cur->content);
2311#else
2312 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2313#endif
2314 xmlFreeNode(cur);
2315 return(parent);
2316 }
2317 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2318 (parent->last->name == cur->name)) {
2319#ifndef XML_USE_BUFFER_CONTENT
2320 xmlNodeAddContent(parent->last, cur->content);
2321#else
2322 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2323#endif
2324 xmlFreeNode(cur);
2325 return(parent->last);
2326 }
2327 }
2328
2329 /*
2330 * add the new element at the end of the children list.
2331 */
2332 cur->parent = parent;
2333 if (cur->doc != parent->doc) {
2334 xmlSetTreeDoc(cur, parent->doc);
2335 }
2336
2337 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002338 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002339 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002340 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002341 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002342#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002343 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002344#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002345 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002346#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002347 xmlFreeNode(cur);
2348 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002349 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002350 if (cur->type == XML_ATTRIBUTE_NODE) {
2351 if (parent->properties == NULL) {
2352 parent->properties = (xmlAttrPtr) cur;
2353 } else {
2354 /* check if an attribute with the same name exists */
2355 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002356
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002357 if (cur->ns == NULL)
2358 lastattr = xmlHasProp(parent, cur->name);
2359 else
2360 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2361 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2362 /* different instance, destroy it (attributes must be unique) */
2363 xmlFreeProp(lastattr);
2364 }
2365 /* find the end */
2366 lastattr = parent->properties;
2367 while (lastattr->next != NULL) {
2368 lastattr = lastattr->next;
2369 }
2370 lastattr->next = (xmlAttrPtr) cur;
2371 ((xmlAttrPtr) cur)->prev = lastattr;
2372 }
2373 } else {
2374 if (parent->children == NULL) {
2375 parent->children = cur;
2376 parent->last = cur;
2377 } else {
2378 prev = parent->last;
2379 prev->next = cur;
2380 cur->prev = prev;
2381 parent->last = cur;
2382 }
2383 }
Owen Taylor3473f882001-02-23 17:55:21 +00002384 return(cur);
2385}
2386
2387/**
2388 * xmlGetLastChild:
2389 * @parent: the parent node
2390 *
2391 * Search the last child of a node.
2392 * Returns the last child or NULL if none.
2393 */
2394xmlNodePtr
2395xmlGetLastChild(xmlNodePtr parent) {
2396 if (parent == NULL) {
2397#ifdef DEBUG_TREE
2398 xmlGenericError(xmlGenericErrorContext,
2399 "xmlGetLastChild : parent == NULL\n");
2400#endif
2401 return(NULL);
2402 }
2403 return(parent->last);
2404}
2405
2406/**
2407 * xmlFreeNodeList:
2408 * @cur: the first node in the list
2409 *
2410 * Free a node and all its siblings, this is a recursive behaviour, all
2411 * the children are freed too.
2412 */
2413void
2414xmlFreeNodeList(xmlNodePtr cur) {
2415 xmlNodePtr next;
2416 if (cur == NULL) {
2417#ifdef DEBUG_TREE
2418 xmlGenericError(xmlGenericErrorContext,
2419 "xmlFreeNodeList : node == NULL\n");
2420#endif
2421 return;
2422 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002423 if (cur->type == XML_NAMESPACE_DECL) {
2424 xmlFreeNsList((xmlNsPtr) cur);
2425 return;
2426 }
Owen Taylor3473f882001-02-23 17:55:21 +00002427 while (cur != NULL) {
2428 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002429 /* unroll to speed up freeing the document */
2430 if (cur->type != XML_DTD_NODE) {
2431 if ((cur->children != NULL) &&
2432 (cur->type != XML_ENTITY_REF_NODE))
2433 xmlFreeNodeList(cur->children);
2434 if (cur->properties != NULL)
2435 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002436 if ((cur->type != XML_ELEMENT_NODE) &&
2437 (cur->type != XML_XINCLUDE_START) &&
2438 (cur->type != XML_XINCLUDE_END) &&
2439 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002440#ifndef XML_USE_BUFFER_CONTENT
2441 if (cur->content != NULL) xmlFree(cur->content);
2442#else
2443 if (cur->content != NULL) xmlBufferFree(cur->content);
2444#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002445 }
2446 if (((cur->type == XML_ELEMENT_NODE) ||
2447 (cur->type == XML_XINCLUDE_START) ||
2448 (cur->type == XML_XINCLUDE_END)) &&
2449 (cur->nsDef != NULL))
2450 xmlFreeNsList(cur->nsDef);
2451
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002452 /*
2453 * When a node is a text node or a comment, it uses a global static
2454 * variable for the name of the node.
2455 *
2456 * The xmlStrEqual comparisons need to be done when (happened with
2457 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002458 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002459 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002460 * the string addresses compare are not sufficient.
2461 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002462 if ((cur->name != NULL) &&
2463 (cur->name != xmlStringText) &&
2464 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002465 (cur->name != xmlStringComment)) {
2466 if (cur->type == XML_TEXT_NODE) {
2467 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2468 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2469 xmlFree((char *) cur->name);
2470 } else if (cur->type == XML_COMMENT_NODE) {
2471 if (!xmlStrEqual(cur->name, xmlStringComment))
2472 xmlFree((char *) cur->name);
2473 } else
2474 xmlFree((char *) cur->name);
2475 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002476 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002477 xmlFree(cur);
2478 }
Owen Taylor3473f882001-02-23 17:55:21 +00002479 cur = next;
2480 }
2481}
2482
2483/**
2484 * xmlFreeNode:
2485 * @cur: the node
2486 *
2487 * Free a node, this is a recursive behaviour, all the children are freed too.
2488 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2489 */
2490void
2491xmlFreeNode(xmlNodePtr cur) {
2492 if (cur == NULL) {
2493#ifdef DEBUG_TREE
2494 xmlGenericError(xmlGenericErrorContext,
2495 "xmlFreeNode : node == NULL\n");
2496#endif
2497 return;
2498 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002499 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002500 if (cur->type == XML_DTD_NODE) {
2501 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002502 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002503 }
2504 if (cur->type == XML_NAMESPACE_DECL) {
2505 xmlFreeNs((xmlNsPtr) cur);
2506 return;
2507 }
Owen Taylor3473f882001-02-23 17:55:21 +00002508 if ((cur->children != NULL) &&
2509 (cur->type != XML_ENTITY_REF_NODE))
2510 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002511 if (cur->properties != NULL)
2512 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002513 if ((cur->type != XML_ELEMENT_NODE) &&
2514 (cur->content != NULL) &&
2515 (cur->type != XML_ENTITY_REF_NODE) &&
2516 (cur->type != XML_XINCLUDE_END) &&
2517 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002518#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002519 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002520#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002521 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002522#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002523 }
2524
Daniel Veillardacd370f2001-06-09 17:17:51 +00002525 /*
2526 * When a node is a text node or a comment, it uses a global static
2527 * variable for the name of the node.
2528 *
2529 * The xmlStrEqual comparisons need to be done when (happened with
2530 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002531 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002532 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002533 * are not sufficient.
2534 */
Owen Taylor3473f882001-02-23 17:55:21 +00002535 if ((cur->name != NULL) &&
2536 (cur->name != xmlStringText) &&
2537 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002538 (cur->name != xmlStringComment)) {
2539 if (cur->type == XML_TEXT_NODE) {
2540 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2541 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2542 xmlFree((char *) cur->name);
2543 } else if (cur->type == XML_COMMENT_NODE) {
2544 if (!xmlStrEqual(cur->name, xmlStringComment))
2545 xmlFree((char *) cur->name);
2546 } else
2547 xmlFree((char *) cur->name);
2548 }
2549
Owen Taylor3473f882001-02-23 17:55:21 +00002550 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002551 xmlFree(cur);
2552}
2553
2554/**
2555 * xmlUnlinkNode:
2556 * @cur: the node
2557 *
2558 * Unlink a node from it's current context, the node is not freed
2559 */
2560void
2561xmlUnlinkNode(xmlNodePtr cur) {
2562 if (cur == NULL) {
2563#ifdef DEBUG_TREE
2564 xmlGenericError(xmlGenericErrorContext,
2565 "xmlUnlinkNode : node == NULL\n");
2566#endif
2567 return;
2568 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002569 if (cur->type == XML_DTD_NODE) {
2570 xmlDocPtr doc;
2571 doc = cur->doc;
2572 if (doc->intSubset == (xmlDtdPtr) cur)
2573 doc->intSubset = NULL;
2574 if (doc->extSubset == (xmlDtdPtr) cur)
2575 doc->extSubset = NULL;
2576 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002577 if (cur->parent != NULL) {
2578 xmlNodePtr parent;
2579 parent = cur->parent;
2580 if (cur->type == XML_ATTRIBUTE_NODE) {
2581 if (parent->properties == (xmlAttrPtr) cur)
2582 parent->properties = ((xmlAttrPtr) cur)->next;
2583 } else {
2584 if (parent->children == cur)
2585 parent->children = cur->next;
2586 if (parent->last == cur)
2587 parent->last = cur->prev;
2588 }
2589 cur->parent = NULL;
2590 }
Owen Taylor3473f882001-02-23 17:55:21 +00002591 if (cur->next != NULL)
2592 cur->next->prev = cur->prev;
2593 if (cur->prev != NULL)
2594 cur->prev->next = cur->next;
2595 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002596}
2597
2598/**
2599 * xmlReplaceNode:
2600 * @old: the old node
2601 * @cur: the node
2602 *
2603 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002604 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002605 * first unlinked from its existing context.
2606 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002607 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002608 */
2609xmlNodePtr
2610xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2611 if (old == NULL) {
2612#ifdef DEBUG_TREE
2613 xmlGenericError(xmlGenericErrorContext,
2614 "xmlReplaceNode : old == NULL\n");
2615#endif
2616 return(NULL);
2617 }
2618 if (cur == NULL) {
2619 xmlUnlinkNode(old);
2620 return(old);
2621 }
2622 if (cur == old) {
2623 return(old);
2624 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002625 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2626#ifdef DEBUG_TREE
2627 xmlGenericError(xmlGenericErrorContext,
2628 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2629#endif
2630 return(old);
2631 }
2632 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2633#ifdef DEBUG_TREE
2634 xmlGenericError(xmlGenericErrorContext,
2635 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2636#endif
2637 return(old);
2638 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002639 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2640#ifdef DEBUG_TREE
2641 xmlGenericError(xmlGenericErrorContext,
2642 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2643#endif
2644 return(old);
2645 }
2646 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2647#ifdef DEBUG_TREE
2648 xmlGenericError(xmlGenericErrorContext,
2649 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2650#endif
2651 return(old);
2652 }
Owen Taylor3473f882001-02-23 17:55:21 +00002653 xmlUnlinkNode(cur);
2654 cur->doc = old->doc;
2655 cur->parent = old->parent;
2656 cur->next = old->next;
2657 if (cur->next != NULL)
2658 cur->next->prev = cur;
2659 cur->prev = old->prev;
2660 if (cur->prev != NULL)
2661 cur->prev->next = cur;
2662 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002663 if (cur->type == XML_ATTRIBUTE_NODE) {
2664 if (cur->parent->properties == (xmlAttrPtr)old)
2665 cur->parent->properties = ((xmlAttrPtr) cur);
2666 } else {
2667 if (cur->parent->children == old)
2668 cur->parent->children = cur;
2669 if (cur->parent->last == old)
2670 cur->parent->last = cur;
2671 }
Owen Taylor3473f882001-02-23 17:55:21 +00002672 }
2673 old->next = old->prev = NULL;
2674 old->parent = NULL;
2675 return(old);
2676}
2677
2678/************************************************************************
2679 * *
2680 * Copy operations *
2681 * *
2682 ************************************************************************/
2683
2684/**
2685 * xmlCopyNamespace:
2686 * @cur: the namespace
2687 *
2688 * Do a copy of the namespace.
2689 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002690 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002691 */
2692xmlNsPtr
2693xmlCopyNamespace(xmlNsPtr cur) {
2694 xmlNsPtr ret;
2695
2696 if (cur == NULL) return(NULL);
2697 switch (cur->type) {
2698 case XML_LOCAL_NAMESPACE:
2699 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2700 break;
2701 default:
2702#ifdef DEBUG_TREE
2703 xmlGenericError(xmlGenericErrorContext,
2704 "xmlCopyNamespace: invalid type %d\n", cur->type);
2705#endif
2706 return(NULL);
2707 }
2708 return(ret);
2709}
2710
2711/**
2712 * xmlCopyNamespaceList:
2713 * @cur: the first namespace
2714 *
2715 * Do a copy of an namespace list.
2716 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002717 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002718 */
2719xmlNsPtr
2720xmlCopyNamespaceList(xmlNsPtr cur) {
2721 xmlNsPtr ret = NULL;
2722 xmlNsPtr p = NULL,q;
2723
2724 while (cur != NULL) {
2725 q = xmlCopyNamespace(cur);
2726 if (p == NULL) {
2727 ret = p = q;
2728 } else {
2729 p->next = q;
2730 p = q;
2731 }
2732 cur = cur->next;
2733 }
2734 return(ret);
2735}
2736
2737static xmlNodePtr
2738xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2739/**
2740 * xmlCopyProp:
2741 * @target: the element where the attribute will be grafted
2742 * @cur: the attribute
2743 *
2744 * Do a copy of the attribute.
2745 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002746 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002747 */
2748xmlAttrPtr
2749xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2750 xmlAttrPtr ret;
2751
2752 if (cur == NULL) return(NULL);
2753 if (target != NULL)
2754 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2755 else if (cur->parent != NULL)
2756 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2757 else if (cur->children != NULL)
2758 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2759 else
2760 ret = xmlNewDocProp(NULL, cur->name, NULL);
2761 if (ret == NULL) return(NULL);
2762 ret->parent = target;
2763
2764 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002765 xmlNsPtr ns;
2766 if (target->doc)
Owen Taylor3473f882001-02-23 17:55:21 +00002767 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
Daniel Veillard8107a222002-01-13 14:10:10 +00002768 else if (cur->doc) /* target may not yet have a doc : KPI */
2769 ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2770 else
2771 ns = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002772 ret->ns = ns;
2773 } else
2774 ret->ns = NULL;
2775
2776 if (cur->children != NULL) {
2777 xmlNodePtr tmp;
2778
2779 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2780 ret->last = NULL;
2781 tmp = ret->children;
2782 while (tmp != NULL) {
2783 /* tmp->parent = (xmlNodePtr)ret; */
2784 if (tmp->next == NULL)
2785 ret->last = tmp;
2786 tmp = tmp->next;
2787 }
2788 }
2789 return(ret);
2790}
2791
2792/**
2793 * xmlCopyPropList:
2794 * @target: the element where the attributes will be grafted
2795 * @cur: the first attribute
2796 *
2797 * Do a copy of an attribute list.
2798 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002799 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002800 */
2801xmlAttrPtr
2802xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2803 xmlAttrPtr ret = NULL;
2804 xmlAttrPtr p = NULL,q;
2805
2806 while (cur != NULL) {
2807 q = xmlCopyProp(target, cur);
2808 if (p == NULL) {
2809 ret = p = q;
2810 } else {
2811 p->next = q;
2812 q->prev = p;
2813 p = q;
2814 }
2815 cur = cur->next;
2816 }
2817 return(ret);
2818}
2819
2820/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002821 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002822 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002823 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002824 * tricky reason: namespaces. Doing a direct copy of a node
2825 * say RPM:Copyright without changing the namespace pointer to
2826 * something else can produce stale links. One way to do it is
2827 * to keep a reference counter but this doesn't work as soon
2828 * as one move the element or the subtree out of the scope of
2829 * the existing namespace. The actual solution seems to add
2830 * a copy of the namespace at the top of the copied tree if
2831 * not available in the subtree.
2832 * Hence two functions, the public front-end call the inner ones
2833 */
2834
2835static xmlNodePtr
2836xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2837
2838static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002839xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002840 int recursive) {
2841 xmlNodePtr ret;
2842
2843 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002844 switch (node->type) {
2845 case XML_TEXT_NODE:
2846 case XML_CDATA_SECTION_NODE:
2847 case XML_ELEMENT_NODE:
2848 case XML_ENTITY_REF_NODE:
2849 case XML_ENTITY_NODE:
2850 case XML_PI_NODE:
2851 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002852 case XML_XINCLUDE_START:
2853 case XML_XINCLUDE_END:
2854 break;
2855 case XML_ATTRIBUTE_NODE:
2856 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2857 case XML_NAMESPACE_DECL:
2858 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2859
Daniel Veillard39196eb2001-06-19 18:09:42 +00002860 case XML_DOCUMENT_NODE:
2861 case XML_HTML_DOCUMENT_NODE:
2862#ifdef LIBXML_DOCB_ENABLED
2863 case XML_DOCB_DOCUMENT_NODE:
2864#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002865 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002866 case XML_DOCUMENT_TYPE_NODE:
2867 case XML_DOCUMENT_FRAG_NODE:
2868 case XML_NOTATION_NODE:
2869 case XML_DTD_NODE:
2870 case XML_ELEMENT_DECL:
2871 case XML_ATTRIBUTE_DECL:
2872 case XML_ENTITY_DECL:
2873 return(NULL);
2874 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002875
Owen Taylor3473f882001-02-23 17:55:21 +00002876 /*
2877 * Allocate a new node and fill the fields.
2878 */
2879 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2880 if (ret == NULL) {
2881 xmlGenericError(xmlGenericErrorContext,
2882 "xmlStaticCopyNode : malloc failed\n");
2883 return(NULL);
2884 }
2885 memset(ret, 0, sizeof(xmlNode));
2886 ret->type = node->type;
2887
2888 ret->doc = doc;
2889 ret->parent = parent;
2890 if (node->name == xmlStringText)
2891 ret->name = xmlStringText;
2892 else if (node->name == xmlStringTextNoenc)
2893 ret->name = xmlStringTextNoenc;
2894 else if (node->name == xmlStringComment)
2895 ret->name = xmlStringComment;
2896 else if (node->name != NULL)
2897 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002898 if ((node->type != XML_ELEMENT_NODE) &&
2899 (node->content != NULL) &&
2900 (node->type != XML_ENTITY_REF_NODE) &&
2901 (node->type != XML_XINCLUDE_END) &&
2902 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002903#ifndef XML_USE_BUFFER_CONTENT
2904 ret->content = xmlStrdup(node->content);
2905#else
2906 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2907 xmlBufferSetAllocationScheme(ret->content,
2908 xmlGetBufferAllocationScheme());
2909 xmlBufferAdd(ret->content,
2910 xmlBufferContent(node->content),
2911 xmlBufferLength(node->content));
2912#endif
Daniel Veillard8107a222002-01-13 14:10:10 +00002913 }else{
2914 if (node->type == XML_ELEMENT_NODE)
2915 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002916 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002917 if (parent != NULL) {
2918 xmlNodePtr tmp;
2919
2920 tmp = xmlAddChild(parent, ret);
2921 /* node could have coalesced */
2922 if (tmp != ret)
2923 return(tmp);
2924 }
Owen Taylor3473f882001-02-23 17:55:21 +00002925
2926 if (!recursive) return(ret);
2927 if (node->nsDef != NULL)
2928 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2929
2930 if (node->ns != NULL) {
2931 xmlNsPtr ns;
2932
2933 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2934 if (ns == NULL) {
2935 /*
2936 * Humm, we are copying an element whose namespace is defined
2937 * out of the new tree scope. Search it in the original tree
2938 * and add it at the top of the new tree
2939 */
2940 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2941 if (ns != NULL) {
2942 xmlNodePtr root = ret;
2943
2944 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002945 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002946 }
2947 } else {
2948 /*
2949 * reference the existing namespace definition in our own tree.
2950 */
2951 ret->ns = ns;
2952 }
2953 }
2954 if (node->properties != NULL)
2955 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002956 if (node->type == XML_ENTITY_REF_NODE) {
2957 if ((doc == NULL) || (node->doc != doc)) {
2958 /*
2959 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002960 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002961 * we cannot keep the reference. Try to find it in the
2962 * target document.
2963 */
2964 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2965 } else {
2966 ret->children = node->children;
2967 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002968 ret->last = ret->children;
2969 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002970 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002971 UPDATE_LAST_CHILD_AND_PARENT(ret)
2972 }
Owen Taylor3473f882001-02-23 17:55:21 +00002973 return(ret);
2974}
2975
2976static xmlNodePtr
2977xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2978 xmlNodePtr ret = NULL;
2979 xmlNodePtr p = NULL,q;
2980
2981 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002982 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002983 if (doc == NULL) {
2984 node = node->next;
2985 continue;
2986 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002987 if (doc->intSubset == NULL) {
2988 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2989 q->doc = doc;
2990 q->parent = parent;
2991 doc->intSubset = (xmlDtdPtr) q;
2992 } else {
2993 q = (xmlNodePtr) doc->intSubset;
2994 }
2995 } else
2996 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002997 if (ret == NULL) {
2998 q->prev = NULL;
2999 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003000 } else if (p != q) {
3001 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003002 p->next = q;
3003 q->prev = p;
3004 p = q;
3005 }
3006 node = node->next;
3007 }
3008 return(ret);
3009}
3010
3011/**
3012 * xmlCopyNode:
3013 * @node: the node
3014 * @recursive: if 1 do a recursive copy.
3015 *
3016 * Do a copy of the node.
3017 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003018 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003019 */
3020xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003021xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003022 xmlNodePtr ret;
3023
3024 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3025 return(ret);
3026}
3027
3028/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003029 * xmlDocCopyNode:
3030 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003031 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003032 * @recursive: if 1 do a recursive copy.
3033 *
3034 * Do a copy of the node to a given document.
3035 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003036 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003037 */
3038xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003039xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003040 xmlNodePtr ret;
3041
3042 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3043 return(ret);
3044}
3045
3046/**
Owen Taylor3473f882001-02-23 17:55:21 +00003047 * xmlCopyNodeList:
3048 * @node: the first node in the list.
3049 *
3050 * Do a recursive copy of the node list.
3051 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003052 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003053 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003054xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003055 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3056 return(ret);
3057}
3058
3059/**
Owen Taylor3473f882001-02-23 17:55:21 +00003060 * xmlCopyDtd:
3061 * @dtd: the dtd
3062 *
3063 * Do a copy of the dtd.
3064 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003065 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003066 */
3067xmlDtdPtr
3068xmlCopyDtd(xmlDtdPtr dtd) {
3069 xmlDtdPtr ret;
3070
3071 if (dtd == NULL) return(NULL);
3072 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3073 if (ret == NULL) return(NULL);
3074 if (dtd->entities != NULL)
3075 ret->entities = (void *) xmlCopyEntitiesTable(
3076 (xmlEntitiesTablePtr) dtd->entities);
3077 if (dtd->notations != NULL)
3078 ret->notations = (void *) xmlCopyNotationTable(
3079 (xmlNotationTablePtr) dtd->notations);
3080 if (dtd->elements != NULL)
3081 ret->elements = (void *) xmlCopyElementTable(
3082 (xmlElementTablePtr) dtd->elements);
3083 if (dtd->attributes != NULL)
3084 ret->attributes = (void *) xmlCopyAttributeTable(
3085 (xmlAttributeTablePtr) dtd->attributes);
3086 return(ret);
3087}
3088
3089/**
3090 * xmlCopyDoc:
3091 * @doc: the document
3092 * @recursive: if 1 do a recursive copy.
3093 *
3094 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003095 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003096 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003097 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003098 */
3099xmlDocPtr
3100xmlCopyDoc(xmlDocPtr doc, int recursive) {
3101 xmlDocPtr ret;
3102
3103 if (doc == NULL) return(NULL);
3104 ret = xmlNewDoc(doc->version);
3105 if (ret == NULL) return(NULL);
3106 if (doc->name != NULL)
3107 ret->name = xmlMemStrdup(doc->name);
3108 if (doc->encoding != NULL)
3109 ret->encoding = xmlStrdup(doc->encoding);
3110 ret->charset = doc->charset;
3111 ret->compression = doc->compression;
3112 ret->standalone = doc->standalone;
3113 if (!recursive) return(ret);
3114
Daniel Veillardb33c2012001-04-25 12:59:04 +00003115 ret->last = NULL;
3116 ret->children = NULL;
3117 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003118 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003119 ret->intSubset->doc = ret;
3120 ret->intSubset->parent = ret;
3121 }
Owen Taylor3473f882001-02-23 17:55:21 +00003122 if (doc->oldNs != NULL)
3123 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3124 if (doc->children != NULL) {
3125 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003126
3127 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3128 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003129 ret->last = NULL;
3130 tmp = ret->children;
3131 while (tmp != NULL) {
3132 if (tmp->next == NULL)
3133 ret->last = tmp;
3134 tmp = tmp->next;
3135 }
3136 }
3137 return(ret);
3138}
3139
3140/************************************************************************
3141 * *
3142 * Content access functions *
3143 * *
3144 ************************************************************************/
3145
3146/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003147 * xmlGetLineNo:
3148 * @node : valid node
3149 *
3150 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003151 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003152 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003153 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003154 */
3155long
3156xmlGetLineNo(xmlNodePtr node)
3157{
3158 long result = -1;
3159
3160 if (!node)
3161 return result;
3162 if (node->type == XML_ELEMENT_NODE)
3163 result = (long) node->content;
3164 else if ((node->prev != NULL) &&
3165 ((node->prev->type == XML_ELEMENT_NODE) ||
3166 (node->prev->type == XML_TEXT_NODE)))
3167 result = xmlGetLineNo(node->prev);
3168 else if ((node->parent != NULL) &&
3169 ((node->parent->type == XML_ELEMENT_NODE) ||
3170 (node->parent->type == XML_TEXT_NODE)))
3171 result = xmlGetLineNo(node->parent);
3172
3173 return result;
3174}
3175
3176/**
3177 * xmlGetNodePath:
3178 * @node: a node
3179 *
3180 * Build a structure based Path for the given node
3181 *
3182 * Returns the new path or NULL in case of error. The caller must free
3183 * the returned string
3184 */
3185xmlChar *
3186xmlGetNodePath(xmlNodePtr node)
3187{
3188 xmlNodePtr cur, tmp, next;
3189 xmlChar *buffer = NULL, *temp;
3190 size_t buf_len;
3191 xmlChar *buf;
3192 char sep;
3193 const char *name;
3194 char nametemp[100];
3195 int occur = 0;
3196
3197 if (node == NULL)
3198 return (NULL);
3199
3200 buf_len = 500;
3201 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3202 if (buffer == NULL)
3203 return (NULL);
3204 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3205 if (buf == NULL) {
3206 xmlFree(buffer);
3207 return (NULL);
3208 }
3209
3210 buffer[0] = 0;
3211 cur = node;
3212 do {
3213 name = "";
3214 sep = '?';
3215 occur = 0;
3216 if ((cur->type == XML_DOCUMENT_NODE) ||
3217 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3218 if (buffer[0] == '/')
3219 break;
3220 sep = '/';
3221 next = NULL;
3222 } else if (cur->type == XML_ELEMENT_NODE) {
3223 sep = '/';
3224 name = (const char *) cur->name;
3225 if (cur->ns) {
3226 snprintf(nametemp, sizeof(nametemp) - 1,
3227 "%s:%s", cur->ns->prefix, cur->name);
3228 nametemp[sizeof(nametemp) - 1] = 0;
3229 name = nametemp;
3230 }
3231 next = cur->parent;
3232
3233 /*
3234 * Thumbler index computation
3235 */
3236 tmp = cur->prev;
3237 while (tmp != NULL) {
3238 if (xmlStrEqual(cur->name, tmp->name))
3239 occur++;
3240 tmp = tmp->prev;
3241 }
3242 if (occur == 0) {
3243 tmp = cur->next;
3244 while (tmp != NULL) {
3245 if (xmlStrEqual(cur->name, tmp->name))
3246 occur++;
3247 tmp = tmp->next;
3248 }
3249 if (occur != 0)
3250 occur = 1;
3251 } else
3252 occur++;
3253 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3254 sep = '@';
3255 name = (const char *) (((xmlAttrPtr) cur)->name);
3256 next = ((xmlAttrPtr) cur)->parent;
3257 } else {
3258 next = cur->parent;
3259 }
3260
3261 /*
3262 * Make sure there is enough room
3263 */
3264 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3265 buf_len =
3266 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3267 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3268 if (temp == NULL) {
3269 xmlFree(buf);
3270 xmlFree(buffer);
3271 return (NULL);
3272 }
3273 buffer = temp;
3274 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3275 if (temp == NULL) {
3276 xmlFree(buf);
3277 xmlFree(buffer);
3278 return (NULL);
3279 }
3280 buf = temp;
3281 }
3282 if (occur == 0)
3283 snprintf((char *) buf, buf_len, "%c%s%s",
3284 sep, name, (char *) buffer);
3285 else
3286 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3287 sep, name, occur, (char *) buffer);
3288 snprintf((char *) buffer, buf_len, "%s", buf);
3289 cur = next;
3290 } while (cur != NULL);
3291 xmlFree(buf);
3292 return (buffer);
3293}
3294
3295/**
Owen Taylor3473f882001-02-23 17:55:21 +00003296 * xmlDocGetRootElement:
3297 * @doc: the document
3298 *
3299 * Get the root element of the document (doc->children is a list
3300 * containing possibly comments, PIs, etc ...).
3301 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003302 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003303 */
3304xmlNodePtr
3305xmlDocGetRootElement(xmlDocPtr doc) {
3306 xmlNodePtr ret;
3307
3308 if (doc == NULL) return(NULL);
3309 ret = doc->children;
3310 while (ret != NULL) {
3311 if (ret->type == XML_ELEMENT_NODE)
3312 return(ret);
3313 ret = ret->next;
3314 }
3315 return(ret);
3316}
3317
3318/**
3319 * xmlDocSetRootElement:
3320 * @doc: the document
3321 * @root: the new document root element
3322 *
3323 * Set the root element of the document (doc->children is a list
3324 * containing possibly comments, PIs, etc ...).
3325 *
3326 * Returns the old root element if any was found
3327 */
3328xmlNodePtr
3329xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3330 xmlNodePtr old = NULL;
3331
3332 if (doc == NULL) return(NULL);
3333 old = doc->children;
3334 while (old != NULL) {
3335 if (old->type == XML_ELEMENT_NODE)
3336 break;
3337 old = old->next;
3338 }
3339 if (old == NULL) {
3340 if (doc->children == NULL) {
3341 doc->children = root;
3342 doc->last = root;
3343 } else {
3344 xmlAddSibling(doc->children, root);
3345 }
3346 } else {
3347 xmlReplaceNode(old, root);
3348 }
3349 return(old);
3350}
3351
3352/**
3353 * xmlNodeSetLang:
3354 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003355 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003356 *
3357 * Set the language of a node, i.e. the values of the xml:lang
3358 * attribute.
3359 */
3360void
3361xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003362 xmlNsPtr ns;
3363
Owen Taylor3473f882001-02-23 17:55:21 +00003364 if (cur == NULL) return;
3365 switch(cur->type) {
3366 case XML_TEXT_NODE:
3367 case XML_CDATA_SECTION_NODE:
3368 case XML_COMMENT_NODE:
3369 case XML_DOCUMENT_NODE:
3370 case XML_DOCUMENT_TYPE_NODE:
3371 case XML_DOCUMENT_FRAG_NODE:
3372 case XML_NOTATION_NODE:
3373 case XML_HTML_DOCUMENT_NODE:
3374 case XML_DTD_NODE:
3375 case XML_ELEMENT_DECL:
3376 case XML_ATTRIBUTE_DECL:
3377 case XML_ENTITY_DECL:
3378 case XML_PI_NODE:
3379 case XML_ENTITY_REF_NODE:
3380 case XML_ENTITY_NODE:
3381 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003382#ifdef LIBXML_DOCB_ENABLED
3383 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003384#endif
3385 case XML_XINCLUDE_START:
3386 case XML_XINCLUDE_END:
3387 return;
3388 case XML_ELEMENT_NODE:
3389 case XML_ATTRIBUTE_NODE:
3390 break;
3391 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003392 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3393 if (ns == NULL)
3394 return;
3395 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003396}
3397
3398/**
3399 * xmlNodeGetLang:
3400 * @cur: the node being checked
3401 *
3402 * Searches the language of a node, i.e. the values of the xml:lang
3403 * attribute or the one carried by the nearest ancestor.
3404 *
3405 * Returns a pointer to the lang value, or NULL if not found
3406 * It's up to the caller to free the memory.
3407 */
3408xmlChar *
3409xmlNodeGetLang(xmlNodePtr cur) {
3410 xmlChar *lang;
3411
3412 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003413 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003414 if (lang != NULL)
3415 return(lang);
3416 cur = cur->parent;
3417 }
3418 return(NULL);
3419}
3420
3421
3422/**
3423 * xmlNodeSetSpacePreserve:
3424 * @cur: the node being changed
3425 * @val: the xml:space value ("0": default, 1: "preserve")
3426 *
3427 * Set (or reset) the space preserving behaviour of a node, i.e. the
3428 * value of the xml:space attribute.
3429 */
3430void
3431xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003432 xmlNsPtr ns;
3433
Owen Taylor3473f882001-02-23 17:55:21 +00003434 if (cur == NULL) return;
3435 switch(cur->type) {
3436 case XML_TEXT_NODE:
3437 case XML_CDATA_SECTION_NODE:
3438 case XML_COMMENT_NODE:
3439 case XML_DOCUMENT_NODE:
3440 case XML_DOCUMENT_TYPE_NODE:
3441 case XML_DOCUMENT_FRAG_NODE:
3442 case XML_NOTATION_NODE:
3443 case XML_HTML_DOCUMENT_NODE:
3444 case XML_DTD_NODE:
3445 case XML_ELEMENT_DECL:
3446 case XML_ATTRIBUTE_DECL:
3447 case XML_ENTITY_DECL:
3448 case XML_PI_NODE:
3449 case XML_ENTITY_REF_NODE:
3450 case XML_ENTITY_NODE:
3451 case XML_NAMESPACE_DECL:
3452 case XML_XINCLUDE_START:
3453 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003454#ifdef LIBXML_DOCB_ENABLED
3455 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003456#endif
3457 return;
3458 case XML_ELEMENT_NODE:
3459 case XML_ATTRIBUTE_NODE:
3460 break;
3461 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003462 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3463 if (ns == NULL)
3464 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003465 switch (val) {
3466 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003467 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003468 break;
3469 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003470 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003471 break;
3472 }
3473}
3474
3475/**
3476 * xmlNodeGetSpacePreserve:
3477 * @cur: the node being checked
3478 *
3479 * Searches the space preserving behaviour of a node, i.e. the values
3480 * of the xml:space attribute or the one carried by the nearest
3481 * ancestor.
3482 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003483 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003484 */
3485int
3486xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3487 xmlChar *space;
3488
3489 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003490 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003491 if (space != NULL) {
3492 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3493 xmlFree(space);
3494 return(1);
3495 }
3496 if (xmlStrEqual(space, BAD_CAST "default")) {
3497 xmlFree(space);
3498 return(0);
3499 }
3500 xmlFree(space);
3501 }
3502 cur = cur->parent;
3503 }
3504 return(-1);
3505}
3506
3507/**
3508 * xmlNodeSetName:
3509 * @cur: the node being changed
3510 * @name: the new tag name
3511 *
3512 * Set (or reset) the name of a node.
3513 */
3514void
3515xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3516 if (cur == NULL) return;
3517 if (name == NULL) return;
3518 switch(cur->type) {
3519 case XML_TEXT_NODE:
3520 case XML_CDATA_SECTION_NODE:
3521 case XML_COMMENT_NODE:
3522 case XML_DOCUMENT_TYPE_NODE:
3523 case XML_DOCUMENT_FRAG_NODE:
3524 case XML_NOTATION_NODE:
3525 case XML_HTML_DOCUMENT_NODE:
3526 case XML_NAMESPACE_DECL:
3527 case XML_XINCLUDE_START:
3528 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003529#ifdef LIBXML_DOCB_ENABLED
3530 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003531#endif
3532 return;
3533 case XML_ELEMENT_NODE:
3534 case XML_ATTRIBUTE_NODE:
3535 case XML_PI_NODE:
3536 case XML_ENTITY_REF_NODE:
3537 case XML_ENTITY_NODE:
3538 case XML_DTD_NODE:
3539 case XML_DOCUMENT_NODE:
3540 case XML_ELEMENT_DECL:
3541 case XML_ATTRIBUTE_DECL:
3542 case XML_ENTITY_DECL:
3543 break;
3544 }
3545 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3546 cur->name = xmlStrdup(name);
3547}
3548
3549/**
3550 * xmlNodeSetBase:
3551 * @cur: the node being changed
3552 * @uri: the new base URI
3553 *
3554 * Set (or reset) the base URI of a node, i.e. the value of the
3555 * xml:base attribute.
3556 */
3557void
3558xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003559 xmlNsPtr ns;
3560
Owen Taylor3473f882001-02-23 17:55:21 +00003561 if (cur == NULL) return;
3562 switch(cur->type) {
3563 case XML_TEXT_NODE:
3564 case XML_CDATA_SECTION_NODE:
3565 case XML_COMMENT_NODE:
3566 case XML_DOCUMENT_NODE:
3567 case XML_DOCUMENT_TYPE_NODE:
3568 case XML_DOCUMENT_FRAG_NODE:
3569 case XML_NOTATION_NODE:
3570 case XML_HTML_DOCUMENT_NODE:
3571 case XML_DTD_NODE:
3572 case XML_ELEMENT_DECL:
3573 case XML_ATTRIBUTE_DECL:
3574 case XML_ENTITY_DECL:
3575 case XML_PI_NODE:
3576 case XML_ENTITY_REF_NODE:
3577 case XML_ENTITY_NODE:
3578 case XML_NAMESPACE_DECL:
3579 case XML_XINCLUDE_START:
3580 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003581#ifdef LIBXML_DOCB_ENABLED
3582 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003583#endif
3584 return;
3585 case XML_ELEMENT_NODE:
3586 case XML_ATTRIBUTE_NODE:
3587 break;
3588 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003589
3590 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3591 if (ns == NULL)
3592 return;
3593 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003594}
3595
3596/**
Owen Taylor3473f882001-02-23 17:55:21 +00003597 * xmlNodeGetBase:
3598 * @doc: the document the node pertains to
3599 * @cur: the node being checked
3600 *
3601 * Searches for the BASE URL. The code should work on both XML
3602 * and HTML document even if base mechanisms are completely different.
3603 * It returns the base as defined in RFC 2396 sections
3604 * 5.1.1. Base URI within Document Content
3605 * and
3606 * 5.1.2. Base URI from the Encapsulating Entity
3607 * However it does not return the document base (5.1.3), use
3608 * xmlDocumentGetBase() for this
3609 *
3610 * Returns a pointer to the base URL, or NULL if not found
3611 * It's up to the caller to free the memory.
3612 */
3613xmlChar *
3614xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003615 xmlChar *oldbase = NULL;
3616 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003617
3618 if ((cur == NULL) && (doc == NULL))
3619 return(NULL);
3620 if (doc == NULL) doc = cur->doc;
3621 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3622 cur = doc->children;
3623 while ((cur != NULL) && (cur->name != NULL)) {
3624 if (cur->type != XML_ELEMENT_NODE) {
3625 cur = cur->next;
3626 continue;
3627 }
3628 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3629 cur = cur->children;
3630 continue;
3631 }
3632 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3633 cur = cur->children;
3634 continue;
3635 }
3636 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3637 return(xmlGetProp(cur, BAD_CAST "href"));
3638 }
3639 cur = cur->next;
3640 }
3641 return(NULL);
3642 }
3643 while (cur != NULL) {
3644 if (cur->type == XML_ENTITY_DECL) {
3645 xmlEntityPtr ent = (xmlEntityPtr) cur;
3646 return(xmlStrdup(ent->URI));
3647 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003648 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003649 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003650 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003651 if (oldbase != NULL) {
3652 newbase = xmlBuildURI(oldbase, base);
3653 if (newbase != NULL) {
3654 xmlFree(oldbase);
3655 xmlFree(base);
3656 oldbase = newbase;
3657 } else {
3658 xmlFree(oldbase);
3659 xmlFree(base);
3660 return(NULL);
3661 }
3662 } else {
3663 oldbase = base;
3664 }
3665 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3666 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3667 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3668 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003669 }
3670 }
Owen Taylor3473f882001-02-23 17:55:21 +00003671 cur = cur->parent;
3672 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003673 if ((doc != NULL) && (doc->URL != NULL)) {
3674 if (oldbase == NULL)
3675 return(xmlStrdup(doc->URL));
3676 newbase = xmlBuildURI(oldbase, doc->URL);
3677 xmlFree(oldbase);
3678 return(newbase);
3679 }
3680 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003681}
3682
3683/**
3684 * xmlNodeGetContent:
3685 * @cur: the node being read
3686 *
3687 * Read the value of a node, this can be either the text carried
3688 * directly by this node if it's a TEXT node or the aggregate string
3689 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003690 * Entity references are substituted.
3691 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003692 * It's up to the caller to free the memory.
3693 */
3694xmlChar *
3695xmlNodeGetContent(xmlNodePtr cur) {
3696 if (cur == NULL) return(NULL);
3697 switch (cur->type) {
3698 case XML_DOCUMENT_FRAG_NODE:
3699 case XML_ELEMENT_NODE: {
3700 xmlNodePtr tmp = cur;
3701 xmlBufferPtr buffer;
3702 xmlChar *ret;
3703
3704 buffer = xmlBufferCreate();
3705 if (buffer == NULL)
3706 return(NULL);
3707 while (tmp != NULL) {
3708 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003709 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003710 case XML_TEXT_NODE:
3711 if (tmp->content != NULL)
3712#ifndef XML_USE_BUFFER_CONTENT
3713 xmlBufferCat(buffer, tmp->content);
3714#else
3715 xmlBufferCat(buffer,
3716 xmlBufferContent(tmp->content));
3717#endif
3718 break;
3719 case XML_ENTITY_REF_NODE: {
3720 xmlEntityPtr ent;
3721
3722 ent = xmlGetDocEntity(cur->doc, tmp->name);
3723 if (ent != NULL)
3724 xmlBufferCat(buffer, ent->content);
3725 }
3726 default:
3727 break;
3728 }
3729 /*
3730 * Skip to next node
3731 */
3732 if (tmp->children != NULL) {
3733 if (tmp->children->type != XML_ENTITY_DECL) {
3734 tmp = tmp->children;
3735 continue;
3736 }
3737 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003738 if (tmp == cur)
3739 break;
3740
Owen Taylor3473f882001-02-23 17:55:21 +00003741 if (tmp->next != NULL) {
3742 tmp = tmp->next;
3743 continue;
3744 }
3745
3746 do {
3747 tmp = tmp->parent;
3748 if (tmp == NULL)
3749 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003750 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003751 tmp = NULL;
3752 break;
3753 }
3754 if (tmp->next != NULL) {
3755 tmp = tmp->next;
3756 break;
3757 }
3758 } while (tmp != NULL);
3759 }
3760 ret = buffer->content;
3761 buffer->content = NULL;
3762 xmlBufferFree(buffer);
3763 return(ret);
3764 }
3765 case XML_ATTRIBUTE_NODE: {
3766 xmlAttrPtr attr = (xmlAttrPtr) cur;
3767 if (attr->parent != NULL)
3768 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3769 else
3770 return(xmlNodeListGetString(NULL, attr->children, 1));
3771 break;
3772 }
3773 case XML_COMMENT_NODE:
3774 case XML_PI_NODE:
3775 if (cur->content != NULL)
3776#ifndef XML_USE_BUFFER_CONTENT
3777 return(xmlStrdup(cur->content));
3778#else
3779 return(xmlStrdup(xmlBufferContent(cur->content)));
3780#endif
3781 return(NULL);
3782 case XML_ENTITY_REF_NODE:
3783 /*
3784 * Locate the entity, and get it's content
3785 * @@@
3786 */
3787 return(NULL);
3788 case XML_ENTITY_NODE:
3789 case XML_DOCUMENT_NODE:
3790 case XML_HTML_DOCUMENT_NODE:
3791 case XML_DOCUMENT_TYPE_NODE:
3792 case XML_NOTATION_NODE:
3793 case XML_DTD_NODE:
3794 case XML_XINCLUDE_START:
3795 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003796#ifdef LIBXML_DOCB_ENABLED
3797 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003798#endif
3799 return(NULL);
3800 case XML_NAMESPACE_DECL:
3801 return(xmlStrdup(((xmlNsPtr)cur)->href));
3802 case XML_ELEMENT_DECL:
3803 /* TODO !!! */
3804 return(NULL);
3805 case XML_ATTRIBUTE_DECL:
3806 /* TODO !!! */
3807 return(NULL);
3808 case XML_ENTITY_DECL:
3809 /* TODO !!! */
3810 return(NULL);
3811 case XML_CDATA_SECTION_NODE:
3812 case XML_TEXT_NODE:
3813 if (cur->content != NULL)
3814#ifndef XML_USE_BUFFER_CONTENT
3815 return(xmlStrdup(cur->content));
3816#else
3817 return(xmlStrdup(xmlBufferContent(cur->content)));
3818#endif
3819 return(NULL);
3820 }
3821 return(NULL);
3822}
3823
3824/**
3825 * xmlNodeSetContent:
3826 * @cur: the node being modified
3827 * @content: the new value of the content
3828 *
3829 * Replace the content of a node.
3830 */
3831void
3832xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3833 if (cur == NULL) {
3834#ifdef DEBUG_TREE
3835 xmlGenericError(xmlGenericErrorContext,
3836 "xmlNodeSetContent : node == NULL\n");
3837#endif
3838 return;
3839 }
3840 switch (cur->type) {
3841 case XML_DOCUMENT_FRAG_NODE:
3842 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003843 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003844 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3845 cur->children = xmlStringGetNodeList(cur->doc, content);
3846 UPDATE_LAST_CHILD_AND_PARENT(cur)
3847 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003848 case XML_TEXT_NODE:
3849 case XML_CDATA_SECTION_NODE:
3850 case XML_ENTITY_REF_NODE:
3851 case XML_ENTITY_NODE:
3852 case XML_PI_NODE:
3853 case XML_COMMENT_NODE:
3854 if (cur->content != NULL) {
3855#ifndef XML_USE_BUFFER_CONTENT
3856 xmlFree(cur->content);
3857#else
3858 xmlBufferFree(cur->content);
3859#endif
3860 }
3861 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3862 cur->last = cur->children = NULL;
3863 if (content != NULL) {
3864#ifndef XML_USE_BUFFER_CONTENT
3865 cur->content = xmlStrdup(content);
3866#else
3867 cur->content = xmlBufferCreateSize(0);
3868 xmlBufferSetAllocationScheme(cur->content,
3869 xmlGetBufferAllocationScheme());
3870 xmlBufferAdd(cur->content, content, -1);
3871#endif
3872 } else
3873 cur->content = NULL;
3874 break;
3875 case XML_DOCUMENT_NODE:
3876 case XML_HTML_DOCUMENT_NODE:
3877 case XML_DOCUMENT_TYPE_NODE:
3878 case XML_XINCLUDE_START:
3879 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003880#ifdef LIBXML_DOCB_ENABLED
3881 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003882#endif
3883 break;
3884 case XML_NOTATION_NODE:
3885 break;
3886 case XML_DTD_NODE:
3887 break;
3888 case XML_NAMESPACE_DECL:
3889 break;
3890 case XML_ELEMENT_DECL:
3891 /* TODO !!! */
3892 break;
3893 case XML_ATTRIBUTE_DECL:
3894 /* TODO !!! */
3895 break;
3896 case XML_ENTITY_DECL:
3897 /* TODO !!! */
3898 break;
3899 }
3900}
3901
3902/**
3903 * xmlNodeSetContentLen:
3904 * @cur: the node being modified
3905 * @content: the new value of the content
3906 * @len: the size of @content
3907 *
3908 * Replace the content of a node.
3909 */
3910void
3911xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3912 if (cur == NULL) {
3913#ifdef DEBUG_TREE
3914 xmlGenericError(xmlGenericErrorContext,
3915 "xmlNodeSetContentLen : node == NULL\n");
3916#endif
3917 return;
3918 }
3919 switch (cur->type) {
3920 case XML_DOCUMENT_FRAG_NODE:
3921 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003922 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003923 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3924 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3925 UPDATE_LAST_CHILD_AND_PARENT(cur)
3926 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003927 case XML_TEXT_NODE:
3928 case XML_CDATA_SECTION_NODE:
3929 case XML_ENTITY_REF_NODE:
3930 case XML_ENTITY_NODE:
3931 case XML_PI_NODE:
3932 case XML_COMMENT_NODE:
3933 case XML_NOTATION_NODE:
3934 if (cur->content != NULL) {
3935#ifndef XML_USE_BUFFER_CONTENT
3936 xmlFree(cur->content);
3937#else
3938 xmlBufferFree(cur->content);
3939#endif
3940 }
3941 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3942 cur->children = cur->last = NULL;
3943 if (content != NULL) {
3944#ifndef XML_USE_BUFFER_CONTENT
3945 cur->content = xmlStrndup(content, len);
3946#else
3947 cur->content = xmlBufferCreateSize(len);
3948 xmlBufferSetAllocationScheme(cur->content,
3949 xmlGetBufferAllocationScheme());
3950 xmlBufferAdd(cur->content, content, len);
3951#endif
3952 } else
3953 cur->content = NULL;
3954 break;
3955 case XML_DOCUMENT_NODE:
3956 case XML_DTD_NODE:
3957 case XML_HTML_DOCUMENT_NODE:
3958 case XML_DOCUMENT_TYPE_NODE:
3959 case XML_NAMESPACE_DECL:
3960 case XML_XINCLUDE_START:
3961 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003962#ifdef LIBXML_DOCB_ENABLED
3963 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003964#endif
3965 break;
3966 case XML_ELEMENT_DECL:
3967 /* TODO !!! */
3968 break;
3969 case XML_ATTRIBUTE_DECL:
3970 /* TODO !!! */
3971 break;
3972 case XML_ENTITY_DECL:
3973 /* TODO !!! */
3974 break;
3975 }
3976}
3977
3978/**
3979 * xmlNodeAddContentLen:
3980 * @cur: the node being modified
3981 * @content: extra content
3982 * @len: the size of @content
3983 *
3984 * Append the extra substring to the node content.
3985 */
3986void
3987xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3988 if (cur == NULL) {
3989#ifdef DEBUG_TREE
3990 xmlGenericError(xmlGenericErrorContext,
3991 "xmlNodeAddContentLen : node == NULL\n");
3992#endif
3993 return;
3994 }
3995 if (len <= 0) return;
3996 switch (cur->type) {
3997 case XML_DOCUMENT_FRAG_NODE:
3998 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003999 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004000
Daniel Veillard7db37732001-07-12 01:20:08 +00004001 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004002 newNode = xmlNewTextLen(content, len);
4003 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004004 tmp = xmlAddChild(cur, newNode);
4005 if (tmp != newNode)
4006 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004007 if ((last != NULL) && (last->next == newNode)) {
4008 xmlTextMerge(last, newNode);
4009 }
4010 }
4011 break;
4012 }
4013 case XML_ATTRIBUTE_NODE:
4014 break;
4015 case XML_TEXT_NODE:
4016 case XML_CDATA_SECTION_NODE:
4017 case XML_ENTITY_REF_NODE:
4018 case XML_ENTITY_NODE:
4019 case XML_PI_NODE:
4020 case XML_COMMENT_NODE:
4021 case XML_NOTATION_NODE:
4022 if (content != NULL) {
4023#ifndef XML_USE_BUFFER_CONTENT
4024 cur->content = xmlStrncat(cur->content, content, len);
4025#else
4026 xmlBufferAdd(cur->content, content, len);
4027#endif
4028 }
4029 case XML_DOCUMENT_NODE:
4030 case XML_DTD_NODE:
4031 case XML_HTML_DOCUMENT_NODE:
4032 case XML_DOCUMENT_TYPE_NODE:
4033 case XML_NAMESPACE_DECL:
4034 case XML_XINCLUDE_START:
4035 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004036#ifdef LIBXML_DOCB_ENABLED
4037 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004038#endif
4039 break;
4040 case XML_ELEMENT_DECL:
4041 case XML_ATTRIBUTE_DECL:
4042 case XML_ENTITY_DECL:
4043 break;
4044 }
4045}
4046
4047/**
4048 * xmlNodeAddContent:
4049 * @cur: the node being modified
4050 * @content: extra content
4051 *
4052 * Append the extra substring to the node content.
4053 */
4054void
4055xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4056 int len;
4057
4058 if (cur == NULL) {
4059#ifdef DEBUG_TREE
4060 xmlGenericError(xmlGenericErrorContext,
4061 "xmlNodeAddContent : node == NULL\n");
4062#endif
4063 return;
4064 }
4065 if (content == NULL) return;
4066 len = xmlStrlen(content);
4067 xmlNodeAddContentLen(cur, content, len);
4068}
4069
4070/**
4071 * xmlTextMerge:
4072 * @first: the first text node
4073 * @second: the second text node being merged
4074 *
4075 * Merge two text nodes into one
4076 * Returns the first text node augmented
4077 */
4078xmlNodePtr
4079xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4080 if (first == NULL) return(second);
4081 if (second == NULL) return(first);
4082 if (first->type != XML_TEXT_NODE) return(first);
4083 if (second->type != XML_TEXT_NODE) return(first);
4084 if (second->name != first->name)
4085 return(first);
4086#ifndef XML_USE_BUFFER_CONTENT
4087 xmlNodeAddContent(first, second->content);
4088#else
4089 xmlNodeAddContent(first, xmlBufferContent(second->content));
4090#endif
4091 xmlUnlinkNode(second);
4092 xmlFreeNode(second);
4093 return(first);
4094}
4095
4096/**
4097 * xmlGetNsList:
4098 * @doc: the document
4099 * @node: the current node
4100 *
4101 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004102 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004103 * that need to be freed by the caller or NULL if no
4104 * namespace if defined
4105 */
4106xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004107xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4108{
Owen Taylor3473f882001-02-23 17:55:21 +00004109 xmlNsPtr cur;
4110 xmlNsPtr *ret = NULL;
4111 int nbns = 0;
4112 int maxns = 10;
4113 int i;
4114
4115 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004116 if (node->type == XML_ELEMENT_NODE) {
4117 cur = node->nsDef;
4118 while (cur != NULL) {
4119 if (ret == NULL) {
4120 ret =
4121 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4122 sizeof(xmlNsPtr));
4123 if (ret == NULL) {
4124 xmlGenericError(xmlGenericErrorContext,
4125 "xmlGetNsList : out of memory!\n");
4126 return (NULL);
4127 }
4128 ret[nbns] = NULL;
4129 }
4130 for (i = 0; i < nbns; i++) {
4131 if ((cur->prefix == ret[i]->prefix) ||
4132 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4133 break;
4134 }
4135 if (i >= nbns) {
4136 if (nbns >= maxns) {
4137 maxns *= 2;
4138 ret = (xmlNsPtr *) xmlRealloc(ret,
4139 (maxns +
4140 1) *
4141 sizeof(xmlNsPtr));
4142 if (ret == NULL) {
4143 xmlGenericError(xmlGenericErrorContext,
4144 "xmlGetNsList : realloc failed!\n");
4145 return (NULL);
4146 }
4147 }
4148 ret[nbns++] = cur;
4149 ret[nbns] = NULL;
4150 }
Owen Taylor3473f882001-02-23 17:55:21 +00004151
Daniel Veillard77044732001-06-29 21:31:07 +00004152 cur = cur->next;
4153 }
4154 }
4155 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004156 }
Daniel Veillard77044732001-06-29 21:31:07 +00004157 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004158}
4159
4160/**
4161 * xmlSearchNs:
4162 * @doc: the document
4163 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004164 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004165 *
4166 * Search a Ns registered under a given name space for a document.
4167 * recurse on the parents until it finds the defined namespace
4168 * or return NULL otherwise.
4169 * @nameSpace can be NULL, this is a search for the default namespace.
4170 * We don't allow to cross entities boundaries. If you don't declare
4171 * the namespace within those you will be in troubles !!! A warning
4172 * is generated to cover this case.
4173 *
4174 * Returns the namespace pointer or NULL.
4175 */
4176xmlNsPtr
4177xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4178 xmlNsPtr cur;
4179
4180 if (node == NULL) return(NULL);
4181 if ((nameSpace != NULL) &&
4182 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004183 if (doc == NULL)
4184 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004185 if (doc->oldNs == NULL) {
4186 /*
4187 * Allocate a new Namespace and fill the fields.
4188 */
4189 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4190 if (doc->oldNs == NULL) {
4191 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004192 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004193 return(NULL);
4194 }
4195 memset(doc->oldNs, 0, sizeof(xmlNs));
4196 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4197
4198 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4199 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4200 }
4201 return(doc->oldNs);
4202 }
4203 while (node != NULL) {
4204 if ((node->type == XML_ENTITY_REF_NODE) ||
4205 (node->type == XML_ENTITY_NODE) ||
4206 (node->type == XML_ENTITY_DECL))
4207 return(NULL);
4208 if (node->type == XML_ELEMENT_NODE) {
4209 cur = node->nsDef;
4210 while (cur != NULL) {
4211 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4212 (cur->href != NULL))
4213 return(cur);
4214 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4215 (cur->href != NULL) &&
4216 (xmlStrEqual(cur->prefix, nameSpace)))
4217 return(cur);
4218 cur = cur->next;
4219 }
4220 }
4221 node = node->parent;
4222 }
4223 return(NULL);
4224}
4225
4226/**
4227 * xmlSearchNsByHref:
4228 * @doc: the document
4229 * @node: the current node
4230 * @href: the namespace value
4231 *
4232 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4233 * the defined namespace or return NULL otherwise.
4234 * Returns the namespace pointer or NULL.
4235 */
4236xmlNsPtr
4237xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4238 xmlNsPtr cur;
4239 xmlNodePtr orig = node;
4240
4241 if ((node == NULL) || (href == NULL)) return(NULL);
4242 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004243 /*
4244 * Only the document can hold the XML spec namespace.
4245 */
4246 if (doc == NULL)
4247 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004248 if (doc->oldNs == NULL) {
4249 /*
4250 * Allocate a new Namespace and fill the fields.
4251 */
4252 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4253 if (doc->oldNs == NULL) {
4254 xmlGenericError(xmlGenericErrorContext,
4255 "xmlSearchNsByHref : malloc failed\n");
4256 return(NULL);
4257 }
4258 memset(doc->oldNs, 0, sizeof(xmlNs));
4259 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4260
4261 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4262 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4263 }
4264 return(doc->oldNs);
4265 }
4266 while (node != NULL) {
4267 cur = node->nsDef;
4268 while (cur != NULL) {
4269 if ((cur->href != NULL) && (href != NULL) &&
4270 (xmlStrEqual(cur->href, href))) {
4271 /*
4272 * Check that the prefix is not shadowed between orig and node
4273 */
4274 xmlNodePtr check = orig;
4275 xmlNsPtr tst;
4276
4277 while (check != node) {
4278 tst = check->nsDef;
4279 while (tst != NULL) {
4280 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4281 goto shadowed;
4282 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4283 (xmlStrEqual(tst->prefix, cur->prefix)))
4284 goto shadowed;
4285 tst = tst->next;
4286 }
4287 check = check->parent;
4288 }
4289 return(cur);
4290 }
4291shadowed:
4292 cur = cur->next;
4293 }
4294 node = node->parent;
4295 }
4296 return(NULL);
4297}
4298
4299/**
4300 * xmlNewReconciliedNs
4301 * @doc: the document
4302 * @tree: a node expected to hold the new namespace
4303 * @ns: the original namespace
4304 *
4305 * This function tries to locate a namespace definition in a tree
4306 * ancestors, or create a new namespace definition node similar to
4307 * @ns trying to reuse the same prefix. However if the given prefix is
4308 * null (default namespace) or reused within the subtree defined by
4309 * @tree or on one of its ancestors then a new prefix is generated.
4310 * Returns the (new) namespace definition or NULL in case of error
4311 */
4312xmlNsPtr
4313xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4314 xmlNsPtr def;
4315 xmlChar prefix[50];
4316 int counter = 1;
4317
4318 if (tree == NULL) {
4319#ifdef DEBUG_TREE
4320 xmlGenericError(xmlGenericErrorContext,
4321 "xmlNewReconciliedNs : tree == NULL\n");
4322#endif
4323 return(NULL);
4324 }
4325 if (ns == NULL) {
4326#ifdef DEBUG_TREE
4327 xmlGenericError(xmlGenericErrorContext,
4328 "xmlNewReconciliedNs : ns == NULL\n");
4329#endif
4330 return(NULL);
4331 }
4332 /*
4333 * Search an existing namespace definition inherited.
4334 */
4335 def = xmlSearchNsByHref(doc, tree, ns->href);
4336 if (def != NULL)
4337 return(def);
4338
4339 /*
4340 * Find a close prefix which is not already in use.
4341 * Let's strip namespace prefixes longer than 20 chars !
4342 */
4343 sprintf((char *) prefix, "%.20s", ns->prefix);
4344 def = xmlSearchNs(doc, tree, prefix);
4345 while (def != NULL) {
4346 if (counter > 1000) return(NULL);
4347 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4348 def = xmlSearchNs(doc, tree, prefix);
4349 }
4350
4351 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004352 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004353 */
4354 def = xmlNewNs(tree, ns->href, prefix);
4355 return(def);
4356}
4357
4358/**
4359 * xmlReconciliateNs
4360 * @doc: the document
4361 * @tree: a node defining the subtree to reconciliate
4362 *
4363 * This function checks that all the namespaces declared within the given
4364 * tree are properly declared. This is needed for example after Copy or Cut
4365 * and then paste operations. The subtree may still hold pointers to
4366 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004367 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004368 * the new environment. If not possible the new namespaces are redeclared
4369 * on @tree at the top of the given subtree.
4370 * Returns the number of namespace declarations created or -1 in case of error.
4371 */
4372int
4373xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4374 xmlNsPtr *oldNs = NULL;
4375 xmlNsPtr *newNs = NULL;
4376 int sizeCache = 0;
4377 int nbCache = 0;
4378
4379 xmlNsPtr n;
4380 xmlNodePtr node = tree;
4381 xmlAttrPtr attr;
4382 int ret = 0, i;
4383
4384 while (node != NULL) {
4385 /*
4386 * Reconciliate the node namespace
4387 */
4388 if (node->ns != NULL) {
4389 /*
4390 * initialize the cache if needed
4391 */
4392 if (sizeCache == 0) {
4393 sizeCache = 10;
4394 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4395 sizeof(xmlNsPtr));
4396 if (oldNs == NULL) {
4397 xmlGenericError(xmlGenericErrorContext,
4398 "xmlReconciliateNs : memory pbm\n");
4399 return(-1);
4400 }
4401 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4402 sizeof(xmlNsPtr));
4403 if (newNs == NULL) {
4404 xmlGenericError(xmlGenericErrorContext,
4405 "xmlReconciliateNs : memory pbm\n");
4406 xmlFree(oldNs);
4407 return(-1);
4408 }
4409 }
4410 for (i = 0;i < nbCache;i++) {
4411 if (oldNs[i] == node->ns) {
4412 node->ns = newNs[i];
4413 break;
4414 }
4415 }
4416 if (i == nbCache) {
4417 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004418 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004419 */
4420 n = xmlNewReconciliedNs(doc, tree, node->ns);
4421 if (n != NULL) { /* :-( what if else ??? */
4422 /*
4423 * check if we need to grow the cache buffers.
4424 */
4425 if (sizeCache <= nbCache) {
4426 sizeCache *= 2;
4427 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4428 sizeof(xmlNsPtr));
4429 if (oldNs == NULL) {
4430 xmlGenericError(xmlGenericErrorContext,
4431 "xmlReconciliateNs : memory pbm\n");
4432 xmlFree(newNs);
4433 return(-1);
4434 }
4435 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4436 sizeof(xmlNsPtr));
4437 if (newNs == NULL) {
4438 xmlGenericError(xmlGenericErrorContext,
4439 "xmlReconciliateNs : memory pbm\n");
4440 xmlFree(oldNs);
4441 return(-1);
4442 }
4443 }
4444 newNs[nbCache] = n;
4445 oldNs[nbCache++] = node->ns;
4446 node->ns = n;
4447 }
4448 }
4449 }
4450 /*
4451 * now check for namespace hold by attributes on the node.
4452 */
4453 attr = node->properties;
4454 while (attr != NULL) {
4455 if (attr->ns != NULL) {
4456 /*
4457 * initialize the cache if needed
4458 */
4459 if (sizeCache == 0) {
4460 sizeCache = 10;
4461 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4462 sizeof(xmlNsPtr));
4463 if (oldNs == NULL) {
4464 xmlGenericError(xmlGenericErrorContext,
4465 "xmlReconciliateNs : memory pbm\n");
4466 return(-1);
4467 }
4468 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4469 sizeof(xmlNsPtr));
4470 if (newNs == NULL) {
4471 xmlGenericError(xmlGenericErrorContext,
4472 "xmlReconciliateNs : memory pbm\n");
4473 xmlFree(oldNs);
4474 return(-1);
4475 }
4476 }
4477 for (i = 0;i < nbCache;i++) {
4478 if (oldNs[i] == attr->ns) {
4479 node->ns = newNs[i];
4480 break;
4481 }
4482 }
4483 if (i == nbCache) {
4484 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004485 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004486 */
4487 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4488 if (n != NULL) { /* :-( what if else ??? */
4489 /*
4490 * check if we need to grow the cache buffers.
4491 */
4492 if (sizeCache <= nbCache) {
4493 sizeCache *= 2;
4494 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4495 sizeof(xmlNsPtr));
4496 if (oldNs == NULL) {
4497 xmlGenericError(xmlGenericErrorContext,
4498 "xmlReconciliateNs : memory pbm\n");
4499 xmlFree(newNs);
4500 return(-1);
4501 }
4502 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4503 sizeof(xmlNsPtr));
4504 if (newNs == NULL) {
4505 xmlGenericError(xmlGenericErrorContext,
4506 "xmlReconciliateNs : memory pbm\n");
4507 xmlFree(oldNs);
4508 return(-1);
4509 }
4510 }
4511 newNs[nbCache] = n;
4512 oldNs[nbCache++] = attr->ns;
4513 attr->ns = n;
4514 }
4515 }
4516 }
4517 attr = attr->next;
4518 }
4519
4520 /*
4521 * Browse the full subtree, deep first
4522 */
4523 if (node->children != NULL) {
4524 /* deep first */
4525 node = node->children;
4526 } else if ((node != tree) && (node->next != NULL)) {
4527 /* then siblings */
4528 node = node->next;
4529 } else if (node != tree) {
4530 /* go up to parents->next if needed */
4531 while (node != tree) {
4532 if (node->parent != NULL)
4533 node = node->parent;
4534 if ((node != tree) && (node->next != NULL)) {
4535 node = node->next;
4536 break;
4537 }
4538 if (node->parent == NULL) {
4539 node = NULL;
4540 break;
4541 }
4542 }
4543 /* exit condition */
4544 if (node == tree)
4545 node = NULL;
4546 }
4547 }
4548 return(ret);
4549}
4550
4551/**
4552 * xmlHasProp:
4553 * @node: the node
4554 * @name: the attribute name
4555 *
4556 * Search an attribute associated to a node
4557 * This function also looks in DTD attribute declaration for #FIXED or
4558 * default declaration values unless DTD use has been turned off.
4559 *
4560 * Returns the attribute or the attribute declaration or NULL if
4561 * neither was found.
4562 */
4563xmlAttrPtr
4564xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4565 xmlAttrPtr prop;
4566 xmlDocPtr doc;
4567
4568 if ((node == NULL) || (name == NULL)) return(NULL);
4569 /*
4570 * Check on the properties attached to the node
4571 */
4572 prop = node->properties;
4573 while (prop != NULL) {
4574 if (xmlStrEqual(prop->name, name)) {
4575 return(prop);
4576 }
4577 prop = prop->next;
4578 }
4579 if (!xmlCheckDTD) return(NULL);
4580
4581 /*
4582 * Check if there is a default declaration in the internal
4583 * or external subsets
4584 */
4585 doc = node->doc;
4586 if (doc != NULL) {
4587 xmlAttributePtr attrDecl;
4588 if (doc->intSubset != NULL) {
4589 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4590 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4591 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4592 if (attrDecl != NULL)
4593 return((xmlAttrPtr) attrDecl);
4594 }
4595 }
4596 return(NULL);
4597}
4598
4599/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004600 * xmlHasNsProp:
4601 * @node: the node
4602 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004603 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004604 *
4605 * Search for an attribute associated to a node
4606 * This attribute has to be anchored in the namespace specified.
4607 * This does the entity substitution.
4608 * This function looks in DTD attribute declaration for #FIXED or
4609 * default declaration values unless DTD use has been turned off.
4610 *
4611 * Returns the attribute or the attribute declaration or NULL
4612 * if neither was found.
4613 */
4614xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004615xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004616 xmlAttrPtr prop;
4617 xmlDocPtr doc;
4618 xmlNsPtr ns;
4619
4620 if (node == NULL)
4621 return(NULL);
4622
4623 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004624 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004625 return(xmlHasProp(node, name));
4626 while (prop != NULL) {
4627 /*
4628 * One need to have
4629 * - same attribute names
4630 * - and the attribute carrying that namespace
4631 * or
4632 * no namespace on the attribute and the element carrying it
4633 */
4634 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004635 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4636 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004637 }
4638 prop = prop->next;
4639 }
4640 if (!xmlCheckDTD) return(NULL);
4641
4642 /*
4643 * Check if there is a default declaration in the internal
4644 * or external subsets
4645 */
4646 doc = node->doc;
4647 if (doc != NULL) {
4648 if (doc->intSubset != NULL) {
4649 xmlAttributePtr attrDecl;
4650
4651 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4652 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4653 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4654
4655 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4656 /*
4657 * The DTD declaration only allows a prefix search
4658 */
4659 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004660 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004661 return((xmlAttrPtr) attrDecl);
4662 }
4663 }
4664 }
4665 return(NULL);
4666}
4667
4668/**
Owen Taylor3473f882001-02-23 17:55:21 +00004669 * xmlGetProp:
4670 * @node: the node
4671 * @name: the attribute name
4672 *
4673 * Search and get the value of an attribute associated to a node
4674 * This does the entity substitution.
4675 * This function looks in DTD attribute declaration for #FIXED or
4676 * default declaration values unless DTD use has been turned off.
4677 *
4678 * Returns the attribute value or NULL if not found.
4679 * It's up to the caller to free the memory.
4680 */
4681xmlChar *
4682xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4683 xmlAttrPtr prop;
4684 xmlDocPtr doc;
4685
4686 if ((node == NULL) || (name == NULL)) return(NULL);
4687 /*
4688 * Check on the properties attached to the node
4689 */
4690 prop = node->properties;
4691 while (prop != NULL) {
4692 if (xmlStrEqual(prop->name, name)) {
4693 xmlChar *ret;
4694
4695 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4696 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4697 return(ret);
4698 }
4699 prop = prop->next;
4700 }
4701 if (!xmlCheckDTD) return(NULL);
4702
4703 /*
4704 * Check if there is a default declaration in the internal
4705 * or external subsets
4706 */
4707 doc = node->doc;
4708 if (doc != NULL) {
4709 xmlAttributePtr attrDecl;
4710 if (doc->intSubset != NULL) {
4711 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4712 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4713 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4714 if (attrDecl != NULL)
4715 return(xmlStrdup(attrDecl->defaultValue));
4716 }
4717 }
4718 return(NULL);
4719}
4720
4721/**
4722 * xmlGetNsProp:
4723 * @node: the node
4724 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004725 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004726 *
4727 * Search and get the value of an attribute associated to a node
4728 * This attribute has to be anchored in the namespace specified.
4729 * This does the entity substitution.
4730 * This function looks in DTD attribute declaration for #FIXED or
4731 * default declaration values unless DTD use has been turned off.
4732 *
4733 * Returns the attribute value or NULL if not found.
4734 * It's up to the caller to free the memory.
4735 */
4736xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004737xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004738 xmlAttrPtr prop;
4739 xmlDocPtr doc;
4740 xmlNsPtr ns;
4741
4742 if (node == NULL)
4743 return(NULL);
4744
4745 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004746 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004747 return(xmlGetProp(node, name));
4748 while (prop != NULL) {
4749 /*
4750 * One need to have
4751 * - same attribute names
4752 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004753 */
4754 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004755 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004756 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004757 xmlChar *ret;
4758
4759 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4760 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4761 return(ret);
4762 }
4763 prop = prop->next;
4764 }
4765 if (!xmlCheckDTD) return(NULL);
4766
4767 /*
4768 * Check if there is a default declaration in the internal
4769 * or external subsets
4770 */
4771 doc = node->doc;
4772 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004773 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004774 xmlAttributePtr attrDecl;
4775
Owen Taylor3473f882001-02-23 17:55:21 +00004776 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4777 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4778 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4779
4780 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4781 /*
4782 * The DTD declaration only allows a prefix search
4783 */
4784 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004785 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004786 return(xmlStrdup(attrDecl->defaultValue));
4787 }
4788 }
4789 }
4790 return(NULL);
4791}
4792
4793/**
4794 * xmlSetProp:
4795 * @node: the node
4796 * @name: the attribute name
4797 * @value: the attribute value
4798 *
4799 * Set (or reset) an attribute carried by a node.
4800 * Returns the attribute pointer.
4801 */
4802xmlAttrPtr
4803xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004804 xmlAttrPtr prop;
4805 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004806
4807 if ((node == NULL) || (name == NULL))
4808 return(NULL);
4809 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004810 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004811 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004812 if ((xmlStrEqual(prop->name, name)) &&
4813 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004814 xmlNodePtr oldprop = prop->children;
4815
Owen Taylor3473f882001-02-23 17:55:21 +00004816 prop->children = NULL;
4817 prop->last = NULL;
4818 if (value != NULL) {
4819 xmlChar *buffer;
4820 xmlNodePtr tmp;
4821
4822 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4823 prop->children = xmlStringGetNodeList(node->doc, buffer);
4824 prop->last = NULL;
4825 prop->doc = doc;
4826 tmp = prop->children;
4827 while (tmp != NULL) {
4828 tmp->parent = (xmlNodePtr) prop;
4829 tmp->doc = doc;
4830 if (tmp->next == NULL)
4831 prop->last = tmp;
4832 tmp = tmp->next;
4833 }
4834 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004835 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004836 if (oldprop != NULL)
4837 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004838 return(prop);
4839 }
4840 prop = prop->next;
4841 }
4842 prop = xmlNewProp(node, name, value);
4843 return(prop);
4844}
4845
4846/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004847 * xmlUnsetProp:
4848 * @node: the node
4849 * @name: the attribute name
4850 *
4851 * Remove an attribute carried by a node.
4852 * Returns 0 if successful, -1 if not found
4853 */
4854int
4855xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4856 xmlAttrPtr prop = node->properties, prev = NULL;;
4857
4858 if ((node == NULL) || (name == NULL))
4859 return(-1);
4860 while (prop != NULL) {
4861 if ((xmlStrEqual(prop->name, name)) &&
4862 (prop->ns == NULL)) {
4863 if (prev == NULL)
4864 node->properties = prop->next;
4865 else
4866 prev->next = prop->next;
4867 xmlFreeProp(prop);
4868 return(0);
4869 }
4870 prev = prop;
4871 prop = prop->next;
4872 }
4873 return(-1);
4874}
4875
4876/**
Owen Taylor3473f882001-02-23 17:55:21 +00004877 * xmlSetNsProp:
4878 * @node: the node
4879 * @ns: the namespace definition
4880 * @name: the attribute name
4881 * @value: the attribute value
4882 *
4883 * Set (or reset) an attribute carried by a node.
4884 * The ns structure must be in scope, this is not checked.
4885 *
4886 * Returns the attribute pointer.
4887 */
4888xmlAttrPtr
4889xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4890 const xmlChar *value) {
4891 xmlAttrPtr prop;
4892
4893 if ((node == NULL) || (name == NULL))
4894 return(NULL);
4895
4896 if (ns == NULL)
4897 return(xmlSetProp(node, name, value));
4898 if (ns->href == NULL)
4899 return(NULL);
4900 prop = node->properties;
4901
4902 while (prop != NULL) {
4903 /*
4904 * One need to have
4905 * - same attribute names
4906 * - and the attribute carrying that namespace
4907 * or
4908 * no namespace on the attribute and the element carrying it
4909 */
4910 if ((xmlStrEqual(prop->name, name)) &&
4911 (((prop->ns == NULL) && (node->ns != NULL) &&
4912 (xmlStrEqual(node->ns->href, ns->href))) ||
4913 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4914 if (prop->children != NULL)
4915 xmlFreeNodeList(prop->children);
4916 prop->children = NULL;
4917 prop->last = NULL;
4918 prop->ns = ns;
4919 if (value != NULL) {
4920 xmlChar *buffer;
4921 xmlNodePtr tmp;
4922
4923 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4924 prop->children = xmlStringGetNodeList(node->doc, buffer);
4925 prop->last = NULL;
4926 tmp = prop->children;
4927 while (tmp != NULL) {
4928 tmp->parent = (xmlNodePtr) prop;
4929 if (tmp->next == NULL)
4930 prop->last = tmp;
4931 tmp = tmp->next;
4932 }
4933 xmlFree(buffer);
4934 }
4935 return(prop);
4936 }
4937 prop = prop->next;
4938 }
4939 prop = xmlNewNsProp(node, ns, name, value);
4940 return(prop);
4941}
4942
4943/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004944 * xmlUnsetNsProp:
4945 * @node: the node
4946 * @ns: the namespace definition
4947 * @name: the attribute name
4948 *
4949 * Remove an attribute carried by a node.
4950 * Returns 0 if successful, -1 if not found
4951 */
4952int
4953xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4954 xmlAttrPtr prop = node->properties, prev = NULL;;
4955
4956 if ((node == NULL) || (name == NULL))
4957 return(-1);
4958 if (ns == NULL)
4959 return(xmlUnsetProp(node, name));
4960 if (ns->href == NULL)
4961 return(-1);
4962 while (prop != NULL) {
4963 if ((xmlStrEqual(prop->name, name)) &&
4964 (((prop->ns == NULL) && (node->ns != NULL) &&
4965 (xmlStrEqual(node->ns->href, ns->href))) ||
4966 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4967 if (prev == NULL)
4968 node->properties = prop->next;
4969 else
4970 prev->next = prop->next;
4971 xmlFreeProp(prop);
4972 return(0);
4973 }
4974 prev = prop;
4975 prop = prop->next;
4976 }
4977 return(-1);
4978}
4979
4980/**
Owen Taylor3473f882001-02-23 17:55:21 +00004981 * xmlNodeIsText:
4982 * @node: the node
4983 *
4984 * Is this node a Text node ?
4985 * Returns 1 yes, 0 no
4986 */
4987int
4988xmlNodeIsText(xmlNodePtr node) {
4989 if (node == NULL) return(0);
4990
4991 if (node->type == XML_TEXT_NODE) return(1);
4992 return(0);
4993}
4994
4995/**
4996 * xmlIsBlankNode:
4997 * @node: the node
4998 *
4999 * Checks whether this node is an empty or whitespace only
5000 * (and possibly ignorable) text-node.
5001 *
5002 * Returns 1 yes, 0 no
5003 */
5004int
5005xmlIsBlankNode(xmlNodePtr node) {
5006 const xmlChar *cur;
5007 if (node == NULL) return(0);
5008
Daniel Veillard7db37732001-07-12 01:20:08 +00005009 if ((node->type != XML_TEXT_NODE) &&
5010 (node->type != XML_CDATA_SECTION_NODE))
5011 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005012 if (node->content == NULL) return(1);
5013#ifndef XML_USE_BUFFER_CONTENT
5014 cur = node->content;
5015#else
5016 cur = xmlBufferContent(node->content);
5017#endif
5018 while (*cur != 0) {
5019 if (!IS_BLANK(*cur)) return(0);
5020 cur++;
5021 }
5022
5023 return(1);
5024}
5025
5026/**
5027 * xmlTextConcat:
5028 * @node: the node
5029 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005030 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005031 *
5032 * Concat the given string at the end of the existing node content
5033 */
5034
5035void
5036xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5037 if (node == NULL) return;
5038
5039 if ((node->type != XML_TEXT_NODE) &&
5040 (node->type != XML_CDATA_SECTION_NODE)) {
5041#ifdef DEBUG_TREE
5042 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005043 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005044#endif
5045 return;
5046 }
5047#ifndef XML_USE_BUFFER_CONTENT
5048 node->content = xmlStrncat(node->content, content, len);
5049#else
5050 xmlBufferAdd(node->content, content, len);
5051#endif
5052}
5053
5054/************************************************************************
5055 * *
5056 * Output : to a FILE or in memory *
5057 * *
5058 ************************************************************************/
5059
Owen Taylor3473f882001-02-23 17:55:21 +00005060/**
5061 * xmlBufferCreate:
5062 *
5063 * routine to create an XML buffer.
5064 * returns the new structure.
5065 */
5066xmlBufferPtr
5067xmlBufferCreate(void) {
5068 xmlBufferPtr ret;
5069
5070 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5071 if (ret == NULL) {
5072 xmlGenericError(xmlGenericErrorContext,
5073 "xmlBufferCreate : out of memory!\n");
5074 return(NULL);
5075 }
5076 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005077 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005078 ret->alloc = xmlBufferAllocScheme;
5079 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5080 if (ret->content == NULL) {
5081 xmlGenericError(xmlGenericErrorContext,
5082 "xmlBufferCreate : out of memory!\n");
5083 xmlFree(ret);
5084 return(NULL);
5085 }
5086 ret->content[0] = 0;
5087 return(ret);
5088}
5089
5090/**
5091 * xmlBufferCreateSize:
5092 * @size: initial size of buffer
5093 *
5094 * routine to create an XML buffer.
5095 * returns the new structure.
5096 */
5097xmlBufferPtr
5098xmlBufferCreateSize(size_t size) {
5099 xmlBufferPtr ret;
5100
5101 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5102 if (ret == NULL) {
5103 xmlGenericError(xmlGenericErrorContext,
5104 "xmlBufferCreate : out of memory!\n");
5105 return(NULL);
5106 }
5107 ret->use = 0;
5108 ret->alloc = xmlBufferAllocScheme;
5109 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5110 if (ret->size){
5111 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5112 if (ret->content == NULL) {
5113 xmlGenericError(xmlGenericErrorContext,
5114 "xmlBufferCreate : out of memory!\n");
5115 xmlFree(ret);
5116 return(NULL);
5117 }
5118 ret->content[0] = 0;
5119 } else
5120 ret->content = NULL;
5121 return(ret);
5122}
5123
5124/**
5125 * xmlBufferSetAllocationScheme:
5126 * @buf: the buffer to free
5127 * @scheme: allocation scheme to use
5128 *
5129 * Sets the allocation scheme for this buffer
5130 */
5131void
5132xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5133 xmlBufferAllocationScheme scheme) {
5134 if (buf == NULL) {
5135#ifdef DEBUG_BUFFER
5136 xmlGenericError(xmlGenericErrorContext,
5137 "xmlBufferSetAllocationScheme: buf == NULL\n");
5138#endif
5139 return;
5140 }
5141
5142 buf->alloc = scheme;
5143}
5144
5145/**
5146 * xmlBufferFree:
5147 * @buf: the buffer to free
5148 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005149 * Frees an XML buffer. It frees both the content and the structure which
5150 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005151 */
5152void
5153xmlBufferFree(xmlBufferPtr buf) {
5154 if (buf == NULL) {
5155#ifdef DEBUG_BUFFER
5156 xmlGenericError(xmlGenericErrorContext,
5157 "xmlBufferFree: buf == NULL\n");
5158#endif
5159 return;
5160 }
5161 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005162 xmlFree(buf->content);
5163 }
Owen Taylor3473f882001-02-23 17:55:21 +00005164 xmlFree(buf);
5165}
5166
5167/**
5168 * xmlBufferEmpty:
5169 * @buf: the buffer
5170 *
5171 * empty a buffer.
5172 */
5173void
5174xmlBufferEmpty(xmlBufferPtr buf) {
5175 if (buf->content == NULL) return;
5176 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005177 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005178}
5179
5180/**
5181 * xmlBufferShrink:
5182 * @buf: the buffer to dump
5183 * @len: the number of xmlChar to remove
5184 *
5185 * Remove the beginning of an XML buffer.
5186 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005187 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005188 */
5189int
5190xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5191 if (len == 0) return(0);
5192 if (len > buf->use) return(-1);
5193
5194 buf->use -= len;
5195 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5196
5197 buf->content[buf->use] = 0;
5198 return(len);
5199}
5200
5201/**
5202 * xmlBufferGrow:
5203 * @buf: the buffer
5204 * @len: the minimum free size to allocate
5205 *
5206 * Grow the available space of an XML buffer.
5207 *
5208 * Returns the new available space or -1 in case of error
5209 */
5210int
5211xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5212 int size;
5213 xmlChar *newbuf;
5214
5215 if (len + buf->use < buf->size) return(0);
5216
5217 size = buf->use + len + 100;
5218
5219 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5220 if (newbuf == NULL) return(-1);
5221 buf->content = newbuf;
5222 buf->size = size;
5223 return(buf->size - buf->use);
5224}
5225
5226/**
5227 * xmlBufferDump:
5228 * @file: the file output
5229 * @buf: the buffer to dump
5230 *
5231 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005232 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005233 */
5234int
5235xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5236 int ret;
5237
5238 if (buf == NULL) {
5239#ifdef DEBUG_BUFFER
5240 xmlGenericError(xmlGenericErrorContext,
5241 "xmlBufferDump: buf == NULL\n");
5242#endif
5243 return(0);
5244 }
5245 if (buf->content == NULL) {
5246#ifdef DEBUG_BUFFER
5247 xmlGenericError(xmlGenericErrorContext,
5248 "xmlBufferDump: buf->content == NULL\n");
5249#endif
5250 return(0);
5251 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005252 if (file == NULL)
5253 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005254 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5255 return(ret);
5256}
5257
5258/**
5259 * xmlBufferContent:
5260 * @buf: the buffer
5261 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005262 * Function to extract the content of a buffer
5263 *
Owen Taylor3473f882001-02-23 17:55:21 +00005264 * Returns the internal content
5265 */
5266
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005267const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005268xmlBufferContent(const xmlBufferPtr buf)
5269{
5270 if(!buf)
5271 return NULL;
5272
5273 return buf->content;
5274}
5275
5276/**
5277 * xmlBufferLength:
5278 * @buf: the buffer
5279 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005280 * Function to get the length of a buffer
5281 *
Owen Taylor3473f882001-02-23 17:55:21 +00005282 * Returns the length of data in the internal content
5283 */
5284
5285int
5286xmlBufferLength(const xmlBufferPtr buf)
5287{
5288 if(!buf)
5289 return 0;
5290
5291 return buf->use;
5292}
5293
5294/**
5295 * xmlBufferResize:
5296 * @buf: the buffer to resize
5297 * @size: the desired size
5298 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005299 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005300 *
5301 * Returns 0 in case of problems, 1 otherwise
5302 */
5303int
5304xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5305{
5306 unsigned int newSize;
5307 xmlChar* rebuf = NULL;
5308
5309 /*take care of empty case*/
5310 newSize = (buf->size ? buf->size*2 : size);
5311
5312 /* Don't resize if we don't have to */
5313 if (size < buf->size)
5314 return 1;
5315
5316 /* figure out new size */
5317 switch (buf->alloc){
5318 case XML_BUFFER_ALLOC_DOUBLEIT:
5319 while (size > newSize) newSize *= 2;
5320 break;
5321 case XML_BUFFER_ALLOC_EXACT:
5322 newSize = size+10;
5323 break;
5324 default:
5325 newSize = size+10;
5326 break;
5327 }
5328
5329 if (buf->content == NULL)
5330 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5331 else
5332 rebuf = (xmlChar *) xmlRealloc(buf->content,
5333 newSize * sizeof(xmlChar));
5334 if (rebuf == NULL) {
5335 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005336 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005337 return 0;
5338 }
5339 buf->content = rebuf;
5340 buf->size = newSize;
5341
5342 return 1;
5343}
5344
5345/**
5346 * xmlBufferAdd:
5347 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005348 * @str: the #xmlChar string
5349 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005350 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005351 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005352 * str is recomputed.
5353 */
5354void
5355xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5356 unsigned int needSize;
5357
5358 if (str == NULL) {
5359#ifdef DEBUG_BUFFER
5360 xmlGenericError(xmlGenericErrorContext,
5361 "xmlBufferAdd: str == NULL\n");
5362#endif
5363 return;
5364 }
5365 if (len < -1) {
5366#ifdef DEBUG_BUFFER
5367 xmlGenericError(xmlGenericErrorContext,
5368 "xmlBufferAdd: len < 0\n");
5369#endif
5370 return;
5371 }
5372 if (len == 0) return;
5373
5374 if (len < 0)
5375 len = xmlStrlen(str);
5376
5377 if (len <= 0) return;
5378
5379 needSize = buf->use + len + 2;
5380 if (needSize > buf->size){
5381 if (!xmlBufferResize(buf, needSize)){
5382 xmlGenericError(xmlGenericErrorContext,
5383 "xmlBufferAdd : out of memory!\n");
5384 return;
5385 }
5386 }
5387
5388 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5389 buf->use += len;
5390 buf->content[buf->use] = 0;
5391}
5392
5393/**
5394 * xmlBufferAddHead:
5395 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005396 * @str: the #xmlChar string
5397 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005398 *
5399 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005400 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005401 */
5402void
5403xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5404 unsigned int needSize;
5405
5406 if (str == NULL) {
5407#ifdef DEBUG_BUFFER
5408 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005409 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005410#endif
5411 return;
5412 }
5413 if (len < -1) {
5414#ifdef DEBUG_BUFFER
5415 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005416 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005417#endif
5418 return;
5419 }
5420 if (len == 0) return;
5421
5422 if (len < 0)
5423 len = xmlStrlen(str);
5424
5425 if (len <= 0) return;
5426
5427 needSize = buf->use + len + 2;
5428 if (needSize > buf->size){
5429 if (!xmlBufferResize(buf, needSize)){
5430 xmlGenericError(xmlGenericErrorContext,
5431 "xmlBufferAddHead : out of memory!\n");
5432 return;
5433 }
5434 }
5435
5436 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5437 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5438 buf->use += len;
5439 buf->content[buf->use] = 0;
5440}
5441
5442/**
5443 * xmlBufferCat:
5444 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005445 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005446 *
5447 * Append a zero terminated string to an XML buffer.
5448 */
5449void
5450xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5451 if (str != NULL)
5452 xmlBufferAdd(buf, str, -1);
5453}
5454
5455/**
5456 * xmlBufferCCat:
5457 * @buf: the buffer to dump
5458 * @str: the C char string
5459 *
5460 * Append a zero terminated C string to an XML buffer.
5461 */
5462void
5463xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5464 const char *cur;
5465
5466 if (str == NULL) {
5467#ifdef DEBUG_BUFFER
5468 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005469 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005470#endif
5471 return;
5472 }
5473 for (cur = str;*cur != 0;cur++) {
5474 if (buf->use + 10 >= buf->size) {
5475 if (!xmlBufferResize(buf, buf->use+10)){
5476 xmlGenericError(xmlGenericErrorContext,
5477 "xmlBufferCCat : out of memory!\n");
5478 return;
5479 }
5480 }
5481 buf->content[buf->use++] = *cur;
5482 }
5483 buf->content[buf->use] = 0;
5484}
5485
5486/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005487 * xmlBufferWriteXmlCHAR:
5488 * @buf: the XML buffer
5489 * @string: the string to add
5490 *
5491 * For VMS only.
5492 * routine which manages and grows an output buffer. This one adds
5493 * xmlChars at the end of the buffer.
5494 */
5495/**
Owen Taylor3473f882001-02-23 17:55:21 +00005496 * xmlBufferWriteCHAR:
5497 * @buf: the XML buffer
5498 * @string: the string to add
5499 *
5500 * routine which manages and grows an output buffer. This one adds
5501 * xmlChars at the end of the buffer.
5502 */
5503void
5504#ifdef VMS
5505xmlBufferWriteXmlCHAR
5506#else
5507xmlBufferWriteCHAR
5508#endif
5509(xmlBufferPtr buf, const xmlChar *string) {
5510 xmlBufferCat(buf, string);
5511}
5512
5513/**
5514 * xmlBufferWriteChar:
5515 * @buf: the XML buffer output
5516 * @string: the string to add
5517 *
5518 * routine which manage and grows an output buffer. This one add
5519 * C chars at the end of the array.
5520 */
5521void
5522xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5523 xmlBufferCCat(buf, string);
5524}
5525
5526
5527/**
5528 * xmlBufferWriteQuotedString:
5529 * @buf: the XML buffer output
5530 * @string: the string to add
5531 *
5532 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005533 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005534 * quote or double-quotes internally
5535 */
5536void
5537xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5538 if (xmlStrchr(string, '"')) {
5539 if (xmlStrchr(string, '\'')) {
5540#ifdef DEBUG_BUFFER
5541 xmlGenericError(xmlGenericErrorContext,
5542 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5543#endif
5544 }
5545 xmlBufferCCat(buf, "'");
5546 xmlBufferCat(buf, string);
5547 xmlBufferCCat(buf, "'");
5548 } else {
5549 xmlBufferCCat(buf, "\"");
5550 xmlBufferCat(buf, string);
5551 xmlBufferCCat(buf, "\"");
5552 }
5553}
5554
5555
5556/************************************************************************
5557 * *
5558 * Dumping XML tree content to a simple buffer *
5559 * *
5560 ************************************************************************/
5561
5562void
5563xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5564 int format);
5565static void
5566xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5567 int format);
5568void
5569htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5570
5571/**
5572 * xmlNsDump:
5573 * @buf: the XML buffer output
5574 * @cur: a namespace
5575 *
5576 * Dump a local Namespace definition.
5577 * Should be called in the context of attributes dumps.
5578 */
5579static void
5580xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5581 if (cur == NULL) {
5582#ifdef DEBUG_TREE
5583 xmlGenericError(xmlGenericErrorContext,
5584 "xmlNsDump : Ns == NULL\n");
5585#endif
5586 return;
5587 }
5588 if (cur->type == XML_LOCAL_NAMESPACE) {
5589 /* Within the context of an element attributes */
5590 if (cur->prefix != NULL) {
5591 xmlBufferWriteChar(buf, " xmlns:");
5592 xmlBufferWriteCHAR(buf, cur->prefix);
5593 } else
5594 xmlBufferWriteChar(buf, " xmlns");
5595 xmlBufferWriteChar(buf, "=");
5596 xmlBufferWriteQuotedString(buf, cur->href);
5597 }
5598}
5599
5600/**
5601 * xmlNsListDump:
5602 * @buf: the XML buffer output
5603 * @cur: the first namespace
5604 *
5605 * Dump a list of local Namespace definitions.
5606 * Should be called in the context of attributes dumps.
5607 */
5608static void
5609xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5610 while (cur != NULL) {
5611 xmlNsDump(buf, cur);
5612 cur = cur->next;
5613 }
5614}
5615
5616/**
5617 * xmlDtdDump:
5618 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005619 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005620 *
5621 * Dump the XML document DTD, if any.
5622 */
5623static void
5624xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5625 if (dtd == NULL) {
5626#ifdef DEBUG_TREE
5627 xmlGenericError(xmlGenericErrorContext,
5628 "xmlDtdDump : no internal subset\n");
5629#endif
5630 return;
5631 }
5632 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5633 xmlBufferWriteCHAR(buf, dtd->name);
5634 if (dtd->ExternalID != NULL) {
5635 xmlBufferWriteChar(buf, " PUBLIC ");
5636 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5637 xmlBufferWriteChar(buf, " ");
5638 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5639 } else if (dtd->SystemID != NULL) {
5640 xmlBufferWriteChar(buf, " SYSTEM ");
5641 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5642 }
5643 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5644 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5645 xmlBufferWriteChar(buf, ">");
5646 return;
5647 }
5648 xmlBufferWriteChar(buf, " [\n");
5649 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5650#if 0
5651 if (dtd->entities != NULL)
5652 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5653 if (dtd->notations != NULL)
5654 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5655 if (dtd->elements != NULL)
5656 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5657 if (dtd->attributes != NULL)
5658 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5659#endif
5660 xmlBufferWriteChar(buf, "]>");
5661}
5662
5663/**
5664 * xmlAttrDump:
5665 * @buf: the XML buffer output
5666 * @doc: the document
5667 * @cur: the attribute pointer
5668 *
5669 * Dump an XML attribute
5670 */
5671static void
5672xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5673 xmlChar *value;
5674
5675 if (cur == NULL) {
5676#ifdef DEBUG_TREE
5677 xmlGenericError(xmlGenericErrorContext,
5678 "xmlAttrDump : property == NULL\n");
5679#endif
5680 return;
5681 }
5682 xmlBufferWriteChar(buf, " ");
5683 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5684 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5685 xmlBufferWriteChar(buf, ":");
5686 }
5687 xmlBufferWriteCHAR(buf, cur->name);
5688 value = xmlNodeListGetString(doc, cur->children, 0);
5689 if (value != NULL) {
5690 xmlBufferWriteChar(buf, "=");
5691 xmlBufferWriteQuotedString(buf, value);
5692 xmlFree(value);
5693 } else {
5694 xmlBufferWriteChar(buf, "=\"\"");
5695 }
5696}
5697
5698/**
5699 * xmlAttrListDump:
5700 * @buf: the XML buffer output
5701 * @doc: the document
5702 * @cur: the first attribute pointer
5703 *
5704 * Dump a list of XML attributes
5705 */
5706static void
5707xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5708 if (cur == NULL) {
5709#ifdef DEBUG_TREE
5710 xmlGenericError(xmlGenericErrorContext,
5711 "xmlAttrListDump : property == NULL\n");
5712#endif
5713 return;
5714 }
5715 while (cur != NULL) {
5716 xmlAttrDump(buf, doc, cur);
5717 cur = cur->next;
5718 }
5719}
5720
5721
5722
5723/**
5724 * xmlNodeListDump:
5725 * @buf: the XML buffer output
5726 * @doc: the document
5727 * @cur: the first node
5728 * @level: the imbrication level for indenting
5729 * @format: is formatting allowed
5730 *
5731 * Dump an XML node list, recursive behaviour,children are printed too.
5732 */
5733static void
5734xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5735 int format) {
5736 int i;
5737
5738 if (cur == NULL) {
5739#ifdef DEBUG_TREE
5740 xmlGenericError(xmlGenericErrorContext,
5741 "xmlNodeListDump : node == NULL\n");
5742#endif
5743 return;
5744 }
5745 while (cur != NULL) {
5746 if ((format) && (xmlIndentTreeOutput) &&
5747 (cur->type == XML_ELEMENT_NODE))
5748 for (i = 0;i < level;i++)
5749 xmlBufferWriteChar(buf, " ");
5750 xmlNodeDump(buf, doc, cur, level, format);
5751 if (format) {
5752 xmlBufferWriteChar(buf, "\n");
5753 }
5754 cur = cur->next;
5755 }
5756}
5757
5758/**
5759 * xmlNodeDump:
5760 * @buf: the XML buffer output
5761 * @doc: the document
5762 * @cur: the current node
5763 * @level: the imbrication level for indenting
5764 * @format: is formatting allowed
5765 *
5766 * Dump an XML node, recursive behaviour,children are printed too.
5767 */
5768void
5769xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5770 int format) {
5771 int i;
5772 xmlNodePtr tmp;
5773
5774 if (cur == NULL) {
5775#ifdef DEBUG_TREE
5776 xmlGenericError(xmlGenericErrorContext,
5777 "xmlNodeDump : node == NULL\n");
5778#endif
5779 return;
5780 }
5781 if (cur->type == XML_XINCLUDE_START)
5782 return;
5783 if (cur->type == XML_XINCLUDE_END)
5784 return;
5785 if (cur->type == XML_DTD_NODE) {
5786 xmlDtdDump(buf, (xmlDtdPtr) cur);
5787 return;
5788 }
5789 if (cur->type == XML_ELEMENT_DECL) {
5790 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5791 return;
5792 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005793 if (cur->type == XML_ATTRIBUTE_NODE){
5794 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5795 return;
5796 }
Owen Taylor3473f882001-02-23 17:55:21 +00005797 if (cur->type == XML_ATTRIBUTE_DECL) {
5798 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5799 return;
5800 }
5801 if (cur->type == XML_ENTITY_DECL) {
5802 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5803 return;
5804 }
5805 if (cur->type == XML_TEXT_NODE) {
5806 if (cur->content != NULL) {
5807 if ((cur->name == xmlStringText) ||
5808 (cur->name != xmlStringTextNoenc)) {
5809 xmlChar *buffer;
5810
5811#ifndef XML_USE_BUFFER_CONTENT
5812 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5813#else
5814 buffer = xmlEncodeEntitiesReentrant(doc,
5815 xmlBufferContent(cur->content));
5816#endif
5817 if (buffer != NULL) {
5818 xmlBufferWriteCHAR(buf, buffer);
5819 xmlFree(buffer);
5820 }
5821 } else {
5822 /*
5823 * Disable escaping, needed for XSLT
5824 */
5825#ifndef XML_USE_BUFFER_CONTENT
5826 xmlBufferWriteCHAR(buf, cur->content);
5827#else
5828 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5829#endif
5830 }
5831 }
5832 return;
5833 }
5834 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005835 xmlBufferWriteChar(buf, "<?");
5836 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005837 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00005838 xmlBufferWriteChar(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00005839#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard2c748c62002-01-16 15:37:50 +00005840 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005841#else
Daniel Veillard2c748c62002-01-16 15:37:50 +00005842 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00005843#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005844 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00005845 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00005846 return;
5847 }
5848 if (cur->type == XML_COMMENT_NODE) {
5849 if (cur->content != NULL) {
5850 xmlBufferWriteChar(buf, "<!--");
5851#ifndef XML_USE_BUFFER_CONTENT
5852 xmlBufferWriteCHAR(buf, cur->content);
5853#else
5854 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5855#endif
5856 xmlBufferWriteChar(buf, "-->");
5857 }
5858 return;
5859 }
5860 if (cur->type == XML_ENTITY_REF_NODE) {
5861 xmlBufferWriteChar(buf, "&");
5862 xmlBufferWriteCHAR(buf, cur->name);
5863 xmlBufferWriteChar(buf, ";");
5864 return;
5865 }
5866 if (cur->type == XML_CDATA_SECTION_NODE) {
5867 xmlBufferWriteChar(buf, "<![CDATA[");
5868 if (cur->content != NULL)
5869#ifndef XML_USE_BUFFER_CONTENT
5870 xmlBufferWriteCHAR(buf, cur->content);
5871#else
5872 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5873#endif
5874 xmlBufferWriteChar(buf, "]]>");
5875 return;
5876 }
5877
5878 if (format == 1) {
5879 tmp = cur->children;
5880 while (tmp != NULL) {
5881 if ((tmp->type == XML_TEXT_NODE) ||
5882 (tmp->type == XML_ENTITY_REF_NODE)) {
5883 format = 0;
5884 break;
5885 }
5886 tmp = tmp->next;
5887 }
5888 }
5889 xmlBufferWriteChar(buf, "<");
5890 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5891 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5892 xmlBufferWriteChar(buf, ":");
5893 }
5894
5895 xmlBufferWriteCHAR(buf, cur->name);
5896 if (cur->nsDef)
5897 xmlNsListDump(buf, cur->nsDef);
5898 if (cur->properties != NULL)
5899 xmlAttrListDump(buf, doc, cur->properties);
5900
Daniel Veillard7db37732001-07-12 01:20:08 +00005901 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5902 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005903 (!xmlSaveNoEmptyTags)) {
5904 xmlBufferWriteChar(buf, "/>");
5905 return;
5906 }
5907 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005908 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005909 xmlChar *buffer;
5910
5911#ifndef XML_USE_BUFFER_CONTENT
5912 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5913#else
5914 buffer = xmlEncodeEntitiesReentrant(doc,
5915 xmlBufferContent(cur->content));
5916#endif
5917 if (buffer != NULL) {
5918 xmlBufferWriteCHAR(buf, buffer);
5919 xmlFree(buffer);
5920 }
5921 }
5922 if (cur->children != NULL) {
5923 if (format) xmlBufferWriteChar(buf, "\n");
5924 xmlNodeListDump(buf, doc, cur->children,
5925 (level >= 0?level+1:-1), format);
5926 if ((xmlIndentTreeOutput) && (format))
5927 for (i = 0;i < level;i++)
5928 xmlBufferWriteChar(buf, " ");
5929 }
5930 xmlBufferWriteChar(buf, "</");
5931 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5932 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5933 xmlBufferWriteChar(buf, ":");
5934 }
5935
5936 xmlBufferWriteCHAR(buf, cur->name);
5937 xmlBufferWriteChar(buf, ">");
5938}
5939
5940/**
5941 * xmlElemDump:
5942 * @f: the FILE * for the output
5943 * @doc: the document
5944 * @cur: the current node
5945 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005946 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00005947 */
5948void
5949xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5950 xmlBufferPtr buf;
5951
5952 if (cur == NULL) {
5953#ifdef DEBUG_TREE
5954 xmlGenericError(xmlGenericErrorContext,
5955 "xmlElemDump : cur == NULL\n");
5956#endif
5957 return;
5958 }
Owen Taylor3473f882001-02-23 17:55:21 +00005959#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005960 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005961 xmlGenericError(xmlGenericErrorContext,
5962 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005963 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005964#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005965
Owen Taylor3473f882001-02-23 17:55:21 +00005966 buf = xmlBufferCreate();
5967 if (buf == NULL) return;
5968 if ((doc != NULL) &&
5969 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5970#ifdef LIBXML_HTML_ENABLED
5971 htmlNodeDump(buf, doc, cur);
5972#else
5973 xmlGenericError(xmlGenericErrorContext,
5974 "HTML support not compiled in\n");
5975#endif /* LIBXML_HTML_ENABLED */
5976 } else
5977 xmlNodeDump(buf, doc, cur, 0, 1);
5978 xmlBufferDump(f, buf);
5979 xmlBufferFree(buf);
5980}
5981
5982/************************************************************************
5983 * *
5984 * Dumping XML tree content to an I/O output buffer *
5985 * *
5986 ************************************************************************/
5987
5988void
5989xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5990 int level, int format, const char *encoding);
5991static void
5992xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5993 int level, int format, const char *encoding);
5994/**
5995 * xmlNsDumpOutput:
5996 * @buf: the XML buffer output
5997 * @cur: a namespace
5998 *
5999 * Dump a local Namespace definition.
6000 * Should be called in the context of attributes dumps.
6001 */
6002static void
6003xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6004 if (cur == NULL) {
6005#ifdef DEBUG_TREE
6006 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006007 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006008#endif
6009 return;
6010 }
6011 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6012 /* Within the context of an element attributes */
6013 if (cur->prefix != NULL) {
6014 xmlOutputBufferWriteString(buf, " xmlns:");
6015 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6016 } else
6017 xmlOutputBufferWriteString(buf, " xmlns");
6018 xmlOutputBufferWriteString(buf, "=");
6019 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6020 }
6021}
6022
6023/**
6024 * xmlNsListDumpOutput:
6025 * @buf: the XML buffer output
6026 * @cur: the first namespace
6027 *
6028 * Dump a list of local Namespace definitions.
6029 * Should be called in the context of attributes dumps.
6030 */
6031static void
6032xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6033 while (cur != NULL) {
6034 xmlNsDumpOutput(buf, cur);
6035 cur = cur->next;
6036 }
6037}
6038
6039/**
6040 * xmlDtdDumpOutput:
6041 * @buf: the XML buffer output
6042 * @doc: the document
6043 * @encoding: an optional encoding string
6044 *
6045 * Dump the XML document DTD, if any.
6046 */
6047static void
6048xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6049 if (dtd == NULL) {
6050#ifdef DEBUG_TREE
6051 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006052 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006053#endif
6054 return;
6055 }
6056 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6057 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6058 if (dtd->ExternalID != NULL) {
6059 xmlOutputBufferWriteString(buf, " PUBLIC ");
6060 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6061 xmlOutputBufferWriteString(buf, " ");
6062 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6063 } else if (dtd->SystemID != NULL) {
6064 xmlOutputBufferWriteString(buf, " SYSTEM ");
6065 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6066 }
6067 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6068 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6069 xmlOutputBufferWriteString(buf, ">");
6070 return;
6071 }
6072 xmlOutputBufferWriteString(buf, " [\n");
6073 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6074 xmlOutputBufferWriteString(buf, "]>");
6075}
6076
6077/**
6078 * xmlAttrDumpOutput:
6079 * @buf: the XML buffer output
6080 * @doc: the document
6081 * @cur: the attribute pointer
6082 * @encoding: an optional encoding string
6083 *
6084 * Dump an XML attribute
6085 */
6086static void
6087xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006088 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006089 xmlChar *value;
6090
6091 if (cur == NULL) {
6092#ifdef DEBUG_TREE
6093 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006094 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006095#endif
6096 return;
6097 }
6098 xmlOutputBufferWriteString(buf, " ");
6099 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6100 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6101 xmlOutputBufferWriteString(buf, ":");
6102 }
6103 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6104 value = xmlNodeListGetString(doc, cur->children, 0);
6105 if (value) {
6106 xmlOutputBufferWriteString(buf, "=");
6107 xmlBufferWriteQuotedString(buf->buffer, value);
6108 xmlFree(value);
6109 } else {
6110 xmlOutputBufferWriteString(buf, "=\"\"");
6111 }
6112}
6113
6114/**
6115 * xmlAttrListDumpOutput:
6116 * @buf: the XML buffer output
6117 * @doc: the document
6118 * @cur: the first attribute pointer
6119 * @encoding: an optional encoding string
6120 *
6121 * Dump a list of XML attributes
6122 */
6123static void
6124xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6125 xmlAttrPtr cur, const char *encoding) {
6126 if (cur == NULL) {
6127#ifdef DEBUG_TREE
6128 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006129 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006130#endif
6131 return;
6132 }
6133 while (cur != NULL) {
6134 xmlAttrDumpOutput(buf, doc, cur, encoding);
6135 cur = cur->next;
6136 }
6137}
6138
6139
6140
6141/**
6142 * xmlNodeListDumpOutput:
6143 * @buf: the XML buffer output
6144 * @doc: the document
6145 * @cur: the first node
6146 * @level: the imbrication level for indenting
6147 * @format: is formatting allowed
6148 * @encoding: an optional encoding string
6149 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006150 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006151 */
6152static void
6153xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6154 xmlNodePtr cur, int level, int format, const char *encoding) {
6155 int i;
6156
6157 if (cur == NULL) {
6158#ifdef DEBUG_TREE
6159 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006160 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006161#endif
6162 return;
6163 }
6164 while (cur != NULL) {
6165 if ((format) && (xmlIndentTreeOutput) &&
6166 (cur->type == XML_ELEMENT_NODE))
6167 for (i = 0;i < level;i++)
6168 xmlOutputBufferWriteString(buf, " ");
6169 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6170 if (format) {
6171 xmlOutputBufferWriteString(buf, "\n");
6172 }
6173 cur = cur->next;
6174 }
6175}
6176
6177/**
6178 * xmlNodeDumpOutput:
6179 * @buf: the XML buffer output
6180 * @doc: the document
6181 * @cur: the current node
6182 * @level: the imbrication level for indenting
6183 * @format: is formatting allowed
6184 * @encoding: an optional encoding string
6185 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006186 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006187 */
6188void
6189xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6190 int level, int format, const char *encoding) {
6191 int i;
6192 xmlNodePtr tmp;
6193
6194 if (cur == NULL) {
6195#ifdef DEBUG_TREE
6196 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006197 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006198#endif
6199 return;
6200 }
6201 if (cur->type == XML_XINCLUDE_START)
6202 return;
6203 if (cur->type == XML_XINCLUDE_END)
6204 return;
6205 if (cur->type == XML_DTD_NODE) {
6206 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6207 return;
6208 }
6209 if (cur->type == XML_ELEMENT_DECL) {
6210 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6211 return;
6212 }
6213 if (cur->type == XML_ATTRIBUTE_DECL) {
6214 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6215 return;
6216 }
6217 if (cur->type == XML_ENTITY_DECL) {
6218 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6219 return;
6220 }
6221 if (cur->type == XML_TEXT_NODE) {
6222 if (cur->content != NULL) {
6223 if ((cur->name == xmlStringText) ||
6224 (cur->name != xmlStringTextNoenc)) {
6225 xmlChar *buffer;
6226
6227#ifndef XML_USE_BUFFER_CONTENT
6228 if (encoding == NULL)
6229 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6230 else
6231 buffer = xmlEncodeSpecialChars(doc, cur->content);
6232#else
6233 if (encoding == NULL)
6234 buffer = xmlEncodeEntitiesReentrant(doc,
6235 xmlBufferContent(cur->content));
6236 else
6237 buffer = xmlEncodeSpecialChars(doc,
6238 xmlBufferContent(cur->content));
6239#endif
6240 if (buffer != NULL) {
6241 xmlOutputBufferWriteString(buf, (const char *)buffer);
6242 xmlFree(buffer);
6243 }
6244 } else {
6245 /*
6246 * Disable escaping, needed for XSLT
6247 */
6248#ifndef XML_USE_BUFFER_CONTENT
6249 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6250#else
6251 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6252#endif
6253 }
6254 }
6255
6256 return;
6257 }
6258 if (cur->type == XML_PI_NODE) {
6259 if (cur->content != NULL) {
6260 xmlOutputBufferWriteString(buf, "<?");
6261 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6262 if (cur->content != NULL) {
6263 xmlOutputBufferWriteString(buf, " ");
6264#ifndef XML_USE_BUFFER_CONTENT
6265 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6266#else
6267 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6268#endif
6269 }
6270 xmlOutputBufferWriteString(buf, "?>");
6271 } else {
6272 xmlOutputBufferWriteString(buf, "<?");
6273 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6274 xmlOutputBufferWriteString(buf, "?>");
6275 }
6276 return;
6277 }
6278 if (cur->type == XML_COMMENT_NODE) {
6279 if (cur->content != NULL) {
6280 xmlOutputBufferWriteString(buf, "<!--");
6281#ifndef XML_USE_BUFFER_CONTENT
6282 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6283#else
6284 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6285#endif
6286 xmlOutputBufferWriteString(buf, "-->");
6287 }
6288 return;
6289 }
6290 if (cur->type == XML_ENTITY_REF_NODE) {
6291 xmlOutputBufferWriteString(buf, "&");
6292 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6293 xmlOutputBufferWriteString(buf, ";");
6294 return;
6295 }
6296 if (cur->type == XML_CDATA_SECTION_NODE) {
6297 xmlOutputBufferWriteString(buf, "<![CDATA[");
6298 if (cur->content != NULL)
6299#ifndef XML_USE_BUFFER_CONTENT
6300 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6301#else
6302 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6303#endif
6304 xmlOutputBufferWriteString(buf, "]]>");
6305 return;
6306 }
6307
6308 if (format == 1) {
6309 tmp = cur->children;
6310 while (tmp != NULL) {
6311 if ((tmp->type == XML_TEXT_NODE) ||
6312 (tmp->type == XML_ENTITY_REF_NODE)) {
6313 format = 0;
6314 break;
6315 }
6316 tmp = tmp->next;
6317 }
6318 }
6319 xmlOutputBufferWriteString(buf, "<");
6320 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6321 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6322 xmlOutputBufferWriteString(buf, ":");
6323 }
6324
6325 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6326 if (cur->nsDef)
6327 xmlNsListDumpOutput(buf, cur->nsDef);
6328 if (cur->properties != NULL)
6329 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6330
Daniel Veillard7db37732001-07-12 01:20:08 +00006331 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6332 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006333 xmlOutputBufferWriteString(buf, "/>");
6334 return;
6335 }
6336 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006337 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006338 xmlChar *buffer;
6339
6340#ifndef XML_USE_BUFFER_CONTENT
6341 if (encoding == NULL)
6342 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6343 else
6344 buffer = xmlEncodeSpecialChars(doc, cur->content);
6345#else
6346 if (encoding == NULL)
6347 buffer = xmlEncodeEntitiesReentrant(doc,
6348 xmlBufferContent(cur->content));
6349 else
6350 buffer = xmlEncodeSpecialChars(doc,
6351 xmlBufferContent(cur->content));
6352#endif
6353 if (buffer != NULL) {
6354 xmlOutputBufferWriteString(buf, (const char *)buffer);
6355 xmlFree(buffer);
6356 }
6357 }
6358 if (cur->children != NULL) {
6359 if (format) xmlOutputBufferWriteString(buf, "\n");
6360 xmlNodeListDumpOutput(buf, doc, cur->children,
6361 (level >= 0?level+1:-1), format, encoding);
6362 if ((xmlIndentTreeOutput) && (format))
6363 for (i = 0;i < level;i++)
6364 xmlOutputBufferWriteString(buf, " ");
6365 }
6366 xmlOutputBufferWriteString(buf, "</");
6367 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6368 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6369 xmlOutputBufferWriteString(buf, ":");
6370 }
6371
6372 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6373 xmlOutputBufferWriteString(buf, ">");
6374}
6375
6376/**
6377 * xmlDocContentDumpOutput:
6378 * @buf: the XML buffer output
6379 * @cur: the document
6380 * @encoding: an optional encoding string
6381 * @format: should formatting spaces been added
6382 *
6383 * Dump an XML document.
6384 */
6385static void
6386xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6387 const char *encoding, int format) {
6388 xmlOutputBufferWriteString(buf, "<?xml version=");
6389 if (cur->version != NULL)
6390 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6391 else
6392 xmlOutputBufferWriteString(buf, "\"1.0\"");
6393 if (encoding == NULL) {
6394 if (cur->encoding != NULL)
6395 encoding = (const char *) cur->encoding;
6396 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6397 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6398 }
6399 if (encoding != NULL) {
6400 xmlOutputBufferWriteString(buf, " encoding=");
6401 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6402 }
6403 switch (cur->standalone) {
6404 case 0:
6405 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6406 break;
6407 case 1:
6408 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6409 break;
6410 }
6411 xmlOutputBufferWriteString(buf, "?>\n");
6412 if (cur->children != NULL) {
6413 xmlNodePtr child = cur->children;
6414
6415 while (child != NULL) {
6416 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6417 xmlOutputBufferWriteString(buf, "\n");
6418 child = child->next;
6419 }
6420 }
6421}
6422
6423/************************************************************************
6424 * *
6425 * Saving functions front-ends *
6426 * *
6427 ************************************************************************/
6428
6429/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006430 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006431 * @out_doc: Document to generate XML text from
6432 * @doc_txt_ptr: Memory pointer for allocated XML text
6433 * @doc_txt_len: Length of the generated XML text
6434 * @txt_encoding: Character encoding to use when generating XML text
6435 * @format: should formatting spaces been added
6436 *
6437 * Dump the current DOM tree into memory using the character encoding specified
6438 * by the caller. Note it is up to the caller of this function to free the
6439 * allocated memory.
6440 */
6441
6442void
6443xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006444 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006445 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006446 int dummy = 0;
6447
6448 xmlCharEncoding doc_charset;
6449 xmlOutputBufferPtr out_buff = NULL;
6450 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6451
6452 if (doc_txt_len == NULL) {
6453 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6454 }
6455
6456 if (doc_txt_ptr == NULL) {
6457 *doc_txt_len = 0;
6458 xmlGenericError(xmlGenericErrorContext,
6459 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6460 return;
6461 }
6462
6463 *doc_txt_ptr = NULL;
6464 *doc_txt_len = 0;
6465
6466 if (out_doc == NULL) {
6467 /* No document, no output */
6468 xmlGenericError(xmlGenericErrorContext,
6469 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6470 return;
6471 }
6472
6473 /*
6474 * Validate the encoding value, if provided.
6475 * This logic is copied from xmlSaveFileEnc.
6476 */
6477
6478 if (txt_encoding == NULL)
6479 txt_encoding = (const char *) out_doc->encoding;
6480 if (txt_encoding != NULL) {
6481 doc_charset = xmlParseCharEncoding(txt_encoding);
6482
6483 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6484 xmlGenericError(xmlGenericErrorContext,
6485 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6486 return;
6487
6488 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6489 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6490 if ( conv_hdlr == NULL ) {
6491 xmlGenericError(xmlGenericErrorContext,
6492 "%s: %s %s '%s'\n",
6493 "xmlDocDumpFormatMemoryEnc",
6494 "Failed to identify encoding handler for",
6495 "character set",
6496 txt_encoding);
6497 return;
6498 }
6499 }
6500 }
6501
6502 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6503 xmlGenericError(xmlGenericErrorContext,
6504 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6505 return;
6506 }
6507
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006508 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006509 xmlOutputBufferFlush(out_buff);
6510 if (out_buff->conv != NULL) {
6511 *doc_txt_len = out_buff->conv->use;
6512 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6513 } else {
6514 *doc_txt_len = out_buff->buffer->use;
6515 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6516 }
6517 (void)xmlOutputBufferClose(out_buff);
6518
6519 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6520 *doc_txt_len = 0;
6521 xmlGenericError(xmlGenericErrorContext,
6522 "xmlDocDumpFormatMemoryEnc: %s\n",
6523 "Failed to allocate memory for document text representation.");
6524 }
6525
6526 return;
6527}
6528
6529/**
6530 * xmlDocDumpMemory:
6531 * @cur: the document
6532 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006533 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006534 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006535 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006536 * It's up to the caller to free the memory.
6537 */
6538void
6539xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6540 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6541}
6542
6543/**
6544 * xmlDocDumpFormatMemory:
6545 * @cur: the document
6546 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006547 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006548 * @format: should formatting spaces been added
6549 *
6550 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006551 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006552 * It's up to the caller to free the memory.
6553 */
6554void
6555xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6556 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6557}
6558
6559/**
6560 * xmlDocDumpMemoryEnc:
6561 * @out_doc: Document to generate XML text from
6562 * @doc_txt_ptr: Memory pointer for allocated XML text
6563 * @doc_txt_len: Length of the generated XML text
6564 * @txt_encoding: Character encoding to use when generating XML text
6565 *
6566 * Dump the current DOM tree into memory using the character encoding specified
6567 * by the caller. Note it is up to the caller of this function to free the
6568 * allocated memory.
6569 */
6570
6571void
6572xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6573 int * doc_txt_len, const char * txt_encoding) {
6574 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006575 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006576}
6577
6578/**
6579 * xmlGetDocCompressMode:
6580 * @doc: the document
6581 *
6582 * get the compression ratio for a document, ZLIB based
6583 * Returns 0 (uncompressed) to 9 (max compression)
6584 */
6585int
6586xmlGetDocCompressMode (xmlDocPtr doc) {
6587 if (doc == NULL) return(-1);
6588 return(doc->compression);
6589}
6590
6591/**
6592 * xmlSetDocCompressMode:
6593 * @doc: the document
6594 * @mode: the compression ratio
6595 *
6596 * set the compression ratio for a document, ZLIB based
6597 * Correct values: 0 (uncompressed) to 9 (max compression)
6598 */
6599void
6600xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6601 if (doc == NULL) return;
6602 if (mode < 0) doc->compression = 0;
6603 else if (mode > 9) doc->compression = 9;
6604 else doc->compression = mode;
6605}
6606
6607/**
6608 * xmlGetCompressMode:
6609 *
6610 * get the default compression mode used, ZLIB based.
6611 * Returns 0 (uncompressed) to 9 (max compression)
6612 */
6613int
6614 xmlGetCompressMode(void) {
6615 return(xmlCompressMode);
6616}
6617
6618/**
6619 * xmlSetCompressMode:
6620 * @mode: the compression ratio
6621 *
6622 * set the default compression mode used, ZLIB based
6623 * Correct values: 0 (uncompressed) to 9 (max compression)
6624 */
6625void
6626xmlSetCompressMode(int mode) {
6627 if (mode < 0) xmlCompressMode = 0;
6628 else if (mode > 9) xmlCompressMode = 9;
6629 else xmlCompressMode = mode;
6630}
6631
6632/**
6633 * xmlDocDump:
6634 * @f: the FILE*
6635 * @cur: the document
6636 *
6637 * Dump an XML document to an open FILE.
6638 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006639 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006640 */
6641int
6642xmlDocDump(FILE *f, xmlDocPtr cur) {
6643 xmlOutputBufferPtr buf;
6644 const char * encoding;
6645 xmlCharEncodingHandlerPtr handler = NULL;
6646 int ret;
6647
6648 if (cur == NULL) {
6649#ifdef DEBUG_TREE
6650 xmlGenericError(xmlGenericErrorContext,
6651 "xmlDocDump : document == NULL\n");
6652#endif
6653 return(-1);
6654 }
6655 encoding = (const char *) cur->encoding;
6656
6657 if (encoding != NULL) {
6658 xmlCharEncoding enc;
6659
6660 enc = xmlParseCharEncoding(encoding);
6661
6662 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6663 xmlGenericError(xmlGenericErrorContext,
6664 "xmlDocDump: document not in UTF8\n");
6665 return(-1);
6666 }
6667 if (enc != XML_CHAR_ENCODING_UTF8) {
6668 handler = xmlFindCharEncodingHandler(encoding);
6669 if (handler == NULL) {
6670 xmlFree((char *) cur->encoding);
6671 cur->encoding = NULL;
6672 }
6673 }
6674 }
6675 buf = xmlOutputBufferCreateFile(f, handler);
6676 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006677 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006678
6679 ret = xmlOutputBufferClose(buf);
6680 return(ret);
6681}
6682
6683/**
6684 * xmlSaveFileTo:
6685 * @buf: an output I/O buffer
6686 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006687 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006688 *
6689 * Dump an XML document to an I/O buffer.
6690 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006691 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006692 */
6693int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006694xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006695 int ret;
6696
6697 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006698 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006699 ret = xmlOutputBufferClose(buf);
6700 return(ret);
6701}
6702
6703/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006704 * xmlSaveFormatFileTo:
6705 * @buf: an output I/O buffer
6706 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006707 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006708 * @format: should formatting spaces been added
6709 *
6710 * Dump an XML document to an I/O buffer.
6711 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006712 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006713 */
6714int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006715xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006716 int ret;
6717
6718 if (buf == NULL) return(0);
6719 xmlDocContentDumpOutput(buf, cur, encoding, format);
6720 ret = xmlOutputBufferClose(buf);
6721 return(ret);
6722}
6723
6724/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006725 * xmlSaveFormatFileEnc
6726 * @filename: the filename or URL to output
6727 * @cur: the document being saved
6728 * @encoding: the name of the encoding to use or NULL.
6729 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006730 *
6731 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006732 */
6733int
Daniel Veillardf012a642001-07-23 19:10:52 +00006734xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6735 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006736 xmlOutputBufferPtr buf;
6737 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006738 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006739 int ret;
6740
Daniel Veillardfb25a512002-01-13 20:32:08 +00006741 if (encoding == NULL)
6742 encoding = (const char *) cur->encoding;
6743
Owen Taylor3473f882001-02-23 17:55:21 +00006744 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006745
6746 enc = xmlParseCharEncoding(encoding);
6747 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6748 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006749 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006750 return(-1);
6751 }
6752 if (enc != XML_CHAR_ENCODING_UTF8) {
6753 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006754 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006755 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006756 }
6757 }
6758
Daniel Veillardf012a642001-07-23 19:10:52 +00006759#ifdef HAVE_ZLIB_H
6760 if (cur->compression < 0) cur->compression = xmlCompressMode;
6761#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006762 /*
6763 * save the content to a temp buffer.
6764 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006765 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006766 if (buf == NULL) return(-1);
6767
Daniel Veillardf012a642001-07-23 19:10:52 +00006768 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006769
6770 ret = xmlOutputBufferClose(buf);
6771 return(ret);
6772}
6773
Daniel Veillardf012a642001-07-23 19:10:52 +00006774
6775/**
6776 * xmlSaveFileEnc:
6777 * @filename: the filename (or URL)
6778 * @cur: the document
6779 * @encoding: the name of an encoding (or NULL)
6780 *
6781 * Dump an XML document, converting it to the given encoding
6782 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006783 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006784 */
6785int
6786xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6787 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6788}
6789
Owen Taylor3473f882001-02-23 17:55:21 +00006790/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006791 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006792 * @filename: the filename (or URL)
6793 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006794 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006795 *
6796 * Dump an XML document to a file. Will use compression if
6797 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006798 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006799 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006800 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006801 */
6802int
Daniel Veillard67fee942001-04-26 18:59:03 +00006803xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006804 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006805}
6806
Daniel Veillard67fee942001-04-26 18:59:03 +00006807/**
6808 * xmlSaveFile:
6809 * @filename: the filename (or URL)
6810 * @cur: the document
6811 *
6812 * Dump an XML document to a file. Will use compression if
6813 * compiled in and enabled. If @filename is "-" the stdout file is
6814 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006815 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006816 */
6817int
6818xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006819 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006820}
6821