blob: 28f4490e912c36e74c13fca0c3c5bc09064fbed3 [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 Veillard19e96c32001-07-09 10:32:59 +00001827 prop = tree->properties;
1828 while (prop != NULL) {
1829 prop->doc = doc;
1830 xmlSetListDoc(prop->children, doc);
1831 prop = prop->next;
1832 }
Owen Taylor3473f882001-02-23 17:55:21 +00001833 if (tree->children != NULL)
1834 xmlSetListDoc(tree->children, doc);
1835 tree->doc = doc;
1836 }
1837}
1838
1839/**
1840 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001841 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001842 * @doc: the document
1843 *
1844 * update all nodes in the list to point to the right document
1845 */
1846void
1847xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1848 xmlNodePtr cur;
1849
1850 if (list == NULL)
1851 return;
1852 cur = list;
1853 while (cur != NULL) {
1854 if (cur->doc != doc)
1855 xmlSetTreeDoc(cur, doc);
1856 cur = cur->next;
1857 }
1858}
1859
1860
1861/**
1862 * xmlNewChild:
1863 * @parent: the parent node
1864 * @ns: a namespace if any
1865 * @name: the name of the child
1866 * @content: the XML content of the child if any.
1867 *
1868 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001869 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001870 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1871 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1872 * references, but XML special chars need to be escaped first by using
1873 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1874 * support is not needed.
1875 *
1876 * Returns a pointer to the new node object.
1877 */
1878xmlNodePtr
1879xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1880 const xmlChar *name, const xmlChar *content) {
1881 xmlNodePtr cur, prev;
1882
1883 if (parent == NULL) {
1884#ifdef DEBUG_TREE
1885 xmlGenericError(xmlGenericErrorContext,
1886 "xmlNewChild : parent == NULL\n");
1887#endif
1888 return(NULL);
1889 }
1890
1891 if (name == NULL) {
1892#ifdef DEBUG_TREE
1893 xmlGenericError(xmlGenericErrorContext,
1894 "xmlNewChild : name == NULL\n");
1895#endif
1896 return(NULL);
1897 }
1898
1899 /*
1900 * Allocate a new node
1901 */
1902 if (ns == NULL)
1903 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1904 else
1905 cur = xmlNewDocNode(parent->doc, ns, name, content);
1906 if (cur == NULL) return(NULL);
1907
1908 /*
1909 * add the new element at the end of the children list.
1910 */
1911 cur->type = XML_ELEMENT_NODE;
1912 cur->parent = parent;
1913 cur->doc = parent->doc;
1914 if (parent->children == NULL) {
1915 parent->children = cur;
1916 parent->last = cur;
1917 } else {
1918 prev = parent->last;
1919 prev->next = cur;
1920 cur->prev = prev;
1921 parent->last = cur;
1922 }
1923
1924 return(cur);
1925}
1926
1927/**
1928 * xmlAddNextSibling:
1929 * @cur: the child node
1930 * @elem: the new node
1931 *
1932 * Add a new element @elem as the next siblings of @cur
1933 * If the new element was already inserted in a document it is
1934 * first unlinked from its existing context.
1935 * As a result of text merging @elem may be freed.
1936 *
1937 * Returns the new element or NULL in case of error.
1938 */
1939xmlNodePtr
1940xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1941 if (cur == NULL) {
1942#ifdef DEBUG_TREE
1943 xmlGenericError(xmlGenericErrorContext,
1944 "xmlAddNextSibling : cur == NULL\n");
1945#endif
1946 return(NULL);
1947 }
1948 if (elem == NULL) {
1949#ifdef DEBUG_TREE
1950 xmlGenericError(xmlGenericErrorContext,
1951 "xmlAddNextSibling : elem == NULL\n");
1952#endif
1953 return(NULL);
1954 }
1955
1956 xmlUnlinkNode(elem);
1957
1958 if (elem->type == XML_TEXT_NODE) {
1959 if (cur->type == XML_TEXT_NODE) {
1960#ifndef XML_USE_BUFFER_CONTENT
1961 xmlNodeAddContent(cur, elem->content);
1962#else
1963 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1964#endif
1965 xmlFreeNode(elem);
1966 return(cur);
1967 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001968 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1969 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001970#ifndef XML_USE_BUFFER_CONTENT
1971 xmlChar *tmp;
1972
1973 tmp = xmlStrdup(elem->content);
1974 tmp = xmlStrcat(tmp, cur->next->content);
1975 xmlNodeSetContent(cur->next, tmp);
1976 xmlFree(tmp);
1977#else
1978 xmlBufferAddHead(cur->next->content,
1979 xmlBufferContent(elem->content),
1980 xmlBufferLength(elem->content));
1981#endif
1982 xmlFreeNode(elem);
1983 return(cur->next);
1984 }
1985 }
1986
1987 if (elem->doc != cur->doc) {
1988 xmlSetTreeDoc(elem, cur->doc);
1989 }
1990 elem->parent = cur->parent;
1991 elem->prev = cur;
1992 elem->next = cur->next;
1993 cur->next = elem;
1994 if (elem->next != NULL)
1995 elem->next->prev = elem;
1996 if ((elem->parent != NULL) && (elem->parent->last == cur))
1997 elem->parent->last = elem;
1998 return(elem);
1999}
2000
2001/**
2002 * xmlAddPrevSibling:
2003 * @cur: the child node
2004 * @elem: the new node
2005 *
2006 * Add a new element @elem as the previous siblings of @cur
2007 * merging adjacent TEXT nodes (@elem may be freed)
2008 * If the new element was already inserted in a document it is
2009 * first unlinked from its existing context.
2010 *
2011 * Returns the new element or NULL in case of error.
2012 */
2013xmlNodePtr
2014xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2015 if (cur == NULL) {
2016#ifdef DEBUG_TREE
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlAddPrevSibling : cur == NULL\n");
2019#endif
2020 return(NULL);
2021 }
2022 if (elem == NULL) {
2023#ifdef DEBUG_TREE
2024 xmlGenericError(xmlGenericErrorContext,
2025 "xmlAddPrevSibling : elem == NULL\n");
2026#endif
2027 return(NULL);
2028 }
2029
2030 xmlUnlinkNode(elem);
2031
2032 if (elem->type == XML_TEXT_NODE) {
2033 if (cur->type == XML_TEXT_NODE) {
2034#ifndef XML_USE_BUFFER_CONTENT
2035 xmlChar *tmp;
2036
2037 tmp = xmlStrdup(elem->content);
2038 tmp = xmlStrcat(tmp, cur->content);
2039 xmlNodeSetContent(cur, tmp);
2040 xmlFree(tmp);
2041#else
2042 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2043 xmlBufferLength(elem->content));
2044#endif
2045 xmlFreeNode(elem);
2046 return(cur);
2047 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002048 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2049 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002050#ifndef XML_USE_BUFFER_CONTENT
2051 xmlNodeAddContent(cur->prev, elem->content);
2052#else
2053 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2054#endif
2055 xmlFreeNode(elem);
2056 return(cur->prev);
2057 }
2058 }
2059
2060 if (elem->doc != cur->doc) {
2061 xmlSetTreeDoc(elem, cur->doc);
2062 }
2063 elem->parent = cur->parent;
2064 elem->next = cur;
2065 elem->prev = cur->prev;
2066 cur->prev = elem;
2067 if (elem->prev != NULL)
2068 elem->prev->next = elem;
2069 if ((elem->parent != NULL) && (elem->parent->children == cur))
2070 elem->parent->children = elem;
2071 return(elem);
2072}
2073
2074/**
2075 * xmlAddSibling:
2076 * @cur: the child node
2077 * @elem: the new node
2078 *
2079 * Add a new element @elem to the list of siblings of @cur
2080 * merging adjacent TEXT nodes (@elem may be freed)
2081 * If the new element was already inserted in a document it is
2082 * first unlinked from its existing context.
2083 *
2084 * Returns the new element or NULL in case of error.
2085 */
2086xmlNodePtr
2087xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2088 xmlNodePtr parent;
2089
2090 if (cur == NULL) {
2091#ifdef DEBUG_TREE
2092 xmlGenericError(xmlGenericErrorContext,
2093 "xmlAddSibling : cur == NULL\n");
2094#endif
2095 return(NULL);
2096 }
2097
2098 if (elem == NULL) {
2099#ifdef DEBUG_TREE
2100 xmlGenericError(xmlGenericErrorContext,
2101 "xmlAddSibling : elem == NULL\n");
2102#endif
2103 return(NULL);
2104 }
2105
2106 /*
2107 * Constant time is we can rely on the ->parent->last to find
2108 * the last sibling.
2109 */
2110 if ((cur->parent != NULL) &&
2111 (cur->parent->children != NULL) &&
2112 (cur->parent->last != NULL) &&
2113 (cur->parent->last->next == NULL)) {
2114 cur = cur->parent->last;
2115 } else {
2116 while (cur->next != NULL) cur = cur->next;
2117 }
2118
2119 xmlUnlinkNode(elem);
2120
2121 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2122#ifndef XML_USE_BUFFER_CONTENT
2123 xmlNodeAddContent(cur, elem->content);
2124#else
2125 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2126#endif
2127 xmlFreeNode(elem);
2128 return(cur);
2129 }
2130
2131 if (elem->doc != cur->doc) {
2132 xmlSetTreeDoc(elem, cur->doc);
2133 }
2134 parent = cur->parent;
2135 elem->prev = cur;
2136 elem->next = NULL;
2137 elem->parent = parent;
2138 cur->next = elem;
2139 if (parent != NULL)
2140 parent->last = elem;
2141
2142 return(elem);
2143}
2144
2145/**
2146 * xmlAddChildList:
2147 * @parent: the parent node
2148 * @cur: the first node in the list
2149 *
2150 * Add a list of node at the end of the child list of the parent
2151 * merging adjacent TEXT nodes (@cur may be freed)
2152 *
2153 * Returns the last child or NULL in case of error.
2154 */
2155xmlNodePtr
2156xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2157 xmlNodePtr prev;
2158
2159 if (parent == NULL) {
2160#ifdef DEBUG_TREE
2161 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002162 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002163#endif
2164 return(NULL);
2165 }
2166
2167 if (cur == NULL) {
2168#ifdef DEBUG_TREE
2169 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002170 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002171#endif
2172 return(NULL);
2173 }
2174
2175 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2176 (cur->doc != parent->doc)) {
2177#ifdef DEBUG_TREE
2178 xmlGenericError(xmlGenericErrorContext,
2179 "Elements moved to a different document\n");
2180#endif
2181 }
2182
2183 /*
2184 * add the first element at the end of the children list.
2185 */
2186 if (parent->children == NULL) {
2187 parent->children = cur;
2188 } else {
2189 /*
2190 * If cur and parent->last both are TEXT nodes, then merge them.
2191 */
2192 if ((cur->type == XML_TEXT_NODE) &&
2193 (parent->last->type == XML_TEXT_NODE) &&
2194 (cur->name == parent->last->name)) {
2195#ifndef XML_USE_BUFFER_CONTENT
2196 xmlNodeAddContent(parent->last, cur->content);
2197#else
2198 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2199#endif
2200 /*
2201 * if it's the only child, nothing more to be done.
2202 */
2203 if (cur->next == NULL) {
2204 xmlFreeNode(cur);
2205 return(parent->last);
2206 }
2207 prev = cur;
2208 cur = cur->next;
2209 xmlFreeNode(prev);
2210 }
2211 prev = parent->last;
2212 prev->next = cur;
2213 cur->prev = prev;
2214 }
2215 while (cur->next != NULL) {
2216 cur->parent = parent;
2217 if (cur->doc != parent->doc) {
2218 xmlSetTreeDoc(cur, parent->doc);
2219 }
2220 cur = cur->next;
2221 }
2222 cur->parent = parent;
2223 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2224 parent->last = cur;
2225
2226 return(cur);
2227}
2228
2229/**
2230 * xmlAddChild:
2231 * @parent: the parent node
2232 * @cur: the child node
2233 *
2234 * Add a new child element, to @parent, at the end of the child list
2235 * merging adjacent TEXT nodes (in which case @cur is freed)
2236 * Returns the child or NULL in case of error.
2237 */
2238xmlNodePtr
2239xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2240 xmlNodePtr prev;
2241
2242 if (parent == NULL) {
2243#ifdef DEBUG_TREE
2244 xmlGenericError(xmlGenericErrorContext,
2245 "xmlAddChild : parent == NULL\n");
2246#endif
2247 return(NULL);
2248 }
2249
2250 if (cur == NULL) {
2251#ifdef DEBUG_TREE
2252 xmlGenericError(xmlGenericErrorContext,
2253 "xmlAddChild : child == NULL\n");
2254#endif
2255 return(NULL);
2256 }
2257
Owen Taylor3473f882001-02-23 17:55:21 +00002258 /*
2259 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002260 * cur is then freed.
2261 */
2262 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002263 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002264 (parent->content != NULL)) {
2265#ifndef XML_USE_BUFFER_CONTENT
2266 xmlNodeAddContent(parent, cur->content);
2267#else
2268 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2269#endif
2270 xmlFreeNode(cur);
2271 return(parent);
2272 }
2273 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2274 (parent->last->name == cur->name)) {
2275#ifndef XML_USE_BUFFER_CONTENT
2276 xmlNodeAddContent(parent->last, cur->content);
2277#else
2278 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2279#endif
2280 xmlFreeNode(cur);
2281 return(parent->last);
2282 }
2283 }
2284
2285 /*
2286 * add the new element at the end of the children list.
2287 */
2288 cur->parent = parent;
2289 if (cur->doc != parent->doc) {
2290 xmlSetTreeDoc(cur, parent->doc);
2291 }
2292
2293 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002294 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002295 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002296 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002297 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002298#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002299 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002300#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002301 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002302#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002303 xmlFreeNode(cur);
2304 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002305 }
2306 if (parent->children == NULL) {
2307 parent->children = cur;
2308 parent->last = cur;
2309 } else {
2310 prev = parent->last;
2311 prev->next = cur;
2312 cur->prev = prev;
2313 parent->last = cur;
2314 }
2315
2316 return(cur);
2317}
2318
2319/**
2320 * xmlGetLastChild:
2321 * @parent: the parent node
2322 *
2323 * Search the last child of a node.
2324 * Returns the last child or NULL if none.
2325 */
2326xmlNodePtr
2327xmlGetLastChild(xmlNodePtr parent) {
2328 if (parent == NULL) {
2329#ifdef DEBUG_TREE
2330 xmlGenericError(xmlGenericErrorContext,
2331 "xmlGetLastChild : parent == NULL\n");
2332#endif
2333 return(NULL);
2334 }
2335 return(parent->last);
2336}
2337
2338/**
2339 * xmlFreeNodeList:
2340 * @cur: the first node in the list
2341 *
2342 * Free a node and all its siblings, this is a recursive behaviour, all
2343 * the children are freed too.
2344 */
2345void
2346xmlFreeNodeList(xmlNodePtr cur) {
2347 xmlNodePtr next;
2348 if (cur == NULL) {
2349#ifdef DEBUG_TREE
2350 xmlGenericError(xmlGenericErrorContext,
2351 "xmlFreeNodeList : node == NULL\n");
2352#endif
2353 return;
2354 }
2355 while (cur != NULL) {
2356 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002357 /* unroll to speed up freeing the document */
2358 if (cur->type != XML_DTD_NODE) {
2359 if ((cur->children != NULL) &&
2360 (cur->type != XML_ENTITY_REF_NODE))
2361 xmlFreeNodeList(cur->children);
2362 if (cur->properties != NULL)
2363 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002364 if ((cur->type != XML_ELEMENT_NODE) &&
2365 (cur->type != XML_XINCLUDE_START) &&
2366 (cur->type != XML_XINCLUDE_END) &&
2367 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002368#ifndef XML_USE_BUFFER_CONTENT
2369 if (cur->content != NULL) xmlFree(cur->content);
2370#else
2371 if (cur->content != NULL) xmlBufferFree(cur->content);
2372#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002373 }
2374 if (((cur->type == XML_ELEMENT_NODE) ||
2375 (cur->type == XML_XINCLUDE_START) ||
2376 (cur->type == XML_XINCLUDE_END)) &&
2377 (cur->nsDef != NULL))
2378 xmlFreeNsList(cur->nsDef);
2379
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002380 /*
2381 * When a node is a text node or a comment, it uses a global static
2382 * variable for the name of the node.
2383 *
2384 * The xmlStrEqual comparisons need to be done when (happened with
2385 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002386 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002387 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002388 * the string addresses compare are not sufficient.
2389 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002390 if ((cur->name != NULL) &&
2391 (cur->name != xmlStringText) &&
2392 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002393 (cur->name != xmlStringComment)) {
2394 if (cur->type == XML_TEXT_NODE) {
2395 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2396 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2397 xmlFree((char *) cur->name);
2398 } else if (cur->type == XML_COMMENT_NODE) {
2399 if (!xmlStrEqual(cur->name, xmlStringComment))
2400 xmlFree((char *) cur->name);
2401 } else
2402 xmlFree((char *) cur->name);
2403 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002404 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002405 xmlFree(cur);
2406 }
Owen Taylor3473f882001-02-23 17:55:21 +00002407 cur = next;
2408 }
2409}
2410
2411/**
2412 * xmlFreeNode:
2413 * @cur: the node
2414 *
2415 * Free a node, this is a recursive behaviour, all the children are freed too.
2416 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2417 */
2418void
2419xmlFreeNode(xmlNodePtr cur) {
2420 if (cur == NULL) {
2421#ifdef DEBUG_TREE
2422 xmlGenericError(xmlGenericErrorContext,
2423 "xmlFreeNode : node == NULL\n");
2424#endif
2425 return;
2426 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002427 /* use xmlFreeDtd for DTD nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002428 if (cur->type == XML_DTD_NODE)
2429 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002430 if ((cur->children != NULL) &&
2431 (cur->type != XML_ENTITY_REF_NODE))
2432 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002433 if (cur->properties != NULL)
2434 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002435 if ((cur->type != XML_ELEMENT_NODE) &&
2436 (cur->content != NULL) &&
2437 (cur->type != XML_ENTITY_REF_NODE) &&
2438 (cur->type != XML_XINCLUDE_END) &&
2439 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002440#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002441 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002442#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002443 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002444#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002445 }
2446
Daniel Veillardacd370f2001-06-09 17:17:51 +00002447 /*
2448 * When a node is a text node or a comment, it uses a global static
2449 * variable for the name of the node.
2450 *
2451 * The xmlStrEqual comparisons need to be done when (happened with
2452 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002453 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002454 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002455 * are not sufficient.
2456 */
Owen Taylor3473f882001-02-23 17:55:21 +00002457 if ((cur->name != NULL) &&
2458 (cur->name != xmlStringText) &&
2459 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002460 (cur->name != xmlStringComment)) {
2461 if (cur->type == XML_TEXT_NODE) {
2462 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2463 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2464 xmlFree((char *) cur->name);
2465 } else if (cur->type == XML_COMMENT_NODE) {
2466 if (!xmlStrEqual(cur->name, xmlStringComment))
2467 xmlFree((char *) cur->name);
2468 } else
2469 xmlFree((char *) cur->name);
2470 }
2471
Owen Taylor3473f882001-02-23 17:55:21 +00002472 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002473 xmlFree(cur);
2474}
2475
2476/**
2477 * xmlUnlinkNode:
2478 * @cur: the node
2479 *
2480 * Unlink a node from it's current context, the node is not freed
2481 */
2482void
2483xmlUnlinkNode(xmlNodePtr cur) {
2484 if (cur == NULL) {
2485#ifdef DEBUG_TREE
2486 xmlGenericError(xmlGenericErrorContext,
2487 "xmlUnlinkNode : node == NULL\n");
2488#endif
2489 return;
2490 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002491 if (cur->type == XML_DTD_NODE) {
2492 xmlDocPtr doc;
2493 doc = cur->doc;
2494 if (doc->intSubset == (xmlDtdPtr) cur)
2495 doc->intSubset = NULL;
2496 if (doc->extSubset == (xmlDtdPtr) cur)
2497 doc->extSubset = NULL;
2498 }
Owen Taylor3473f882001-02-23 17:55:21 +00002499 if ((cur->parent != NULL) && (cur->parent->children == cur))
2500 cur->parent->children = cur->next;
2501 if ((cur->parent != NULL) && (cur->parent->last == cur))
2502 cur->parent->last = cur->prev;
2503 if (cur->next != NULL)
2504 cur->next->prev = cur->prev;
2505 if (cur->prev != NULL)
2506 cur->prev->next = cur->next;
2507 cur->next = cur->prev = NULL;
2508 cur->parent = NULL;
2509}
2510
2511/**
2512 * xmlReplaceNode:
2513 * @old: the old node
2514 * @cur: the node
2515 *
2516 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002517 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002518 * first unlinked from its existing context.
2519 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002520 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002521 */
2522xmlNodePtr
2523xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2524 if (old == NULL) {
2525#ifdef DEBUG_TREE
2526 xmlGenericError(xmlGenericErrorContext,
2527 "xmlReplaceNode : old == NULL\n");
2528#endif
2529 return(NULL);
2530 }
2531 if (cur == NULL) {
2532 xmlUnlinkNode(old);
2533 return(old);
2534 }
2535 if (cur == old) {
2536 return(old);
2537 }
2538 xmlUnlinkNode(cur);
2539 cur->doc = old->doc;
2540 cur->parent = old->parent;
2541 cur->next = old->next;
2542 if (cur->next != NULL)
2543 cur->next->prev = cur;
2544 cur->prev = old->prev;
2545 if (cur->prev != NULL)
2546 cur->prev->next = cur;
2547 if (cur->parent != NULL) {
2548 if (cur->parent->children == old)
2549 cur->parent->children = cur;
2550 if (cur->parent->last == old)
2551 cur->parent->last = cur;
2552 }
2553 old->next = old->prev = NULL;
2554 old->parent = NULL;
2555 return(old);
2556}
2557
2558/************************************************************************
2559 * *
2560 * Copy operations *
2561 * *
2562 ************************************************************************/
2563
2564/**
2565 * xmlCopyNamespace:
2566 * @cur: the namespace
2567 *
2568 * Do a copy of the namespace.
2569 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002570 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002571 */
2572xmlNsPtr
2573xmlCopyNamespace(xmlNsPtr cur) {
2574 xmlNsPtr ret;
2575
2576 if (cur == NULL) return(NULL);
2577 switch (cur->type) {
2578 case XML_LOCAL_NAMESPACE:
2579 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2580 break;
2581 default:
2582#ifdef DEBUG_TREE
2583 xmlGenericError(xmlGenericErrorContext,
2584 "xmlCopyNamespace: invalid type %d\n", cur->type);
2585#endif
2586 return(NULL);
2587 }
2588 return(ret);
2589}
2590
2591/**
2592 * xmlCopyNamespaceList:
2593 * @cur: the first namespace
2594 *
2595 * Do a copy of an namespace list.
2596 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002597 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002598 */
2599xmlNsPtr
2600xmlCopyNamespaceList(xmlNsPtr cur) {
2601 xmlNsPtr ret = NULL;
2602 xmlNsPtr p = NULL,q;
2603
2604 while (cur != NULL) {
2605 q = xmlCopyNamespace(cur);
2606 if (p == NULL) {
2607 ret = p = q;
2608 } else {
2609 p->next = q;
2610 p = q;
2611 }
2612 cur = cur->next;
2613 }
2614 return(ret);
2615}
2616
2617static xmlNodePtr
2618xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2619/**
2620 * xmlCopyProp:
2621 * @target: the element where the attribute will be grafted
2622 * @cur: the attribute
2623 *
2624 * Do a copy of the attribute.
2625 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002626 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002627 */
2628xmlAttrPtr
2629xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2630 xmlAttrPtr ret;
2631
2632 if (cur == NULL) return(NULL);
2633 if (target != NULL)
2634 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2635 else if (cur->parent != NULL)
2636 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2637 else if (cur->children != NULL)
2638 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2639 else
2640 ret = xmlNewDocProp(NULL, cur->name, NULL);
2641 if (ret == NULL) return(NULL);
2642 ret->parent = target;
2643
2644 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002645 xmlNsPtr ns;
2646 if (target->doc)
Owen Taylor3473f882001-02-23 17:55:21 +00002647 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
Daniel Veillard8107a222002-01-13 14:10:10 +00002648 else if (cur->doc) /* target may not yet have a doc : KPI */
2649 ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2650 else
2651 ns = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002652 ret->ns = ns;
2653 } else
2654 ret->ns = NULL;
2655
2656 if (cur->children != NULL) {
2657 xmlNodePtr tmp;
2658
2659 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2660 ret->last = NULL;
2661 tmp = ret->children;
2662 while (tmp != NULL) {
2663 /* tmp->parent = (xmlNodePtr)ret; */
2664 if (tmp->next == NULL)
2665 ret->last = tmp;
2666 tmp = tmp->next;
2667 }
2668 }
2669 return(ret);
2670}
2671
2672/**
2673 * xmlCopyPropList:
2674 * @target: the element where the attributes will be grafted
2675 * @cur: the first attribute
2676 *
2677 * Do a copy of an attribute list.
2678 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002679 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002680 */
2681xmlAttrPtr
2682xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2683 xmlAttrPtr ret = NULL;
2684 xmlAttrPtr p = NULL,q;
2685
2686 while (cur != NULL) {
2687 q = xmlCopyProp(target, cur);
2688 if (p == NULL) {
2689 ret = p = q;
2690 } else {
2691 p->next = q;
2692 q->prev = p;
2693 p = q;
2694 }
2695 cur = cur->next;
2696 }
2697 return(ret);
2698}
2699
2700/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002701 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002702 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002703 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002704 * tricky reason: namespaces. Doing a direct copy of a node
2705 * say RPM:Copyright without changing the namespace pointer to
2706 * something else can produce stale links. One way to do it is
2707 * to keep a reference counter but this doesn't work as soon
2708 * as one move the element or the subtree out of the scope of
2709 * the existing namespace. The actual solution seems to add
2710 * a copy of the namespace at the top of the copied tree if
2711 * not available in the subtree.
2712 * Hence two functions, the public front-end call the inner ones
2713 */
2714
2715static xmlNodePtr
2716xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2717
2718static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002719xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002720 int recursive) {
2721 xmlNodePtr ret;
2722
2723 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002724 switch (node->type) {
2725 case XML_TEXT_NODE:
2726 case XML_CDATA_SECTION_NODE:
2727 case XML_ELEMENT_NODE:
2728 case XML_ENTITY_REF_NODE:
2729 case XML_ENTITY_NODE:
2730 case XML_PI_NODE:
2731 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002732 case XML_XINCLUDE_START:
2733 case XML_XINCLUDE_END:
2734 break;
2735 case XML_ATTRIBUTE_NODE:
2736 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2737 case XML_NAMESPACE_DECL:
2738 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2739
Daniel Veillard39196eb2001-06-19 18:09:42 +00002740 case XML_DOCUMENT_NODE:
2741 case XML_HTML_DOCUMENT_NODE:
2742#ifdef LIBXML_DOCB_ENABLED
2743 case XML_DOCB_DOCUMENT_NODE:
2744#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002745 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002746 case XML_DOCUMENT_TYPE_NODE:
2747 case XML_DOCUMENT_FRAG_NODE:
2748 case XML_NOTATION_NODE:
2749 case XML_DTD_NODE:
2750 case XML_ELEMENT_DECL:
2751 case XML_ATTRIBUTE_DECL:
2752 case XML_ENTITY_DECL:
2753 return(NULL);
2754 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002755
Owen Taylor3473f882001-02-23 17:55:21 +00002756 /*
2757 * Allocate a new node and fill the fields.
2758 */
2759 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2760 if (ret == NULL) {
2761 xmlGenericError(xmlGenericErrorContext,
2762 "xmlStaticCopyNode : malloc failed\n");
2763 return(NULL);
2764 }
2765 memset(ret, 0, sizeof(xmlNode));
2766 ret->type = node->type;
2767
2768 ret->doc = doc;
2769 ret->parent = parent;
2770 if (node->name == xmlStringText)
2771 ret->name = xmlStringText;
2772 else if (node->name == xmlStringTextNoenc)
2773 ret->name = xmlStringTextNoenc;
2774 else if (node->name == xmlStringComment)
2775 ret->name = xmlStringComment;
2776 else if (node->name != NULL)
2777 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002778 if ((node->type != XML_ELEMENT_NODE) &&
2779 (node->content != NULL) &&
2780 (node->type != XML_ENTITY_REF_NODE) &&
2781 (node->type != XML_XINCLUDE_END) &&
2782 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002783#ifndef XML_USE_BUFFER_CONTENT
2784 ret->content = xmlStrdup(node->content);
2785#else
2786 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2787 xmlBufferSetAllocationScheme(ret->content,
2788 xmlGetBufferAllocationScheme());
2789 xmlBufferAdd(ret->content,
2790 xmlBufferContent(node->content),
2791 xmlBufferLength(node->content));
2792#endif
Daniel Veillard8107a222002-01-13 14:10:10 +00002793 }else{
2794 if (node->type == XML_ELEMENT_NODE)
2795 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002796 }
2797 if (parent != NULL)
2798 xmlAddChild(parent, ret);
2799
2800 if (!recursive) return(ret);
2801 if (node->nsDef != NULL)
2802 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2803
2804 if (node->ns != NULL) {
2805 xmlNsPtr ns;
2806
2807 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2808 if (ns == NULL) {
2809 /*
2810 * Humm, we are copying an element whose namespace is defined
2811 * out of the new tree scope. Search it in the original tree
2812 * and add it at the top of the new tree
2813 */
2814 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2815 if (ns != NULL) {
2816 xmlNodePtr root = ret;
2817
2818 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002819 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002820 }
2821 } else {
2822 /*
2823 * reference the existing namespace definition in our own tree.
2824 */
2825 ret->ns = ns;
2826 }
2827 }
2828 if (node->properties != NULL)
2829 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002830 if (node->type == XML_ENTITY_REF_NODE) {
2831 if ((doc == NULL) || (node->doc != doc)) {
2832 /*
2833 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002834 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002835 * we cannot keep the reference. Try to find it in the
2836 * target document.
2837 */
2838 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2839 } else {
2840 ret->children = node->children;
2841 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002842 ret->last = ret->children;
2843 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002844 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002845 UPDATE_LAST_CHILD_AND_PARENT(ret)
2846 }
Owen Taylor3473f882001-02-23 17:55:21 +00002847 return(ret);
2848}
2849
2850static xmlNodePtr
2851xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2852 xmlNodePtr ret = NULL;
2853 xmlNodePtr p = NULL,q;
2854
2855 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002856 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002857 if (doc == NULL) {
2858 node = node->next;
2859 continue;
2860 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002861 if (doc->intSubset == NULL) {
2862 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2863 q->doc = doc;
2864 q->parent = parent;
2865 doc->intSubset = (xmlDtdPtr) q;
2866 } else {
2867 q = (xmlNodePtr) doc->intSubset;
2868 }
2869 } else
2870 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002871 if (ret == NULL) {
2872 q->prev = NULL;
2873 ret = p = q;
2874 } else {
2875 p->next = q;
2876 q->prev = p;
2877 p = q;
2878 }
2879 node = node->next;
2880 }
2881 return(ret);
2882}
2883
2884/**
2885 * xmlCopyNode:
2886 * @node: the node
2887 * @recursive: if 1 do a recursive copy.
2888 *
2889 * Do a copy of the node.
2890 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002891 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002892 */
2893xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002894xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002895 xmlNodePtr ret;
2896
2897 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2898 return(ret);
2899}
2900
2901/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002902 * xmlDocCopyNode:
2903 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00002904 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00002905 * @recursive: if 1 do a recursive copy.
2906 *
2907 * Do a copy of the node to a given document.
2908 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002909 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00002910 */
2911xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002912xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002913 xmlNodePtr ret;
2914
2915 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2916 return(ret);
2917}
2918
2919/**
Owen Taylor3473f882001-02-23 17:55:21 +00002920 * xmlCopyNodeList:
2921 * @node: the first node in the list.
2922 *
2923 * Do a recursive copy of the node list.
2924 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002925 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002926 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002927xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002928 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2929 return(ret);
2930}
2931
2932/**
Owen Taylor3473f882001-02-23 17:55:21 +00002933 * xmlCopyDtd:
2934 * @dtd: the dtd
2935 *
2936 * Do a copy of the dtd.
2937 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002938 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002939 */
2940xmlDtdPtr
2941xmlCopyDtd(xmlDtdPtr dtd) {
2942 xmlDtdPtr ret;
2943
2944 if (dtd == NULL) return(NULL);
2945 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2946 if (ret == NULL) return(NULL);
2947 if (dtd->entities != NULL)
2948 ret->entities = (void *) xmlCopyEntitiesTable(
2949 (xmlEntitiesTablePtr) dtd->entities);
2950 if (dtd->notations != NULL)
2951 ret->notations = (void *) xmlCopyNotationTable(
2952 (xmlNotationTablePtr) dtd->notations);
2953 if (dtd->elements != NULL)
2954 ret->elements = (void *) xmlCopyElementTable(
2955 (xmlElementTablePtr) dtd->elements);
2956 if (dtd->attributes != NULL)
2957 ret->attributes = (void *) xmlCopyAttributeTable(
2958 (xmlAttributeTablePtr) dtd->attributes);
2959 return(ret);
2960}
2961
2962/**
2963 * xmlCopyDoc:
2964 * @doc: the document
2965 * @recursive: if 1 do a recursive copy.
2966 *
2967 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002968 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00002969 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002970 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002971 */
2972xmlDocPtr
2973xmlCopyDoc(xmlDocPtr doc, int recursive) {
2974 xmlDocPtr ret;
2975
2976 if (doc == NULL) return(NULL);
2977 ret = xmlNewDoc(doc->version);
2978 if (ret == NULL) return(NULL);
2979 if (doc->name != NULL)
2980 ret->name = xmlMemStrdup(doc->name);
2981 if (doc->encoding != NULL)
2982 ret->encoding = xmlStrdup(doc->encoding);
2983 ret->charset = doc->charset;
2984 ret->compression = doc->compression;
2985 ret->standalone = doc->standalone;
2986 if (!recursive) return(ret);
2987
Daniel Veillardb33c2012001-04-25 12:59:04 +00002988 ret->last = NULL;
2989 ret->children = NULL;
2990 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002991 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002992 ret->intSubset->doc = ret;
2993 ret->intSubset->parent = ret;
2994 }
Owen Taylor3473f882001-02-23 17:55:21 +00002995 if (doc->oldNs != NULL)
2996 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2997 if (doc->children != NULL) {
2998 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002999
3000 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3001 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003002 ret->last = NULL;
3003 tmp = ret->children;
3004 while (tmp != NULL) {
3005 if (tmp->next == NULL)
3006 ret->last = tmp;
3007 tmp = tmp->next;
3008 }
3009 }
3010 return(ret);
3011}
3012
3013/************************************************************************
3014 * *
3015 * Content access functions *
3016 * *
3017 ************************************************************************/
3018
3019/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003020 * xmlGetLineNo:
3021 * @node : valid node
3022 *
3023 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003024 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003025 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003026 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003027 */
3028long
3029xmlGetLineNo(xmlNodePtr node)
3030{
3031 long result = -1;
3032
3033 if (!node)
3034 return result;
3035 if (node->type == XML_ELEMENT_NODE)
3036 result = (long) node->content;
3037 else if ((node->prev != NULL) &&
3038 ((node->prev->type == XML_ELEMENT_NODE) ||
3039 (node->prev->type == XML_TEXT_NODE)))
3040 result = xmlGetLineNo(node->prev);
3041 else if ((node->parent != NULL) &&
3042 ((node->parent->type == XML_ELEMENT_NODE) ||
3043 (node->parent->type == XML_TEXT_NODE)))
3044 result = xmlGetLineNo(node->parent);
3045
3046 return result;
3047}
3048
3049/**
3050 * xmlGetNodePath:
3051 * @node: a node
3052 *
3053 * Build a structure based Path for the given node
3054 *
3055 * Returns the new path or NULL in case of error. The caller must free
3056 * the returned string
3057 */
3058xmlChar *
3059xmlGetNodePath(xmlNodePtr node)
3060{
3061 xmlNodePtr cur, tmp, next;
3062 xmlChar *buffer = NULL, *temp;
3063 size_t buf_len;
3064 xmlChar *buf;
3065 char sep;
3066 const char *name;
3067 char nametemp[100];
3068 int occur = 0;
3069
3070 if (node == NULL)
3071 return (NULL);
3072
3073 buf_len = 500;
3074 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3075 if (buffer == NULL)
3076 return (NULL);
3077 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3078 if (buf == NULL) {
3079 xmlFree(buffer);
3080 return (NULL);
3081 }
3082
3083 buffer[0] = 0;
3084 cur = node;
3085 do {
3086 name = "";
3087 sep = '?';
3088 occur = 0;
3089 if ((cur->type == XML_DOCUMENT_NODE) ||
3090 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3091 if (buffer[0] == '/')
3092 break;
3093 sep = '/';
3094 next = NULL;
3095 } else if (cur->type == XML_ELEMENT_NODE) {
3096 sep = '/';
3097 name = (const char *) cur->name;
3098 if (cur->ns) {
3099 snprintf(nametemp, sizeof(nametemp) - 1,
3100 "%s:%s", cur->ns->prefix, cur->name);
3101 nametemp[sizeof(nametemp) - 1] = 0;
3102 name = nametemp;
3103 }
3104 next = cur->parent;
3105
3106 /*
3107 * Thumbler index computation
3108 */
3109 tmp = cur->prev;
3110 while (tmp != NULL) {
3111 if (xmlStrEqual(cur->name, tmp->name))
3112 occur++;
3113 tmp = tmp->prev;
3114 }
3115 if (occur == 0) {
3116 tmp = cur->next;
3117 while (tmp != NULL) {
3118 if (xmlStrEqual(cur->name, tmp->name))
3119 occur++;
3120 tmp = tmp->next;
3121 }
3122 if (occur != 0)
3123 occur = 1;
3124 } else
3125 occur++;
3126 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3127 sep = '@';
3128 name = (const char *) (((xmlAttrPtr) cur)->name);
3129 next = ((xmlAttrPtr) cur)->parent;
3130 } else {
3131 next = cur->parent;
3132 }
3133
3134 /*
3135 * Make sure there is enough room
3136 */
3137 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3138 buf_len =
3139 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3140 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3141 if (temp == NULL) {
3142 xmlFree(buf);
3143 xmlFree(buffer);
3144 return (NULL);
3145 }
3146 buffer = temp;
3147 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3148 if (temp == NULL) {
3149 xmlFree(buf);
3150 xmlFree(buffer);
3151 return (NULL);
3152 }
3153 buf = temp;
3154 }
3155 if (occur == 0)
3156 snprintf((char *) buf, buf_len, "%c%s%s",
3157 sep, name, (char *) buffer);
3158 else
3159 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3160 sep, name, occur, (char *) buffer);
3161 snprintf((char *) buffer, buf_len, "%s", buf);
3162 cur = next;
3163 } while (cur != NULL);
3164 xmlFree(buf);
3165 return (buffer);
3166}
3167
3168/**
Owen Taylor3473f882001-02-23 17:55:21 +00003169 * xmlDocGetRootElement:
3170 * @doc: the document
3171 *
3172 * Get the root element of the document (doc->children is a list
3173 * containing possibly comments, PIs, etc ...).
3174 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003175 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003176 */
3177xmlNodePtr
3178xmlDocGetRootElement(xmlDocPtr doc) {
3179 xmlNodePtr ret;
3180
3181 if (doc == NULL) return(NULL);
3182 ret = doc->children;
3183 while (ret != NULL) {
3184 if (ret->type == XML_ELEMENT_NODE)
3185 return(ret);
3186 ret = ret->next;
3187 }
3188 return(ret);
3189}
3190
3191/**
3192 * xmlDocSetRootElement:
3193 * @doc: the document
3194 * @root: the new document root element
3195 *
3196 * Set the root element of the document (doc->children is a list
3197 * containing possibly comments, PIs, etc ...).
3198 *
3199 * Returns the old root element if any was found
3200 */
3201xmlNodePtr
3202xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3203 xmlNodePtr old = NULL;
3204
3205 if (doc == NULL) return(NULL);
3206 old = doc->children;
3207 while (old != NULL) {
3208 if (old->type == XML_ELEMENT_NODE)
3209 break;
3210 old = old->next;
3211 }
3212 if (old == NULL) {
3213 if (doc->children == NULL) {
3214 doc->children = root;
3215 doc->last = root;
3216 } else {
3217 xmlAddSibling(doc->children, root);
3218 }
3219 } else {
3220 xmlReplaceNode(old, root);
3221 }
3222 return(old);
3223}
3224
3225/**
3226 * xmlNodeSetLang:
3227 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003228 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003229 *
3230 * Set the language of a node, i.e. the values of the xml:lang
3231 * attribute.
3232 */
3233void
3234xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3235 if (cur == NULL) return;
3236 switch(cur->type) {
3237 case XML_TEXT_NODE:
3238 case XML_CDATA_SECTION_NODE:
3239 case XML_COMMENT_NODE:
3240 case XML_DOCUMENT_NODE:
3241 case XML_DOCUMENT_TYPE_NODE:
3242 case XML_DOCUMENT_FRAG_NODE:
3243 case XML_NOTATION_NODE:
3244 case XML_HTML_DOCUMENT_NODE:
3245 case XML_DTD_NODE:
3246 case XML_ELEMENT_DECL:
3247 case XML_ATTRIBUTE_DECL:
3248 case XML_ENTITY_DECL:
3249 case XML_PI_NODE:
3250 case XML_ENTITY_REF_NODE:
3251 case XML_ENTITY_NODE:
3252 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003253#ifdef LIBXML_DOCB_ENABLED
3254 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003255#endif
3256 case XML_XINCLUDE_START:
3257 case XML_XINCLUDE_END:
3258 return;
3259 case XML_ELEMENT_NODE:
3260 case XML_ATTRIBUTE_NODE:
3261 break;
3262 }
3263 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3264}
3265
3266/**
3267 * xmlNodeGetLang:
3268 * @cur: the node being checked
3269 *
3270 * Searches the language of a node, i.e. the values of the xml:lang
3271 * attribute or the one carried by the nearest ancestor.
3272 *
3273 * Returns a pointer to the lang value, or NULL if not found
3274 * It's up to the caller to free the memory.
3275 */
3276xmlChar *
3277xmlNodeGetLang(xmlNodePtr cur) {
3278 xmlChar *lang;
3279
3280 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003281 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003282 if (lang != NULL)
3283 return(lang);
3284 cur = cur->parent;
3285 }
3286 return(NULL);
3287}
3288
3289
3290/**
3291 * xmlNodeSetSpacePreserve:
3292 * @cur: the node being changed
3293 * @val: the xml:space value ("0": default, 1: "preserve")
3294 *
3295 * Set (or reset) the space preserving behaviour of a node, i.e. the
3296 * value of the xml:space attribute.
3297 */
3298void
3299xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3300 if (cur == NULL) return;
3301 switch(cur->type) {
3302 case XML_TEXT_NODE:
3303 case XML_CDATA_SECTION_NODE:
3304 case XML_COMMENT_NODE:
3305 case XML_DOCUMENT_NODE:
3306 case XML_DOCUMENT_TYPE_NODE:
3307 case XML_DOCUMENT_FRAG_NODE:
3308 case XML_NOTATION_NODE:
3309 case XML_HTML_DOCUMENT_NODE:
3310 case XML_DTD_NODE:
3311 case XML_ELEMENT_DECL:
3312 case XML_ATTRIBUTE_DECL:
3313 case XML_ENTITY_DECL:
3314 case XML_PI_NODE:
3315 case XML_ENTITY_REF_NODE:
3316 case XML_ENTITY_NODE:
3317 case XML_NAMESPACE_DECL:
3318 case XML_XINCLUDE_START:
3319 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003320#ifdef LIBXML_DOCB_ENABLED
3321 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003322#endif
3323 return;
3324 case XML_ELEMENT_NODE:
3325 case XML_ATTRIBUTE_NODE:
3326 break;
3327 }
3328 switch (val) {
3329 case 0:
3330 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3331 break;
3332 case 1:
3333 xmlSetProp(cur, BAD_CAST "xml:space",
3334 BAD_CAST "preserve");
3335 break;
3336 }
3337}
3338
3339/**
3340 * xmlNodeGetSpacePreserve:
3341 * @cur: the node being checked
3342 *
3343 * Searches the space preserving behaviour of a node, i.e. the values
3344 * of the xml:space attribute or the one carried by the nearest
3345 * ancestor.
3346 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003347 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003348 */
3349int
3350xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3351 xmlChar *space;
3352
3353 while (cur != NULL) {
3354 space = xmlGetProp(cur, BAD_CAST "xml:space");
3355 if (space != NULL) {
3356 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3357 xmlFree(space);
3358 return(1);
3359 }
3360 if (xmlStrEqual(space, BAD_CAST "default")) {
3361 xmlFree(space);
3362 return(0);
3363 }
3364 xmlFree(space);
3365 }
3366 cur = cur->parent;
3367 }
3368 return(-1);
3369}
3370
3371/**
3372 * xmlNodeSetName:
3373 * @cur: the node being changed
3374 * @name: the new tag name
3375 *
3376 * Set (or reset) the name of a node.
3377 */
3378void
3379xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3380 if (cur == NULL) return;
3381 if (name == NULL) return;
3382 switch(cur->type) {
3383 case XML_TEXT_NODE:
3384 case XML_CDATA_SECTION_NODE:
3385 case XML_COMMENT_NODE:
3386 case XML_DOCUMENT_TYPE_NODE:
3387 case XML_DOCUMENT_FRAG_NODE:
3388 case XML_NOTATION_NODE:
3389 case XML_HTML_DOCUMENT_NODE:
3390 case XML_NAMESPACE_DECL:
3391 case XML_XINCLUDE_START:
3392 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003393#ifdef LIBXML_DOCB_ENABLED
3394 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003395#endif
3396 return;
3397 case XML_ELEMENT_NODE:
3398 case XML_ATTRIBUTE_NODE:
3399 case XML_PI_NODE:
3400 case XML_ENTITY_REF_NODE:
3401 case XML_ENTITY_NODE:
3402 case XML_DTD_NODE:
3403 case XML_DOCUMENT_NODE:
3404 case XML_ELEMENT_DECL:
3405 case XML_ATTRIBUTE_DECL:
3406 case XML_ENTITY_DECL:
3407 break;
3408 }
3409 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3410 cur->name = xmlStrdup(name);
3411}
3412
3413/**
3414 * xmlNodeSetBase:
3415 * @cur: the node being changed
3416 * @uri: the new base URI
3417 *
3418 * Set (or reset) the base URI of a node, i.e. the value of the
3419 * xml:base attribute.
3420 */
3421void
3422xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3423 if (cur == NULL) return;
3424 switch(cur->type) {
3425 case XML_TEXT_NODE:
3426 case XML_CDATA_SECTION_NODE:
3427 case XML_COMMENT_NODE:
3428 case XML_DOCUMENT_NODE:
3429 case XML_DOCUMENT_TYPE_NODE:
3430 case XML_DOCUMENT_FRAG_NODE:
3431 case XML_NOTATION_NODE:
3432 case XML_HTML_DOCUMENT_NODE:
3433 case XML_DTD_NODE:
3434 case XML_ELEMENT_DECL:
3435 case XML_ATTRIBUTE_DECL:
3436 case XML_ENTITY_DECL:
3437 case XML_PI_NODE:
3438 case XML_ENTITY_REF_NODE:
3439 case XML_ENTITY_NODE:
3440 case XML_NAMESPACE_DECL:
3441 case XML_XINCLUDE_START:
3442 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003443#ifdef LIBXML_DOCB_ENABLED
3444 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003445#endif
3446 return;
3447 case XML_ELEMENT_NODE:
3448 case XML_ATTRIBUTE_NODE:
3449 break;
3450 }
3451 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3452}
3453
3454/**
Owen Taylor3473f882001-02-23 17:55:21 +00003455 * xmlNodeGetBase:
3456 * @doc: the document the node pertains to
3457 * @cur: the node being checked
3458 *
3459 * Searches for the BASE URL. The code should work on both XML
3460 * and HTML document even if base mechanisms are completely different.
3461 * It returns the base as defined in RFC 2396 sections
3462 * 5.1.1. Base URI within Document Content
3463 * and
3464 * 5.1.2. Base URI from the Encapsulating Entity
3465 * However it does not return the document base (5.1.3), use
3466 * xmlDocumentGetBase() for this
3467 *
3468 * Returns a pointer to the base URL, or NULL if not found
3469 * It's up to the caller to free the memory.
3470 */
3471xmlChar *
3472xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003473 xmlChar *oldbase = NULL;
3474 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003475
3476 if ((cur == NULL) && (doc == NULL))
3477 return(NULL);
3478 if (doc == NULL) doc = cur->doc;
3479 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3480 cur = doc->children;
3481 while ((cur != NULL) && (cur->name != NULL)) {
3482 if (cur->type != XML_ELEMENT_NODE) {
3483 cur = cur->next;
3484 continue;
3485 }
3486 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3487 cur = cur->children;
3488 continue;
3489 }
3490 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3491 cur = cur->children;
3492 continue;
3493 }
3494 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3495 return(xmlGetProp(cur, BAD_CAST "href"));
3496 }
3497 cur = cur->next;
3498 }
3499 return(NULL);
3500 }
3501 while (cur != NULL) {
3502 if (cur->type == XML_ENTITY_DECL) {
3503 xmlEntityPtr ent = (xmlEntityPtr) cur;
3504 return(xmlStrdup(ent->URI));
3505 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003506 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003507 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003508 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003509 if (oldbase != NULL) {
3510 newbase = xmlBuildURI(oldbase, base);
3511 if (newbase != NULL) {
3512 xmlFree(oldbase);
3513 xmlFree(base);
3514 oldbase = newbase;
3515 } else {
3516 xmlFree(oldbase);
3517 xmlFree(base);
3518 return(NULL);
3519 }
3520 } else {
3521 oldbase = base;
3522 }
3523 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3524 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3525 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3526 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003527 }
3528 }
Owen Taylor3473f882001-02-23 17:55:21 +00003529 cur = cur->parent;
3530 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003531 if ((doc != NULL) && (doc->URL != NULL)) {
3532 if (oldbase == NULL)
3533 return(xmlStrdup(doc->URL));
3534 newbase = xmlBuildURI(oldbase, doc->URL);
3535 xmlFree(oldbase);
3536 return(newbase);
3537 }
3538 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003539}
3540
3541/**
3542 * xmlNodeGetContent:
3543 * @cur: the node being read
3544 *
3545 * Read the value of a node, this can be either the text carried
3546 * directly by this node if it's a TEXT node or the aggregate string
3547 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003548 * Entity references are substituted.
3549 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003550 * It's up to the caller to free the memory.
3551 */
3552xmlChar *
3553xmlNodeGetContent(xmlNodePtr cur) {
3554 if (cur == NULL) return(NULL);
3555 switch (cur->type) {
3556 case XML_DOCUMENT_FRAG_NODE:
3557 case XML_ELEMENT_NODE: {
3558 xmlNodePtr tmp = cur;
3559 xmlBufferPtr buffer;
3560 xmlChar *ret;
3561
3562 buffer = xmlBufferCreate();
3563 if (buffer == NULL)
3564 return(NULL);
3565 while (tmp != NULL) {
3566 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003567 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003568 case XML_TEXT_NODE:
3569 if (tmp->content != NULL)
3570#ifndef XML_USE_BUFFER_CONTENT
3571 xmlBufferCat(buffer, tmp->content);
3572#else
3573 xmlBufferCat(buffer,
3574 xmlBufferContent(tmp->content));
3575#endif
3576 break;
3577 case XML_ENTITY_REF_NODE: {
3578 xmlEntityPtr ent;
3579
3580 ent = xmlGetDocEntity(cur->doc, tmp->name);
3581 if (ent != NULL)
3582 xmlBufferCat(buffer, ent->content);
3583 }
3584 default:
3585 break;
3586 }
3587 /*
3588 * Skip to next node
3589 */
3590 if (tmp->children != NULL) {
3591 if (tmp->children->type != XML_ENTITY_DECL) {
3592 tmp = tmp->children;
3593 continue;
3594 }
3595 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003596 if (tmp == cur)
3597 break;
3598
Owen Taylor3473f882001-02-23 17:55:21 +00003599 if (tmp->next != NULL) {
3600 tmp = tmp->next;
3601 continue;
3602 }
3603
3604 do {
3605 tmp = tmp->parent;
3606 if (tmp == NULL)
3607 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003608 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003609 tmp = NULL;
3610 break;
3611 }
3612 if (tmp->next != NULL) {
3613 tmp = tmp->next;
3614 break;
3615 }
3616 } while (tmp != NULL);
3617 }
3618 ret = buffer->content;
3619 buffer->content = NULL;
3620 xmlBufferFree(buffer);
3621 return(ret);
3622 }
3623 case XML_ATTRIBUTE_NODE: {
3624 xmlAttrPtr attr = (xmlAttrPtr) cur;
3625 if (attr->parent != NULL)
3626 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3627 else
3628 return(xmlNodeListGetString(NULL, attr->children, 1));
3629 break;
3630 }
3631 case XML_COMMENT_NODE:
3632 case XML_PI_NODE:
3633 if (cur->content != NULL)
3634#ifndef XML_USE_BUFFER_CONTENT
3635 return(xmlStrdup(cur->content));
3636#else
3637 return(xmlStrdup(xmlBufferContent(cur->content)));
3638#endif
3639 return(NULL);
3640 case XML_ENTITY_REF_NODE:
3641 /*
3642 * Locate the entity, and get it's content
3643 * @@@
3644 */
3645 return(NULL);
3646 case XML_ENTITY_NODE:
3647 case XML_DOCUMENT_NODE:
3648 case XML_HTML_DOCUMENT_NODE:
3649 case XML_DOCUMENT_TYPE_NODE:
3650 case XML_NOTATION_NODE:
3651 case XML_DTD_NODE:
3652 case XML_XINCLUDE_START:
3653 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003654#ifdef LIBXML_DOCB_ENABLED
3655 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003656#endif
3657 return(NULL);
3658 case XML_NAMESPACE_DECL:
3659 return(xmlStrdup(((xmlNsPtr)cur)->href));
3660 case XML_ELEMENT_DECL:
3661 /* TODO !!! */
3662 return(NULL);
3663 case XML_ATTRIBUTE_DECL:
3664 /* TODO !!! */
3665 return(NULL);
3666 case XML_ENTITY_DECL:
3667 /* TODO !!! */
3668 return(NULL);
3669 case XML_CDATA_SECTION_NODE:
3670 case XML_TEXT_NODE:
3671 if (cur->content != NULL)
3672#ifndef XML_USE_BUFFER_CONTENT
3673 return(xmlStrdup(cur->content));
3674#else
3675 return(xmlStrdup(xmlBufferContent(cur->content)));
3676#endif
3677 return(NULL);
3678 }
3679 return(NULL);
3680}
3681
3682/**
3683 * xmlNodeSetContent:
3684 * @cur: the node being modified
3685 * @content: the new value of the content
3686 *
3687 * Replace the content of a node.
3688 */
3689void
3690xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3691 if (cur == NULL) {
3692#ifdef DEBUG_TREE
3693 xmlGenericError(xmlGenericErrorContext,
3694 "xmlNodeSetContent : node == NULL\n");
3695#endif
3696 return;
3697 }
3698 switch (cur->type) {
3699 case XML_DOCUMENT_FRAG_NODE:
3700 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003701 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3702 cur->children = xmlStringGetNodeList(cur->doc, content);
3703 UPDATE_LAST_CHILD_AND_PARENT(cur)
3704 break;
3705 case XML_ATTRIBUTE_NODE:
3706 break;
3707 case XML_TEXT_NODE:
3708 case XML_CDATA_SECTION_NODE:
3709 case XML_ENTITY_REF_NODE:
3710 case XML_ENTITY_NODE:
3711 case XML_PI_NODE:
3712 case XML_COMMENT_NODE:
3713 if (cur->content != NULL) {
3714#ifndef XML_USE_BUFFER_CONTENT
3715 xmlFree(cur->content);
3716#else
3717 xmlBufferFree(cur->content);
3718#endif
3719 }
3720 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3721 cur->last = cur->children = NULL;
3722 if (content != NULL) {
3723#ifndef XML_USE_BUFFER_CONTENT
3724 cur->content = xmlStrdup(content);
3725#else
3726 cur->content = xmlBufferCreateSize(0);
3727 xmlBufferSetAllocationScheme(cur->content,
3728 xmlGetBufferAllocationScheme());
3729 xmlBufferAdd(cur->content, content, -1);
3730#endif
3731 } else
3732 cur->content = NULL;
3733 break;
3734 case XML_DOCUMENT_NODE:
3735 case XML_HTML_DOCUMENT_NODE:
3736 case XML_DOCUMENT_TYPE_NODE:
3737 case XML_XINCLUDE_START:
3738 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003739#ifdef LIBXML_DOCB_ENABLED
3740 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003741#endif
3742 break;
3743 case XML_NOTATION_NODE:
3744 break;
3745 case XML_DTD_NODE:
3746 break;
3747 case XML_NAMESPACE_DECL:
3748 break;
3749 case XML_ELEMENT_DECL:
3750 /* TODO !!! */
3751 break;
3752 case XML_ATTRIBUTE_DECL:
3753 /* TODO !!! */
3754 break;
3755 case XML_ENTITY_DECL:
3756 /* TODO !!! */
3757 break;
3758 }
3759}
3760
3761/**
3762 * xmlNodeSetContentLen:
3763 * @cur: the node being modified
3764 * @content: the new value of the content
3765 * @len: the size of @content
3766 *
3767 * Replace the content of a node.
3768 */
3769void
3770xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3771 if (cur == NULL) {
3772#ifdef DEBUG_TREE
3773 xmlGenericError(xmlGenericErrorContext,
3774 "xmlNodeSetContentLen : node == NULL\n");
3775#endif
3776 return;
3777 }
3778 switch (cur->type) {
3779 case XML_DOCUMENT_FRAG_NODE:
3780 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003781 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3782 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3783 UPDATE_LAST_CHILD_AND_PARENT(cur)
3784 break;
3785 case XML_ATTRIBUTE_NODE:
3786 break;
3787 case XML_TEXT_NODE:
3788 case XML_CDATA_SECTION_NODE:
3789 case XML_ENTITY_REF_NODE:
3790 case XML_ENTITY_NODE:
3791 case XML_PI_NODE:
3792 case XML_COMMENT_NODE:
3793 case XML_NOTATION_NODE:
3794 if (cur->content != NULL) {
3795#ifndef XML_USE_BUFFER_CONTENT
3796 xmlFree(cur->content);
3797#else
3798 xmlBufferFree(cur->content);
3799#endif
3800 }
3801 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3802 cur->children = cur->last = NULL;
3803 if (content != NULL) {
3804#ifndef XML_USE_BUFFER_CONTENT
3805 cur->content = xmlStrndup(content, len);
3806#else
3807 cur->content = xmlBufferCreateSize(len);
3808 xmlBufferSetAllocationScheme(cur->content,
3809 xmlGetBufferAllocationScheme());
3810 xmlBufferAdd(cur->content, content, len);
3811#endif
3812 } else
3813 cur->content = NULL;
3814 break;
3815 case XML_DOCUMENT_NODE:
3816 case XML_DTD_NODE:
3817 case XML_HTML_DOCUMENT_NODE:
3818 case XML_DOCUMENT_TYPE_NODE:
3819 case XML_NAMESPACE_DECL:
3820 case XML_XINCLUDE_START:
3821 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003822#ifdef LIBXML_DOCB_ENABLED
3823 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003824#endif
3825 break;
3826 case XML_ELEMENT_DECL:
3827 /* TODO !!! */
3828 break;
3829 case XML_ATTRIBUTE_DECL:
3830 /* TODO !!! */
3831 break;
3832 case XML_ENTITY_DECL:
3833 /* TODO !!! */
3834 break;
3835 }
3836}
3837
3838/**
3839 * xmlNodeAddContentLen:
3840 * @cur: the node being modified
3841 * @content: extra content
3842 * @len: the size of @content
3843 *
3844 * Append the extra substring to the node content.
3845 */
3846void
3847xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3848 if (cur == NULL) {
3849#ifdef DEBUG_TREE
3850 xmlGenericError(xmlGenericErrorContext,
3851 "xmlNodeAddContentLen : node == NULL\n");
3852#endif
3853 return;
3854 }
3855 if (len <= 0) return;
3856 switch (cur->type) {
3857 case XML_DOCUMENT_FRAG_NODE:
3858 case XML_ELEMENT_NODE: {
Daniel Veillard7db37732001-07-12 01:20:08 +00003859 xmlNodePtr last, newNode;
Owen Taylor3473f882001-02-23 17:55:21 +00003860
Daniel Veillard7db37732001-07-12 01:20:08 +00003861 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003862 newNode = xmlNewTextLen(content, len);
3863 if (newNode != NULL) {
3864 xmlAddChild(cur, newNode);
3865 if ((last != NULL) && (last->next == newNode)) {
3866 xmlTextMerge(last, newNode);
3867 }
3868 }
3869 break;
3870 }
3871 case XML_ATTRIBUTE_NODE:
3872 break;
3873 case XML_TEXT_NODE:
3874 case XML_CDATA_SECTION_NODE:
3875 case XML_ENTITY_REF_NODE:
3876 case XML_ENTITY_NODE:
3877 case XML_PI_NODE:
3878 case XML_COMMENT_NODE:
3879 case XML_NOTATION_NODE:
3880 if (content != NULL) {
3881#ifndef XML_USE_BUFFER_CONTENT
3882 cur->content = xmlStrncat(cur->content, content, len);
3883#else
3884 xmlBufferAdd(cur->content, content, len);
3885#endif
3886 }
3887 case XML_DOCUMENT_NODE:
3888 case XML_DTD_NODE:
3889 case XML_HTML_DOCUMENT_NODE:
3890 case XML_DOCUMENT_TYPE_NODE:
3891 case XML_NAMESPACE_DECL:
3892 case XML_XINCLUDE_START:
3893 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003894#ifdef LIBXML_DOCB_ENABLED
3895 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003896#endif
3897 break;
3898 case XML_ELEMENT_DECL:
3899 case XML_ATTRIBUTE_DECL:
3900 case XML_ENTITY_DECL:
3901 break;
3902 }
3903}
3904
3905/**
3906 * xmlNodeAddContent:
3907 * @cur: the node being modified
3908 * @content: extra content
3909 *
3910 * Append the extra substring to the node content.
3911 */
3912void
3913xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3914 int len;
3915
3916 if (cur == NULL) {
3917#ifdef DEBUG_TREE
3918 xmlGenericError(xmlGenericErrorContext,
3919 "xmlNodeAddContent : node == NULL\n");
3920#endif
3921 return;
3922 }
3923 if (content == NULL) return;
3924 len = xmlStrlen(content);
3925 xmlNodeAddContentLen(cur, content, len);
3926}
3927
3928/**
3929 * xmlTextMerge:
3930 * @first: the first text node
3931 * @second: the second text node being merged
3932 *
3933 * Merge two text nodes into one
3934 * Returns the first text node augmented
3935 */
3936xmlNodePtr
3937xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3938 if (first == NULL) return(second);
3939 if (second == NULL) return(first);
3940 if (first->type != XML_TEXT_NODE) return(first);
3941 if (second->type != XML_TEXT_NODE) return(first);
3942 if (second->name != first->name)
3943 return(first);
3944#ifndef XML_USE_BUFFER_CONTENT
3945 xmlNodeAddContent(first, second->content);
3946#else
3947 xmlNodeAddContent(first, xmlBufferContent(second->content));
3948#endif
3949 xmlUnlinkNode(second);
3950 xmlFreeNode(second);
3951 return(first);
3952}
3953
3954/**
3955 * xmlGetNsList:
3956 * @doc: the document
3957 * @node: the current node
3958 *
3959 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00003960 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00003961 * that need to be freed by the caller or NULL if no
3962 * namespace if defined
3963 */
3964xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003965xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3966{
Owen Taylor3473f882001-02-23 17:55:21 +00003967 xmlNsPtr cur;
3968 xmlNsPtr *ret = NULL;
3969 int nbns = 0;
3970 int maxns = 10;
3971 int i;
3972
3973 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00003974 if (node->type == XML_ELEMENT_NODE) {
3975 cur = node->nsDef;
3976 while (cur != NULL) {
3977 if (ret == NULL) {
3978 ret =
3979 (xmlNsPtr *) xmlMalloc((maxns + 1) *
3980 sizeof(xmlNsPtr));
3981 if (ret == NULL) {
3982 xmlGenericError(xmlGenericErrorContext,
3983 "xmlGetNsList : out of memory!\n");
3984 return (NULL);
3985 }
3986 ret[nbns] = NULL;
3987 }
3988 for (i = 0; i < nbns; i++) {
3989 if ((cur->prefix == ret[i]->prefix) ||
3990 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
3991 break;
3992 }
3993 if (i >= nbns) {
3994 if (nbns >= maxns) {
3995 maxns *= 2;
3996 ret = (xmlNsPtr *) xmlRealloc(ret,
3997 (maxns +
3998 1) *
3999 sizeof(xmlNsPtr));
4000 if (ret == NULL) {
4001 xmlGenericError(xmlGenericErrorContext,
4002 "xmlGetNsList : realloc failed!\n");
4003 return (NULL);
4004 }
4005 }
4006 ret[nbns++] = cur;
4007 ret[nbns] = NULL;
4008 }
Owen Taylor3473f882001-02-23 17:55:21 +00004009
Daniel Veillard77044732001-06-29 21:31:07 +00004010 cur = cur->next;
4011 }
4012 }
4013 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004014 }
Daniel Veillard77044732001-06-29 21:31:07 +00004015 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004016}
4017
4018/**
4019 * xmlSearchNs:
4020 * @doc: the document
4021 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004022 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004023 *
4024 * Search a Ns registered under a given name space for a document.
4025 * recurse on the parents until it finds the defined namespace
4026 * or return NULL otherwise.
4027 * @nameSpace can be NULL, this is a search for the default namespace.
4028 * We don't allow to cross entities boundaries. If you don't declare
4029 * the namespace within those you will be in troubles !!! A warning
4030 * is generated to cover this case.
4031 *
4032 * Returns the namespace pointer or NULL.
4033 */
4034xmlNsPtr
4035xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4036 xmlNsPtr cur;
4037
4038 if (node == NULL) return(NULL);
4039 if ((nameSpace != NULL) &&
4040 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
4041 if (doc->oldNs == NULL) {
4042 /*
4043 * Allocate a new Namespace and fill the fields.
4044 */
4045 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4046 if (doc->oldNs == NULL) {
4047 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004048 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004049 return(NULL);
4050 }
4051 memset(doc->oldNs, 0, sizeof(xmlNs));
4052 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4053
4054 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4055 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4056 }
4057 return(doc->oldNs);
4058 }
4059 while (node != NULL) {
4060 if ((node->type == XML_ENTITY_REF_NODE) ||
4061 (node->type == XML_ENTITY_NODE) ||
4062 (node->type == XML_ENTITY_DECL))
4063 return(NULL);
4064 if (node->type == XML_ELEMENT_NODE) {
4065 cur = node->nsDef;
4066 while (cur != NULL) {
4067 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4068 (cur->href != NULL))
4069 return(cur);
4070 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4071 (cur->href != NULL) &&
4072 (xmlStrEqual(cur->prefix, nameSpace)))
4073 return(cur);
4074 cur = cur->next;
4075 }
4076 }
4077 node = node->parent;
4078 }
4079 return(NULL);
4080}
4081
4082/**
4083 * xmlSearchNsByHref:
4084 * @doc: the document
4085 * @node: the current node
4086 * @href: the namespace value
4087 *
4088 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4089 * the defined namespace or return NULL otherwise.
4090 * Returns the namespace pointer or NULL.
4091 */
4092xmlNsPtr
4093xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4094 xmlNsPtr cur;
4095 xmlNodePtr orig = node;
4096
4097 if ((node == NULL) || (href == NULL)) return(NULL);
4098 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
4099 if (doc->oldNs == NULL) {
4100 /*
4101 * Allocate a new Namespace and fill the fields.
4102 */
4103 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4104 if (doc->oldNs == NULL) {
4105 xmlGenericError(xmlGenericErrorContext,
4106 "xmlSearchNsByHref : malloc failed\n");
4107 return(NULL);
4108 }
4109 memset(doc->oldNs, 0, sizeof(xmlNs));
4110 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4111
4112 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4113 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4114 }
4115 return(doc->oldNs);
4116 }
4117 while (node != NULL) {
4118 cur = node->nsDef;
4119 while (cur != NULL) {
4120 if ((cur->href != NULL) && (href != NULL) &&
4121 (xmlStrEqual(cur->href, href))) {
4122 /*
4123 * Check that the prefix is not shadowed between orig and node
4124 */
4125 xmlNodePtr check = orig;
4126 xmlNsPtr tst;
4127
4128 while (check != node) {
4129 tst = check->nsDef;
4130 while (tst != NULL) {
4131 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4132 goto shadowed;
4133 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4134 (xmlStrEqual(tst->prefix, cur->prefix)))
4135 goto shadowed;
4136 tst = tst->next;
4137 }
4138 check = check->parent;
4139 }
4140 return(cur);
4141 }
4142shadowed:
4143 cur = cur->next;
4144 }
4145 node = node->parent;
4146 }
4147 return(NULL);
4148}
4149
4150/**
4151 * xmlNewReconciliedNs
4152 * @doc: the document
4153 * @tree: a node expected to hold the new namespace
4154 * @ns: the original namespace
4155 *
4156 * This function tries to locate a namespace definition in a tree
4157 * ancestors, or create a new namespace definition node similar to
4158 * @ns trying to reuse the same prefix. However if the given prefix is
4159 * null (default namespace) or reused within the subtree defined by
4160 * @tree or on one of its ancestors then a new prefix is generated.
4161 * Returns the (new) namespace definition or NULL in case of error
4162 */
4163xmlNsPtr
4164xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4165 xmlNsPtr def;
4166 xmlChar prefix[50];
4167 int counter = 1;
4168
4169 if (tree == NULL) {
4170#ifdef DEBUG_TREE
4171 xmlGenericError(xmlGenericErrorContext,
4172 "xmlNewReconciliedNs : tree == NULL\n");
4173#endif
4174 return(NULL);
4175 }
4176 if (ns == NULL) {
4177#ifdef DEBUG_TREE
4178 xmlGenericError(xmlGenericErrorContext,
4179 "xmlNewReconciliedNs : ns == NULL\n");
4180#endif
4181 return(NULL);
4182 }
4183 /*
4184 * Search an existing namespace definition inherited.
4185 */
4186 def = xmlSearchNsByHref(doc, tree, ns->href);
4187 if (def != NULL)
4188 return(def);
4189
4190 /*
4191 * Find a close prefix which is not already in use.
4192 * Let's strip namespace prefixes longer than 20 chars !
4193 */
4194 sprintf((char *) prefix, "%.20s", ns->prefix);
4195 def = xmlSearchNs(doc, tree, prefix);
4196 while (def != NULL) {
4197 if (counter > 1000) return(NULL);
4198 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4199 def = xmlSearchNs(doc, tree, prefix);
4200 }
4201
4202 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004203 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004204 */
4205 def = xmlNewNs(tree, ns->href, prefix);
4206 return(def);
4207}
4208
4209/**
4210 * xmlReconciliateNs
4211 * @doc: the document
4212 * @tree: a node defining the subtree to reconciliate
4213 *
4214 * This function checks that all the namespaces declared within the given
4215 * tree are properly declared. This is needed for example after Copy or Cut
4216 * and then paste operations. The subtree may still hold pointers to
4217 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004218 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004219 * the new environment. If not possible the new namespaces are redeclared
4220 * on @tree at the top of the given subtree.
4221 * Returns the number of namespace declarations created or -1 in case of error.
4222 */
4223int
4224xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4225 xmlNsPtr *oldNs = NULL;
4226 xmlNsPtr *newNs = NULL;
4227 int sizeCache = 0;
4228 int nbCache = 0;
4229
4230 xmlNsPtr n;
4231 xmlNodePtr node = tree;
4232 xmlAttrPtr attr;
4233 int ret = 0, i;
4234
4235 while (node != NULL) {
4236 /*
4237 * Reconciliate the node namespace
4238 */
4239 if (node->ns != NULL) {
4240 /*
4241 * initialize the cache if needed
4242 */
4243 if (sizeCache == 0) {
4244 sizeCache = 10;
4245 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4246 sizeof(xmlNsPtr));
4247 if (oldNs == NULL) {
4248 xmlGenericError(xmlGenericErrorContext,
4249 "xmlReconciliateNs : memory pbm\n");
4250 return(-1);
4251 }
4252 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4253 sizeof(xmlNsPtr));
4254 if (newNs == NULL) {
4255 xmlGenericError(xmlGenericErrorContext,
4256 "xmlReconciliateNs : memory pbm\n");
4257 xmlFree(oldNs);
4258 return(-1);
4259 }
4260 }
4261 for (i = 0;i < nbCache;i++) {
4262 if (oldNs[i] == node->ns) {
4263 node->ns = newNs[i];
4264 break;
4265 }
4266 }
4267 if (i == nbCache) {
4268 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004269 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004270 */
4271 n = xmlNewReconciliedNs(doc, tree, node->ns);
4272 if (n != NULL) { /* :-( what if else ??? */
4273 /*
4274 * check if we need to grow the cache buffers.
4275 */
4276 if (sizeCache <= nbCache) {
4277 sizeCache *= 2;
4278 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4279 sizeof(xmlNsPtr));
4280 if (oldNs == NULL) {
4281 xmlGenericError(xmlGenericErrorContext,
4282 "xmlReconciliateNs : memory pbm\n");
4283 xmlFree(newNs);
4284 return(-1);
4285 }
4286 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4287 sizeof(xmlNsPtr));
4288 if (newNs == NULL) {
4289 xmlGenericError(xmlGenericErrorContext,
4290 "xmlReconciliateNs : memory pbm\n");
4291 xmlFree(oldNs);
4292 return(-1);
4293 }
4294 }
4295 newNs[nbCache] = n;
4296 oldNs[nbCache++] = node->ns;
4297 node->ns = n;
4298 }
4299 }
4300 }
4301 /*
4302 * now check for namespace hold by attributes on the node.
4303 */
4304 attr = node->properties;
4305 while (attr != NULL) {
4306 if (attr->ns != NULL) {
4307 /*
4308 * initialize the cache if needed
4309 */
4310 if (sizeCache == 0) {
4311 sizeCache = 10;
4312 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4313 sizeof(xmlNsPtr));
4314 if (oldNs == NULL) {
4315 xmlGenericError(xmlGenericErrorContext,
4316 "xmlReconciliateNs : memory pbm\n");
4317 return(-1);
4318 }
4319 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4320 sizeof(xmlNsPtr));
4321 if (newNs == NULL) {
4322 xmlGenericError(xmlGenericErrorContext,
4323 "xmlReconciliateNs : memory pbm\n");
4324 xmlFree(oldNs);
4325 return(-1);
4326 }
4327 }
4328 for (i = 0;i < nbCache;i++) {
4329 if (oldNs[i] == attr->ns) {
4330 node->ns = newNs[i];
4331 break;
4332 }
4333 }
4334 if (i == nbCache) {
4335 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004336 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004337 */
4338 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4339 if (n != NULL) { /* :-( what if else ??? */
4340 /*
4341 * check if we need to grow the cache buffers.
4342 */
4343 if (sizeCache <= nbCache) {
4344 sizeCache *= 2;
4345 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4346 sizeof(xmlNsPtr));
4347 if (oldNs == NULL) {
4348 xmlGenericError(xmlGenericErrorContext,
4349 "xmlReconciliateNs : memory pbm\n");
4350 xmlFree(newNs);
4351 return(-1);
4352 }
4353 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4354 sizeof(xmlNsPtr));
4355 if (newNs == NULL) {
4356 xmlGenericError(xmlGenericErrorContext,
4357 "xmlReconciliateNs : memory pbm\n");
4358 xmlFree(oldNs);
4359 return(-1);
4360 }
4361 }
4362 newNs[nbCache] = n;
4363 oldNs[nbCache++] = attr->ns;
4364 attr->ns = n;
4365 }
4366 }
4367 }
4368 attr = attr->next;
4369 }
4370
4371 /*
4372 * Browse the full subtree, deep first
4373 */
4374 if (node->children != NULL) {
4375 /* deep first */
4376 node = node->children;
4377 } else if ((node != tree) && (node->next != NULL)) {
4378 /* then siblings */
4379 node = node->next;
4380 } else if (node != tree) {
4381 /* go up to parents->next if needed */
4382 while (node != tree) {
4383 if (node->parent != NULL)
4384 node = node->parent;
4385 if ((node != tree) && (node->next != NULL)) {
4386 node = node->next;
4387 break;
4388 }
4389 if (node->parent == NULL) {
4390 node = NULL;
4391 break;
4392 }
4393 }
4394 /* exit condition */
4395 if (node == tree)
4396 node = NULL;
4397 }
4398 }
4399 return(ret);
4400}
4401
4402/**
4403 * xmlHasProp:
4404 * @node: the node
4405 * @name: the attribute name
4406 *
4407 * Search an attribute associated to a node
4408 * This function also looks in DTD attribute declaration for #FIXED or
4409 * default declaration values unless DTD use has been turned off.
4410 *
4411 * Returns the attribute or the attribute declaration or NULL if
4412 * neither was found.
4413 */
4414xmlAttrPtr
4415xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4416 xmlAttrPtr prop;
4417 xmlDocPtr doc;
4418
4419 if ((node == NULL) || (name == NULL)) return(NULL);
4420 /*
4421 * Check on the properties attached to the node
4422 */
4423 prop = node->properties;
4424 while (prop != NULL) {
4425 if (xmlStrEqual(prop->name, name)) {
4426 return(prop);
4427 }
4428 prop = prop->next;
4429 }
4430 if (!xmlCheckDTD) return(NULL);
4431
4432 /*
4433 * Check if there is a default declaration in the internal
4434 * or external subsets
4435 */
4436 doc = node->doc;
4437 if (doc != NULL) {
4438 xmlAttributePtr attrDecl;
4439 if (doc->intSubset != NULL) {
4440 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4441 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4442 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4443 if (attrDecl != NULL)
4444 return((xmlAttrPtr) attrDecl);
4445 }
4446 }
4447 return(NULL);
4448}
4449
4450/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004451 * xmlHasNsProp:
4452 * @node: the node
4453 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004454 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004455 *
4456 * Search for an attribute associated to a node
4457 * This attribute has to be anchored in the namespace specified.
4458 * This does the entity substitution.
4459 * This function looks in DTD attribute declaration for #FIXED or
4460 * default declaration values unless DTD use has been turned off.
4461 *
4462 * Returns the attribute or the attribute declaration or NULL
4463 * if neither was found.
4464 */
4465xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004466xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004467 xmlAttrPtr prop;
4468 xmlDocPtr doc;
4469 xmlNsPtr ns;
4470
4471 if (node == NULL)
4472 return(NULL);
4473
4474 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004475 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004476 return(xmlHasProp(node, name));
4477 while (prop != NULL) {
4478 /*
4479 * One need to have
4480 * - same attribute names
4481 * - and the attribute carrying that namespace
4482 * or
4483 * no namespace on the attribute and the element carrying it
4484 */
4485 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004486 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4487 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004488 }
4489 prop = prop->next;
4490 }
4491 if (!xmlCheckDTD) return(NULL);
4492
4493 /*
4494 * Check if there is a default declaration in the internal
4495 * or external subsets
4496 */
4497 doc = node->doc;
4498 if (doc != NULL) {
4499 if (doc->intSubset != NULL) {
4500 xmlAttributePtr attrDecl;
4501
4502 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4503 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4504 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4505
4506 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4507 /*
4508 * The DTD declaration only allows a prefix search
4509 */
4510 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004511 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004512 return((xmlAttrPtr) attrDecl);
4513 }
4514 }
4515 }
4516 return(NULL);
4517}
4518
4519/**
Owen Taylor3473f882001-02-23 17:55:21 +00004520 * xmlGetProp:
4521 * @node: the node
4522 * @name: the attribute name
4523 *
4524 * Search and get the value of an attribute associated to a node
4525 * This does the entity substitution.
4526 * This function looks in DTD attribute declaration for #FIXED or
4527 * default declaration values unless DTD use has been turned off.
4528 *
4529 * Returns the attribute value or NULL if not found.
4530 * It's up to the caller to free the memory.
4531 */
4532xmlChar *
4533xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4534 xmlAttrPtr prop;
4535 xmlDocPtr doc;
4536
4537 if ((node == NULL) || (name == NULL)) return(NULL);
4538 /*
4539 * Check on the properties attached to the node
4540 */
4541 prop = node->properties;
4542 while (prop != NULL) {
4543 if (xmlStrEqual(prop->name, name)) {
4544 xmlChar *ret;
4545
4546 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4547 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4548 return(ret);
4549 }
4550 prop = prop->next;
4551 }
4552 if (!xmlCheckDTD) return(NULL);
4553
4554 /*
4555 * Check if there is a default declaration in the internal
4556 * or external subsets
4557 */
4558 doc = node->doc;
4559 if (doc != NULL) {
4560 xmlAttributePtr attrDecl;
4561 if (doc->intSubset != NULL) {
4562 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4563 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4564 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4565 if (attrDecl != NULL)
4566 return(xmlStrdup(attrDecl->defaultValue));
4567 }
4568 }
4569 return(NULL);
4570}
4571
4572/**
4573 * xmlGetNsProp:
4574 * @node: the node
4575 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004576 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004577 *
4578 * Search and get the value of an attribute associated to a node
4579 * This attribute has to be anchored in the namespace specified.
4580 * This does the entity substitution.
4581 * This function looks in DTD attribute declaration for #FIXED or
4582 * default declaration values unless DTD use has been turned off.
4583 *
4584 * Returns the attribute value or NULL if not found.
4585 * It's up to the caller to free the memory.
4586 */
4587xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004588xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004589 xmlAttrPtr prop;
4590 xmlDocPtr doc;
4591 xmlNsPtr ns;
4592
4593 if (node == NULL)
4594 return(NULL);
4595
4596 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004597 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004598 return(xmlGetProp(node, name));
4599 while (prop != NULL) {
4600 /*
4601 * One need to have
4602 * - same attribute names
4603 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004604 */
4605 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004606 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004607 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004608 xmlChar *ret;
4609
4610 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4611 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4612 return(ret);
4613 }
4614 prop = prop->next;
4615 }
4616 if (!xmlCheckDTD) return(NULL);
4617
4618 /*
4619 * Check if there is a default declaration in the internal
4620 * or external subsets
4621 */
4622 doc = node->doc;
4623 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004624 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004625 xmlAttributePtr attrDecl;
4626
Owen Taylor3473f882001-02-23 17:55:21 +00004627 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4628 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4629 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4630
4631 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4632 /*
4633 * The DTD declaration only allows a prefix search
4634 */
4635 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004636 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004637 return(xmlStrdup(attrDecl->defaultValue));
4638 }
4639 }
4640 }
4641 return(NULL);
4642}
4643
4644/**
4645 * xmlSetProp:
4646 * @node: the node
4647 * @name: the attribute name
4648 * @value: the attribute value
4649 *
4650 * Set (or reset) an attribute carried by a node.
4651 * Returns the attribute pointer.
4652 */
4653xmlAttrPtr
4654xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004655 xmlAttrPtr prop;
4656 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004657
4658 if ((node == NULL) || (name == NULL))
4659 return(NULL);
4660 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004661 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004662 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004663 if ((xmlStrEqual(prop->name, name)) &&
4664 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004665 xmlNodePtr oldprop = prop->children;
4666
Owen Taylor3473f882001-02-23 17:55:21 +00004667 prop->children = NULL;
4668 prop->last = NULL;
4669 if (value != NULL) {
4670 xmlChar *buffer;
4671 xmlNodePtr tmp;
4672
4673 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4674 prop->children = xmlStringGetNodeList(node->doc, buffer);
4675 prop->last = NULL;
4676 prop->doc = doc;
4677 tmp = prop->children;
4678 while (tmp != NULL) {
4679 tmp->parent = (xmlNodePtr) prop;
4680 tmp->doc = doc;
4681 if (tmp->next == NULL)
4682 prop->last = tmp;
4683 tmp = tmp->next;
4684 }
4685 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004686 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004687 if (oldprop != NULL)
4688 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004689 return(prop);
4690 }
4691 prop = prop->next;
4692 }
4693 prop = xmlNewProp(node, name, value);
4694 return(prop);
4695}
4696
4697/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004698 * xmlUnsetProp:
4699 * @node: the node
4700 * @name: the attribute name
4701 *
4702 * Remove an attribute carried by a node.
4703 * Returns 0 if successful, -1 if not found
4704 */
4705int
4706xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4707 xmlAttrPtr prop = node->properties, prev = NULL;;
4708
4709 if ((node == NULL) || (name == NULL))
4710 return(-1);
4711 while (prop != NULL) {
4712 if ((xmlStrEqual(prop->name, name)) &&
4713 (prop->ns == NULL)) {
4714 if (prev == NULL)
4715 node->properties = prop->next;
4716 else
4717 prev->next = prop->next;
4718 xmlFreeProp(prop);
4719 return(0);
4720 }
4721 prev = prop;
4722 prop = prop->next;
4723 }
4724 return(-1);
4725}
4726
4727/**
Owen Taylor3473f882001-02-23 17:55:21 +00004728 * xmlSetNsProp:
4729 * @node: the node
4730 * @ns: the namespace definition
4731 * @name: the attribute name
4732 * @value: the attribute value
4733 *
4734 * Set (or reset) an attribute carried by a node.
4735 * The ns structure must be in scope, this is not checked.
4736 *
4737 * Returns the attribute pointer.
4738 */
4739xmlAttrPtr
4740xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4741 const xmlChar *value) {
4742 xmlAttrPtr prop;
4743
4744 if ((node == NULL) || (name == NULL))
4745 return(NULL);
4746
4747 if (ns == NULL)
4748 return(xmlSetProp(node, name, value));
4749 if (ns->href == NULL)
4750 return(NULL);
4751 prop = node->properties;
4752
4753 while (prop != NULL) {
4754 /*
4755 * One need to have
4756 * - same attribute names
4757 * - and the attribute carrying that namespace
4758 * or
4759 * no namespace on the attribute and the element carrying it
4760 */
4761 if ((xmlStrEqual(prop->name, name)) &&
4762 (((prop->ns == NULL) && (node->ns != NULL) &&
4763 (xmlStrEqual(node->ns->href, ns->href))) ||
4764 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4765 if (prop->children != NULL)
4766 xmlFreeNodeList(prop->children);
4767 prop->children = NULL;
4768 prop->last = NULL;
4769 prop->ns = ns;
4770 if (value != NULL) {
4771 xmlChar *buffer;
4772 xmlNodePtr tmp;
4773
4774 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4775 prop->children = xmlStringGetNodeList(node->doc, buffer);
4776 prop->last = NULL;
4777 tmp = prop->children;
4778 while (tmp != NULL) {
4779 tmp->parent = (xmlNodePtr) prop;
4780 if (tmp->next == NULL)
4781 prop->last = tmp;
4782 tmp = tmp->next;
4783 }
4784 xmlFree(buffer);
4785 }
4786 return(prop);
4787 }
4788 prop = prop->next;
4789 }
4790 prop = xmlNewNsProp(node, ns, name, value);
4791 return(prop);
4792}
4793
4794/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004795 * xmlUnsetNsProp:
4796 * @node: the node
4797 * @ns: the namespace definition
4798 * @name: the attribute name
4799 *
4800 * Remove an attribute carried by a node.
4801 * Returns 0 if successful, -1 if not found
4802 */
4803int
4804xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4805 xmlAttrPtr prop = node->properties, prev = NULL;;
4806
4807 if ((node == NULL) || (name == NULL))
4808 return(-1);
4809 if (ns == NULL)
4810 return(xmlUnsetProp(node, name));
4811 if (ns->href == NULL)
4812 return(-1);
4813 while (prop != NULL) {
4814 if ((xmlStrEqual(prop->name, name)) &&
4815 (((prop->ns == NULL) && (node->ns != NULL) &&
4816 (xmlStrEqual(node->ns->href, ns->href))) ||
4817 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4818 if (prev == NULL)
4819 node->properties = prop->next;
4820 else
4821 prev->next = prop->next;
4822 xmlFreeProp(prop);
4823 return(0);
4824 }
4825 prev = prop;
4826 prop = prop->next;
4827 }
4828 return(-1);
4829}
4830
4831/**
Owen Taylor3473f882001-02-23 17:55:21 +00004832 * xmlNodeIsText:
4833 * @node: the node
4834 *
4835 * Is this node a Text node ?
4836 * Returns 1 yes, 0 no
4837 */
4838int
4839xmlNodeIsText(xmlNodePtr node) {
4840 if (node == NULL) return(0);
4841
4842 if (node->type == XML_TEXT_NODE) return(1);
4843 return(0);
4844}
4845
4846/**
4847 * xmlIsBlankNode:
4848 * @node: the node
4849 *
4850 * Checks whether this node is an empty or whitespace only
4851 * (and possibly ignorable) text-node.
4852 *
4853 * Returns 1 yes, 0 no
4854 */
4855int
4856xmlIsBlankNode(xmlNodePtr node) {
4857 const xmlChar *cur;
4858 if (node == NULL) return(0);
4859
Daniel Veillard7db37732001-07-12 01:20:08 +00004860 if ((node->type != XML_TEXT_NODE) &&
4861 (node->type != XML_CDATA_SECTION_NODE))
4862 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004863 if (node->content == NULL) return(1);
4864#ifndef XML_USE_BUFFER_CONTENT
4865 cur = node->content;
4866#else
4867 cur = xmlBufferContent(node->content);
4868#endif
4869 while (*cur != 0) {
4870 if (!IS_BLANK(*cur)) return(0);
4871 cur++;
4872 }
4873
4874 return(1);
4875}
4876
4877/**
4878 * xmlTextConcat:
4879 * @node: the node
4880 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00004881 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00004882 *
4883 * Concat the given string at the end of the existing node content
4884 */
4885
4886void
4887xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4888 if (node == NULL) return;
4889
4890 if ((node->type != XML_TEXT_NODE) &&
4891 (node->type != XML_CDATA_SECTION_NODE)) {
4892#ifdef DEBUG_TREE
4893 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004894 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004895#endif
4896 return;
4897 }
4898#ifndef XML_USE_BUFFER_CONTENT
4899 node->content = xmlStrncat(node->content, content, len);
4900#else
4901 xmlBufferAdd(node->content, content, len);
4902#endif
4903}
4904
4905/************************************************************************
4906 * *
4907 * Output : to a FILE or in memory *
4908 * *
4909 ************************************************************************/
4910
Owen Taylor3473f882001-02-23 17:55:21 +00004911/**
4912 * xmlBufferCreate:
4913 *
4914 * routine to create an XML buffer.
4915 * returns the new structure.
4916 */
4917xmlBufferPtr
4918xmlBufferCreate(void) {
4919 xmlBufferPtr ret;
4920
4921 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4922 if (ret == NULL) {
4923 xmlGenericError(xmlGenericErrorContext,
4924 "xmlBufferCreate : out of memory!\n");
4925 return(NULL);
4926 }
4927 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004928 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004929 ret->alloc = xmlBufferAllocScheme;
4930 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4931 if (ret->content == NULL) {
4932 xmlGenericError(xmlGenericErrorContext,
4933 "xmlBufferCreate : out of memory!\n");
4934 xmlFree(ret);
4935 return(NULL);
4936 }
4937 ret->content[0] = 0;
4938 return(ret);
4939}
4940
4941/**
4942 * xmlBufferCreateSize:
4943 * @size: initial size of buffer
4944 *
4945 * routine to create an XML buffer.
4946 * returns the new structure.
4947 */
4948xmlBufferPtr
4949xmlBufferCreateSize(size_t size) {
4950 xmlBufferPtr ret;
4951
4952 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4953 if (ret == NULL) {
4954 xmlGenericError(xmlGenericErrorContext,
4955 "xmlBufferCreate : out of memory!\n");
4956 return(NULL);
4957 }
4958 ret->use = 0;
4959 ret->alloc = xmlBufferAllocScheme;
4960 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4961 if (ret->size){
4962 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4963 if (ret->content == NULL) {
4964 xmlGenericError(xmlGenericErrorContext,
4965 "xmlBufferCreate : out of memory!\n");
4966 xmlFree(ret);
4967 return(NULL);
4968 }
4969 ret->content[0] = 0;
4970 } else
4971 ret->content = NULL;
4972 return(ret);
4973}
4974
4975/**
4976 * xmlBufferSetAllocationScheme:
4977 * @buf: the buffer to free
4978 * @scheme: allocation scheme to use
4979 *
4980 * Sets the allocation scheme for this buffer
4981 */
4982void
4983xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4984 xmlBufferAllocationScheme scheme) {
4985 if (buf == NULL) {
4986#ifdef DEBUG_BUFFER
4987 xmlGenericError(xmlGenericErrorContext,
4988 "xmlBufferSetAllocationScheme: buf == NULL\n");
4989#endif
4990 return;
4991 }
4992
4993 buf->alloc = scheme;
4994}
4995
4996/**
4997 * xmlBufferFree:
4998 * @buf: the buffer to free
4999 *
5000 * Frees an XML buffer.
5001 */
5002void
5003xmlBufferFree(xmlBufferPtr buf) {
5004 if (buf == NULL) {
5005#ifdef DEBUG_BUFFER
5006 xmlGenericError(xmlGenericErrorContext,
5007 "xmlBufferFree: buf == NULL\n");
5008#endif
5009 return;
5010 }
5011 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005012 xmlFree(buf->content);
5013 }
Owen Taylor3473f882001-02-23 17:55:21 +00005014 xmlFree(buf);
5015}
5016
5017/**
5018 * xmlBufferEmpty:
5019 * @buf: the buffer
5020 *
5021 * empty a buffer.
5022 */
5023void
5024xmlBufferEmpty(xmlBufferPtr buf) {
5025 if (buf->content == NULL) return;
5026 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005027 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005028}
5029
5030/**
5031 * xmlBufferShrink:
5032 * @buf: the buffer to dump
5033 * @len: the number of xmlChar to remove
5034 *
5035 * Remove the beginning of an XML buffer.
5036 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005037 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005038 */
5039int
5040xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5041 if (len == 0) return(0);
5042 if (len > buf->use) return(-1);
5043
5044 buf->use -= len;
5045 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5046
5047 buf->content[buf->use] = 0;
5048 return(len);
5049}
5050
5051/**
5052 * xmlBufferGrow:
5053 * @buf: the buffer
5054 * @len: the minimum free size to allocate
5055 *
5056 * Grow the available space of an XML buffer.
5057 *
5058 * Returns the new available space or -1 in case of error
5059 */
5060int
5061xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5062 int size;
5063 xmlChar *newbuf;
5064
5065 if (len + buf->use < buf->size) return(0);
5066
5067 size = buf->use + len + 100;
5068
5069 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5070 if (newbuf == NULL) return(-1);
5071 buf->content = newbuf;
5072 buf->size = size;
5073 return(buf->size - buf->use);
5074}
5075
5076/**
5077 * xmlBufferDump:
5078 * @file: the file output
5079 * @buf: the buffer to dump
5080 *
5081 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005082 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005083 */
5084int
5085xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5086 int ret;
5087
5088 if (buf == NULL) {
5089#ifdef DEBUG_BUFFER
5090 xmlGenericError(xmlGenericErrorContext,
5091 "xmlBufferDump: buf == NULL\n");
5092#endif
5093 return(0);
5094 }
5095 if (buf->content == NULL) {
5096#ifdef DEBUG_BUFFER
5097 xmlGenericError(xmlGenericErrorContext,
5098 "xmlBufferDump: buf->content == NULL\n");
5099#endif
5100 return(0);
5101 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005102 if (file == NULL)
5103 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005104 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5105 return(ret);
5106}
5107
5108/**
5109 * xmlBufferContent:
5110 * @buf: the buffer
5111 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005112 * Function to extract the content of a buffer
5113 *
Owen Taylor3473f882001-02-23 17:55:21 +00005114 * Returns the internal content
5115 */
5116
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005117const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005118xmlBufferContent(const xmlBufferPtr buf)
5119{
5120 if(!buf)
5121 return NULL;
5122
5123 return buf->content;
5124}
5125
5126/**
5127 * xmlBufferLength:
5128 * @buf: the buffer
5129 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005130 * Function to get the length of a buffer
5131 *
Owen Taylor3473f882001-02-23 17:55:21 +00005132 * Returns the length of data in the internal content
5133 */
5134
5135int
5136xmlBufferLength(const xmlBufferPtr buf)
5137{
5138 if(!buf)
5139 return 0;
5140
5141 return buf->use;
5142}
5143
5144/**
5145 * xmlBufferResize:
5146 * @buf: the buffer to resize
5147 * @size: the desired size
5148 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005149 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005150 *
5151 * Returns 0 in case of problems, 1 otherwise
5152 */
5153int
5154xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5155{
5156 unsigned int newSize;
5157 xmlChar* rebuf = NULL;
5158
5159 /*take care of empty case*/
5160 newSize = (buf->size ? buf->size*2 : size);
5161
5162 /* Don't resize if we don't have to */
5163 if (size < buf->size)
5164 return 1;
5165
5166 /* figure out new size */
5167 switch (buf->alloc){
5168 case XML_BUFFER_ALLOC_DOUBLEIT:
5169 while (size > newSize) newSize *= 2;
5170 break;
5171 case XML_BUFFER_ALLOC_EXACT:
5172 newSize = size+10;
5173 break;
5174 default:
5175 newSize = size+10;
5176 break;
5177 }
5178
5179 if (buf->content == NULL)
5180 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5181 else
5182 rebuf = (xmlChar *) xmlRealloc(buf->content,
5183 newSize * sizeof(xmlChar));
5184 if (rebuf == NULL) {
5185 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005186 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005187 return 0;
5188 }
5189 buf->content = rebuf;
5190 buf->size = newSize;
5191
5192 return 1;
5193}
5194
5195/**
5196 * xmlBufferAdd:
5197 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005198 * @str: the #xmlChar string
5199 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005200 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005201 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005202 * str is recomputed.
5203 */
5204void
5205xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5206 unsigned int needSize;
5207
5208 if (str == NULL) {
5209#ifdef DEBUG_BUFFER
5210 xmlGenericError(xmlGenericErrorContext,
5211 "xmlBufferAdd: str == NULL\n");
5212#endif
5213 return;
5214 }
5215 if (len < -1) {
5216#ifdef DEBUG_BUFFER
5217 xmlGenericError(xmlGenericErrorContext,
5218 "xmlBufferAdd: len < 0\n");
5219#endif
5220 return;
5221 }
5222 if (len == 0) return;
5223
5224 if (len < 0)
5225 len = xmlStrlen(str);
5226
5227 if (len <= 0) return;
5228
5229 needSize = buf->use + len + 2;
5230 if (needSize > buf->size){
5231 if (!xmlBufferResize(buf, needSize)){
5232 xmlGenericError(xmlGenericErrorContext,
5233 "xmlBufferAdd : out of memory!\n");
5234 return;
5235 }
5236 }
5237
5238 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5239 buf->use += len;
5240 buf->content[buf->use] = 0;
5241}
5242
5243/**
5244 * xmlBufferAddHead:
5245 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005246 * @str: the #xmlChar string
5247 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005248 *
5249 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005250 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005251 */
5252void
5253xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5254 unsigned int needSize;
5255
5256 if (str == NULL) {
5257#ifdef DEBUG_BUFFER
5258 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005259 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005260#endif
5261 return;
5262 }
5263 if (len < -1) {
5264#ifdef DEBUG_BUFFER
5265 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005266 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005267#endif
5268 return;
5269 }
5270 if (len == 0) return;
5271
5272 if (len < 0)
5273 len = xmlStrlen(str);
5274
5275 if (len <= 0) return;
5276
5277 needSize = buf->use + len + 2;
5278 if (needSize > buf->size){
5279 if (!xmlBufferResize(buf, needSize)){
5280 xmlGenericError(xmlGenericErrorContext,
5281 "xmlBufferAddHead : out of memory!\n");
5282 return;
5283 }
5284 }
5285
5286 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5287 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5288 buf->use += len;
5289 buf->content[buf->use] = 0;
5290}
5291
5292/**
5293 * xmlBufferCat:
5294 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005295 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005296 *
5297 * Append a zero terminated string to an XML buffer.
5298 */
5299void
5300xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5301 if (str != NULL)
5302 xmlBufferAdd(buf, str, -1);
5303}
5304
5305/**
5306 * xmlBufferCCat:
5307 * @buf: the buffer to dump
5308 * @str: the C char string
5309 *
5310 * Append a zero terminated C string to an XML buffer.
5311 */
5312void
5313xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5314 const char *cur;
5315
5316 if (str == NULL) {
5317#ifdef DEBUG_BUFFER
5318 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005319 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005320#endif
5321 return;
5322 }
5323 for (cur = str;*cur != 0;cur++) {
5324 if (buf->use + 10 >= buf->size) {
5325 if (!xmlBufferResize(buf, buf->use+10)){
5326 xmlGenericError(xmlGenericErrorContext,
5327 "xmlBufferCCat : out of memory!\n");
5328 return;
5329 }
5330 }
5331 buf->content[buf->use++] = *cur;
5332 }
5333 buf->content[buf->use] = 0;
5334}
5335
5336/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005337 * xmlBufferWriteXmlCHAR:
5338 * @buf: the XML buffer
5339 * @string: the string to add
5340 *
5341 * For VMS only.
5342 * routine which manages and grows an output buffer. This one adds
5343 * xmlChars at the end of the buffer.
5344 */
5345/**
Owen Taylor3473f882001-02-23 17:55:21 +00005346 * xmlBufferWriteCHAR:
5347 * @buf: the XML buffer
5348 * @string: the string to add
5349 *
5350 * routine which manages and grows an output buffer. This one adds
5351 * xmlChars at the end of the buffer.
5352 */
5353void
5354#ifdef VMS
5355xmlBufferWriteXmlCHAR
5356#else
5357xmlBufferWriteCHAR
5358#endif
5359(xmlBufferPtr buf, const xmlChar *string) {
5360 xmlBufferCat(buf, string);
5361}
5362
5363/**
5364 * xmlBufferWriteChar:
5365 * @buf: the XML buffer output
5366 * @string: the string to add
5367 *
5368 * routine which manage and grows an output buffer. This one add
5369 * C chars at the end of the array.
5370 */
5371void
5372xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5373 xmlBufferCCat(buf, string);
5374}
5375
5376
5377/**
5378 * xmlBufferWriteQuotedString:
5379 * @buf: the XML buffer output
5380 * @string: the string to add
5381 *
5382 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005383 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005384 * quote or double-quotes internally
5385 */
5386void
5387xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5388 if (xmlStrchr(string, '"')) {
5389 if (xmlStrchr(string, '\'')) {
5390#ifdef DEBUG_BUFFER
5391 xmlGenericError(xmlGenericErrorContext,
5392 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5393#endif
5394 }
5395 xmlBufferCCat(buf, "'");
5396 xmlBufferCat(buf, string);
5397 xmlBufferCCat(buf, "'");
5398 } else {
5399 xmlBufferCCat(buf, "\"");
5400 xmlBufferCat(buf, string);
5401 xmlBufferCCat(buf, "\"");
5402 }
5403}
5404
5405
5406/************************************************************************
5407 * *
5408 * Dumping XML tree content to a simple buffer *
5409 * *
5410 ************************************************************************/
5411
5412void
5413xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5414 int format);
5415static void
5416xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5417 int format);
5418void
5419htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5420
5421/**
5422 * xmlNsDump:
5423 * @buf: the XML buffer output
5424 * @cur: a namespace
5425 *
5426 * Dump a local Namespace definition.
5427 * Should be called in the context of attributes dumps.
5428 */
5429static void
5430xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5431 if (cur == NULL) {
5432#ifdef DEBUG_TREE
5433 xmlGenericError(xmlGenericErrorContext,
5434 "xmlNsDump : Ns == NULL\n");
5435#endif
5436 return;
5437 }
5438 if (cur->type == XML_LOCAL_NAMESPACE) {
5439 /* Within the context of an element attributes */
5440 if (cur->prefix != NULL) {
5441 xmlBufferWriteChar(buf, " xmlns:");
5442 xmlBufferWriteCHAR(buf, cur->prefix);
5443 } else
5444 xmlBufferWriteChar(buf, " xmlns");
5445 xmlBufferWriteChar(buf, "=");
5446 xmlBufferWriteQuotedString(buf, cur->href);
5447 }
5448}
5449
5450/**
5451 * xmlNsListDump:
5452 * @buf: the XML buffer output
5453 * @cur: the first namespace
5454 *
5455 * Dump a list of local Namespace definitions.
5456 * Should be called in the context of attributes dumps.
5457 */
5458static void
5459xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5460 while (cur != NULL) {
5461 xmlNsDump(buf, cur);
5462 cur = cur->next;
5463 }
5464}
5465
5466/**
5467 * xmlDtdDump:
5468 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005469 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005470 *
5471 * Dump the XML document DTD, if any.
5472 */
5473static void
5474xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5475 if (dtd == NULL) {
5476#ifdef DEBUG_TREE
5477 xmlGenericError(xmlGenericErrorContext,
5478 "xmlDtdDump : no internal subset\n");
5479#endif
5480 return;
5481 }
5482 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5483 xmlBufferWriteCHAR(buf, dtd->name);
5484 if (dtd->ExternalID != NULL) {
5485 xmlBufferWriteChar(buf, " PUBLIC ");
5486 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5487 xmlBufferWriteChar(buf, " ");
5488 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5489 } else if (dtd->SystemID != NULL) {
5490 xmlBufferWriteChar(buf, " SYSTEM ");
5491 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5492 }
5493 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5494 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5495 xmlBufferWriteChar(buf, ">");
5496 return;
5497 }
5498 xmlBufferWriteChar(buf, " [\n");
5499 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5500#if 0
5501 if (dtd->entities != NULL)
5502 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5503 if (dtd->notations != NULL)
5504 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5505 if (dtd->elements != NULL)
5506 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5507 if (dtd->attributes != NULL)
5508 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5509#endif
5510 xmlBufferWriteChar(buf, "]>");
5511}
5512
5513/**
5514 * xmlAttrDump:
5515 * @buf: the XML buffer output
5516 * @doc: the document
5517 * @cur: the attribute pointer
5518 *
5519 * Dump an XML attribute
5520 */
5521static void
5522xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5523 xmlChar *value;
5524
5525 if (cur == NULL) {
5526#ifdef DEBUG_TREE
5527 xmlGenericError(xmlGenericErrorContext,
5528 "xmlAttrDump : property == NULL\n");
5529#endif
5530 return;
5531 }
5532 xmlBufferWriteChar(buf, " ");
5533 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5534 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5535 xmlBufferWriteChar(buf, ":");
5536 }
5537 xmlBufferWriteCHAR(buf, cur->name);
5538 value = xmlNodeListGetString(doc, cur->children, 0);
5539 if (value != NULL) {
5540 xmlBufferWriteChar(buf, "=");
5541 xmlBufferWriteQuotedString(buf, value);
5542 xmlFree(value);
5543 } else {
5544 xmlBufferWriteChar(buf, "=\"\"");
5545 }
5546}
5547
5548/**
5549 * xmlAttrListDump:
5550 * @buf: the XML buffer output
5551 * @doc: the document
5552 * @cur: the first attribute pointer
5553 *
5554 * Dump a list of XML attributes
5555 */
5556static void
5557xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5558 if (cur == NULL) {
5559#ifdef DEBUG_TREE
5560 xmlGenericError(xmlGenericErrorContext,
5561 "xmlAttrListDump : property == NULL\n");
5562#endif
5563 return;
5564 }
5565 while (cur != NULL) {
5566 xmlAttrDump(buf, doc, cur);
5567 cur = cur->next;
5568 }
5569}
5570
5571
5572
5573/**
5574 * xmlNodeListDump:
5575 * @buf: the XML buffer output
5576 * @doc: the document
5577 * @cur: the first node
5578 * @level: the imbrication level for indenting
5579 * @format: is formatting allowed
5580 *
5581 * Dump an XML node list, recursive behaviour,children are printed too.
5582 */
5583static void
5584xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5585 int format) {
5586 int i;
5587
5588 if (cur == NULL) {
5589#ifdef DEBUG_TREE
5590 xmlGenericError(xmlGenericErrorContext,
5591 "xmlNodeListDump : node == NULL\n");
5592#endif
5593 return;
5594 }
5595 while (cur != NULL) {
5596 if ((format) && (xmlIndentTreeOutput) &&
5597 (cur->type == XML_ELEMENT_NODE))
5598 for (i = 0;i < level;i++)
5599 xmlBufferWriteChar(buf, " ");
5600 xmlNodeDump(buf, doc, cur, level, format);
5601 if (format) {
5602 xmlBufferWriteChar(buf, "\n");
5603 }
5604 cur = cur->next;
5605 }
5606}
5607
5608/**
5609 * xmlNodeDump:
5610 * @buf: the XML buffer output
5611 * @doc: the document
5612 * @cur: the current node
5613 * @level: the imbrication level for indenting
5614 * @format: is formatting allowed
5615 *
5616 * Dump an XML node, recursive behaviour,children are printed too.
5617 */
5618void
5619xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5620 int format) {
5621 int i;
5622 xmlNodePtr tmp;
5623
5624 if (cur == NULL) {
5625#ifdef DEBUG_TREE
5626 xmlGenericError(xmlGenericErrorContext,
5627 "xmlNodeDump : node == NULL\n");
5628#endif
5629 return;
5630 }
5631 if (cur->type == XML_XINCLUDE_START)
5632 return;
5633 if (cur->type == XML_XINCLUDE_END)
5634 return;
5635 if (cur->type == XML_DTD_NODE) {
5636 xmlDtdDump(buf, (xmlDtdPtr) cur);
5637 return;
5638 }
5639 if (cur->type == XML_ELEMENT_DECL) {
5640 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5641 return;
5642 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005643 if (cur->type == XML_ATTRIBUTE_NODE){
5644 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5645 return;
5646 }
Owen Taylor3473f882001-02-23 17:55:21 +00005647 if (cur->type == XML_ATTRIBUTE_DECL) {
5648 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5649 return;
5650 }
5651 if (cur->type == XML_ENTITY_DECL) {
5652 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5653 return;
5654 }
5655 if (cur->type == XML_TEXT_NODE) {
5656 if (cur->content != NULL) {
5657 if ((cur->name == xmlStringText) ||
5658 (cur->name != xmlStringTextNoenc)) {
5659 xmlChar *buffer;
5660
5661#ifndef XML_USE_BUFFER_CONTENT
5662 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5663#else
5664 buffer = xmlEncodeEntitiesReentrant(doc,
5665 xmlBufferContent(cur->content));
5666#endif
5667 if (buffer != NULL) {
5668 xmlBufferWriteCHAR(buf, buffer);
5669 xmlFree(buffer);
5670 }
5671 } else {
5672 /*
5673 * Disable escaping, needed for XSLT
5674 */
5675#ifndef XML_USE_BUFFER_CONTENT
5676 xmlBufferWriteCHAR(buf, cur->content);
5677#else
5678 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5679#endif
5680 }
5681 }
5682 return;
5683 }
5684 if (cur->type == XML_PI_NODE) {
5685 if (cur->content != NULL) {
5686 xmlBufferWriteChar(buf, "<?");
5687 xmlBufferWriteCHAR(buf, cur->name);
5688 if (cur->content != NULL) {
5689 xmlBufferWriteChar(buf, " ");
5690#ifndef XML_USE_BUFFER_CONTENT
5691 xmlBufferWriteCHAR(buf, cur->content);
5692#else
5693 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5694#endif
5695 }
5696 xmlBufferWriteChar(buf, "?>");
5697 } else {
5698 xmlBufferWriteChar(buf, "<?");
5699 xmlBufferWriteCHAR(buf, cur->name);
5700 xmlBufferWriteChar(buf, "?>");
5701 }
5702 return;
5703 }
5704 if (cur->type == XML_COMMENT_NODE) {
5705 if (cur->content != NULL) {
5706 xmlBufferWriteChar(buf, "<!--");
5707#ifndef XML_USE_BUFFER_CONTENT
5708 xmlBufferWriteCHAR(buf, cur->content);
5709#else
5710 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5711#endif
5712 xmlBufferWriteChar(buf, "-->");
5713 }
5714 return;
5715 }
5716 if (cur->type == XML_ENTITY_REF_NODE) {
5717 xmlBufferWriteChar(buf, "&");
5718 xmlBufferWriteCHAR(buf, cur->name);
5719 xmlBufferWriteChar(buf, ";");
5720 return;
5721 }
5722 if (cur->type == XML_CDATA_SECTION_NODE) {
5723 xmlBufferWriteChar(buf, "<![CDATA[");
5724 if (cur->content != NULL)
5725#ifndef XML_USE_BUFFER_CONTENT
5726 xmlBufferWriteCHAR(buf, cur->content);
5727#else
5728 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5729#endif
5730 xmlBufferWriteChar(buf, "]]>");
5731 return;
5732 }
5733
5734 if (format == 1) {
5735 tmp = cur->children;
5736 while (tmp != NULL) {
5737 if ((tmp->type == XML_TEXT_NODE) ||
5738 (tmp->type == XML_ENTITY_REF_NODE)) {
5739 format = 0;
5740 break;
5741 }
5742 tmp = tmp->next;
5743 }
5744 }
5745 xmlBufferWriteChar(buf, "<");
5746 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5747 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5748 xmlBufferWriteChar(buf, ":");
5749 }
5750
5751 xmlBufferWriteCHAR(buf, cur->name);
5752 if (cur->nsDef)
5753 xmlNsListDump(buf, cur->nsDef);
5754 if (cur->properties != NULL)
5755 xmlAttrListDump(buf, doc, cur->properties);
5756
Daniel Veillard7db37732001-07-12 01:20:08 +00005757 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5758 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005759 (!xmlSaveNoEmptyTags)) {
5760 xmlBufferWriteChar(buf, "/>");
5761 return;
5762 }
5763 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005764 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005765 xmlChar *buffer;
5766
5767#ifndef XML_USE_BUFFER_CONTENT
5768 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5769#else
5770 buffer = xmlEncodeEntitiesReentrant(doc,
5771 xmlBufferContent(cur->content));
5772#endif
5773 if (buffer != NULL) {
5774 xmlBufferWriteCHAR(buf, buffer);
5775 xmlFree(buffer);
5776 }
5777 }
5778 if (cur->children != NULL) {
5779 if (format) xmlBufferWriteChar(buf, "\n");
5780 xmlNodeListDump(buf, doc, cur->children,
5781 (level >= 0?level+1:-1), format);
5782 if ((xmlIndentTreeOutput) && (format))
5783 for (i = 0;i < level;i++)
5784 xmlBufferWriteChar(buf, " ");
5785 }
5786 xmlBufferWriteChar(buf, "</");
5787 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5788 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5789 xmlBufferWriteChar(buf, ":");
5790 }
5791
5792 xmlBufferWriteCHAR(buf, cur->name);
5793 xmlBufferWriteChar(buf, ">");
5794}
5795
5796/**
5797 * xmlElemDump:
5798 * @f: the FILE * for the output
5799 * @doc: the document
5800 * @cur: the current node
5801 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005802 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00005803 */
5804void
5805xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5806 xmlBufferPtr buf;
5807
5808 if (cur == NULL) {
5809#ifdef DEBUG_TREE
5810 xmlGenericError(xmlGenericErrorContext,
5811 "xmlElemDump : cur == NULL\n");
5812#endif
5813 return;
5814 }
Owen Taylor3473f882001-02-23 17:55:21 +00005815#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005816 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005817 xmlGenericError(xmlGenericErrorContext,
5818 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005819 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005820#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005821
Owen Taylor3473f882001-02-23 17:55:21 +00005822 buf = xmlBufferCreate();
5823 if (buf == NULL) return;
5824 if ((doc != NULL) &&
5825 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5826#ifdef LIBXML_HTML_ENABLED
5827 htmlNodeDump(buf, doc, cur);
5828#else
5829 xmlGenericError(xmlGenericErrorContext,
5830 "HTML support not compiled in\n");
5831#endif /* LIBXML_HTML_ENABLED */
5832 } else
5833 xmlNodeDump(buf, doc, cur, 0, 1);
5834 xmlBufferDump(f, buf);
5835 xmlBufferFree(buf);
5836}
5837
5838/************************************************************************
5839 * *
5840 * Dumping XML tree content to an I/O output buffer *
5841 * *
5842 ************************************************************************/
5843
5844void
5845xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5846 int level, int format, const char *encoding);
5847static void
5848xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5849 int level, int format, const char *encoding);
5850/**
5851 * xmlNsDumpOutput:
5852 * @buf: the XML buffer output
5853 * @cur: a namespace
5854 *
5855 * Dump a local Namespace definition.
5856 * Should be called in the context of attributes dumps.
5857 */
5858static void
5859xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5860 if (cur == NULL) {
5861#ifdef DEBUG_TREE
5862 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005863 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005864#endif
5865 return;
5866 }
5867 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5868 /* Within the context of an element attributes */
5869 if (cur->prefix != NULL) {
5870 xmlOutputBufferWriteString(buf, " xmlns:");
5871 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5872 } else
5873 xmlOutputBufferWriteString(buf, " xmlns");
5874 xmlOutputBufferWriteString(buf, "=");
5875 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5876 }
5877}
5878
5879/**
5880 * xmlNsListDumpOutput:
5881 * @buf: the XML buffer output
5882 * @cur: the first namespace
5883 *
5884 * Dump a list of local Namespace definitions.
5885 * Should be called in the context of attributes dumps.
5886 */
5887static void
5888xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5889 while (cur != NULL) {
5890 xmlNsDumpOutput(buf, cur);
5891 cur = cur->next;
5892 }
5893}
5894
5895/**
5896 * xmlDtdDumpOutput:
5897 * @buf: the XML buffer output
5898 * @doc: the document
5899 * @encoding: an optional encoding string
5900 *
5901 * Dump the XML document DTD, if any.
5902 */
5903static void
5904xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5905 if (dtd == NULL) {
5906#ifdef DEBUG_TREE
5907 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005908 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005909#endif
5910 return;
5911 }
5912 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5913 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5914 if (dtd->ExternalID != NULL) {
5915 xmlOutputBufferWriteString(buf, " PUBLIC ");
5916 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5917 xmlOutputBufferWriteString(buf, " ");
5918 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5919 } else if (dtd->SystemID != NULL) {
5920 xmlOutputBufferWriteString(buf, " SYSTEM ");
5921 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5922 }
5923 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5924 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5925 xmlOutputBufferWriteString(buf, ">");
5926 return;
5927 }
5928 xmlOutputBufferWriteString(buf, " [\n");
5929 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5930 xmlOutputBufferWriteString(buf, "]>");
5931}
5932
5933/**
5934 * xmlAttrDumpOutput:
5935 * @buf: the XML buffer output
5936 * @doc: the document
5937 * @cur: the attribute pointer
5938 * @encoding: an optional encoding string
5939 *
5940 * Dump an XML attribute
5941 */
5942static void
5943xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005944 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005945 xmlChar *value;
5946
5947 if (cur == NULL) {
5948#ifdef DEBUG_TREE
5949 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005950 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005951#endif
5952 return;
5953 }
5954 xmlOutputBufferWriteString(buf, " ");
5955 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5956 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5957 xmlOutputBufferWriteString(buf, ":");
5958 }
5959 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5960 value = xmlNodeListGetString(doc, cur->children, 0);
5961 if (value) {
5962 xmlOutputBufferWriteString(buf, "=");
5963 xmlBufferWriteQuotedString(buf->buffer, value);
5964 xmlFree(value);
5965 } else {
5966 xmlOutputBufferWriteString(buf, "=\"\"");
5967 }
5968}
5969
5970/**
5971 * xmlAttrListDumpOutput:
5972 * @buf: the XML buffer output
5973 * @doc: the document
5974 * @cur: the first attribute pointer
5975 * @encoding: an optional encoding string
5976 *
5977 * Dump a list of XML attributes
5978 */
5979static void
5980xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5981 xmlAttrPtr cur, const char *encoding) {
5982 if (cur == NULL) {
5983#ifdef DEBUG_TREE
5984 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005985 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005986#endif
5987 return;
5988 }
5989 while (cur != NULL) {
5990 xmlAttrDumpOutput(buf, doc, cur, encoding);
5991 cur = cur->next;
5992 }
5993}
5994
5995
5996
5997/**
5998 * xmlNodeListDumpOutput:
5999 * @buf: the XML buffer output
6000 * @doc: the document
6001 * @cur: the first node
6002 * @level: the imbrication level for indenting
6003 * @format: is formatting allowed
6004 * @encoding: an optional encoding string
6005 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006006 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006007 */
6008static void
6009xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6010 xmlNodePtr cur, int level, int format, const char *encoding) {
6011 int i;
6012
6013 if (cur == NULL) {
6014#ifdef DEBUG_TREE
6015 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006016 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006017#endif
6018 return;
6019 }
6020 while (cur != NULL) {
6021 if ((format) && (xmlIndentTreeOutput) &&
6022 (cur->type == XML_ELEMENT_NODE))
6023 for (i = 0;i < level;i++)
6024 xmlOutputBufferWriteString(buf, " ");
6025 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6026 if (format) {
6027 xmlOutputBufferWriteString(buf, "\n");
6028 }
6029 cur = cur->next;
6030 }
6031}
6032
6033/**
6034 * xmlNodeDumpOutput:
6035 * @buf: the XML buffer output
6036 * @doc: the document
6037 * @cur: the current node
6038 * @level: the imbrication level for indenting
6039 * @format: is formatting allowed
6040 * @encoding: an optional encoding string
6041 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006042 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006043 */
6044void
6045xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6046 int level, int format, const char *encoding) {
6047 int i;
6048 xmlNodePtr tmp;
6049
6050 if (cur == NULL) {
6051#ifdef DEBUG_TREE
6052 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006053 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006054#endif
6055 return;
6056 }
6057 if (cur->type == XML_XINCLUDE_START)
6058 return;
6059 if (cur->type == XML_XINCLUDE_END)
6060 return;
6061 if (cur->type == XML_DTD_NODE) {
6062 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6063 return;
6064 }
6065 if (cur->type == XML_ELEMENT_DECL) {
6066 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6067 return;
6068 }
6069 if (cur->type == XML_ATTRIBUTE_DECL) {
6070 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6071 return;
6072 }
6073 if (cur->type == XML_ENTITY_DECL) {
6074 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6075 return;
6076 }
6077 if (cur->type == XML_TEXT_NODE) {
6078 if (cur->content != NULL) {
6079 if ((cur->name == xmlStringText) ||
6080 (cur->name != xmlStringTextNoenc)) {
6081 xmlChar *buffer;
6082
6083#ifndef XML_USE_BUFFER_CONTENT
6084 if (encoding == NULL)
6085 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6086 else
6087 buffer = xmlEncodeSpecialChars(doc, cur->content);
6088#else
6089 if (encoding == NULL)
6090 buffer = xmlEncodeEntitiesReentrant(doc,
6091 xmlBufferContent(cur->content));
6092 else
6093 buffer = xmlEncodeSpecialChars(doc,
6094 xmlBufferContent(cur->content));
6095#endif
6096 if (buffer != NULL) {
6097 xmlOutputBufferWriteString(buf, (const char *)buffer);
6098 xmlFree(buffer);
6099 }
6100 } else {
6101 /*
6102 * Disable escaping, needed for XSLT
6103 */
6104#ifndef XML_USE_BUFFER_CONTENT
6105 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6106#else
6107 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6108#endif
6109 }
6110 }
6111
6112 return;
6113 }
6114 if (cur->type == XML_PI_NODE) {
6115 if (cur->content != NULL) {
6116 xmlOutputBufferWriteString(buf, "<?");
6117 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6118 if (cur->content != NULL) {
6119 xmlOutputBufferWriteString(buf, " ");
6120#ifndef XML_USE_BUFFER_CONTENT
6121 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6122#else
6123 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6124#endif
6125 }
6126 xmlOutputBufferWriteString(buf, "?>");
6127 } else {
6128 xmlOutputBufferWriteString(buf, "<?");
6129 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6130 xmlOutputBufferWriteString(buf, "?>");
6131 }
6132 return;
6133 }
6134 if (cur->type == XML_COMMENT_NODE) {
6135 if (cur->content != NULL) {
6136 xmlOutputBufferWriteString(buf, "<!--");
6137#ifndef XML_USE_BUFFER_CONTENT
6138 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6139#else
6140 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6141#endif
6142 xmlOutputBufferWriteString(buf, "-->");
6143 }
6144 return;
6145 }
6146 if (cur->type == XML_ENTITY_REF_NODE) {
6147 xmlOutputBufferWriteString(buf, "&");
6148 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6149 xmlOutputBufferWriteString(buf, ";");
6150 return;
6151 }
6152 if (cur->type == XML_CDATA_SECTION_NODE) {
6153 xmlOutputBufferWriteString(buf, "<![CDATA[");
6154 if (cur->content != NULL)
6155#ifndef XML_USE_BUFFER_CONTENT
6156 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6157#else
6158 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6159#endif
6160 xmlOutputBufferWriteString(buf, "]]>");
6161 return;
6162 }
6163
6164 if (format == 1) {
6165 tmp = cur->children;
6166 while (tmp != NULL) {
6167 if ((tmp->type == XML_TEXT_NODE) ||
6168 (tmp->type == XML_ENTITY_REF_NODE)) {
6169 format = 0;
6170 break;
6171 }
6172 tmp = tmp->next;
6173 }
6174 }
6175 xmlOutputBufferWriteString(buf, "<");
6176 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6177 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6178 xmlOutputBufferWriteString(buf, ":");
6179 }
6180
6181 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6182 if (cur->nsDef)
6183 xmlNsListDumpOutput(buf, cur->nsDef);
6184 if (cur->properties != NULL)
6185 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6186
Daniel Veillard7db37732001-07-12 01:20:08 +00006187 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6188 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006189 xmlOutputBufferWriteString(buf, "/>");
6190 return;
6191 }
6192 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006193 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006194 xmlChar *buffer;
6195
6196#ifndef XML_USE_BUFFER_CONTENT
6197 if (encoding == NULL)
6198 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6199 else
6200 buffer = xmlEncodeSpecialChars(doc, cur->content);
6201#else
6202 if (encoding == NULL)
6203 buffer = xmlEncodeEntitiesReentrant(doc,
6204 xmlBufferContent(cur->content));
6205 else
6206 buffer = xmlEncodeSpecialChars(doc,
6207 xmlBufferContent(cur->content));
6208#endif
6209 if (buffer != NULL) {
6210 xmlOutputBufferWriteString(buf, (const char *)buffer);
6211 xmlFree(buffer);
6212 }
6213 }
6214 if (cur->children != NULL) {
6215 if (format) xmlOutputBufferWriteString(buf, "\n");
6216 xmlNodeListDumpOutput(buf, doc, cur->children,
6217 (level >= 0?level+1:-1), format, encoding);
6218 if ((xmlIndentTreeOutput) && (format))
6219 for (i = 0;i < level;i++)
6220 xmlOutputBufferWriteString(buf, " ");
6221 }
6222 xmlOutputBufferWriteString(buf, "</");
6223 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6224 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6225 xmlOutputBufferWriteString(buf, ":");
6226 }
6227
6228 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6229 xmlOutputBufferWriteString(buf, ">");
6230}
6231
6232/**
6233 * xmlDocContentDumpOutput:
6234 * @buf: the XML buffer output
6235 * @cur: the document
6236 * @encoding: an optional encoding string
6237 * @format: should formatting spaces been added
6238 *
6239 * Dump an XML document.
6240 */
6241static void
6242xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6243 const char *encoding, int format) {
6244 xmlOutputBufferWriteString(buf, "<?xml version=");
6245 if (cur->version != NULL)
6246 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6247 else
6248 xmlOutputBufferWriteString(buf, "\"1.0\"");
6249 if (encoding == NULL) {
6250 if (cur->encoding != NULL)
6251 encoding = (const char *) cur->encoding;
6252 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6253 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6254 }
6255 if (encoding != NULL) {
6256 xmlOutputBufferWriteString(buf, " encoding=");
6257 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6258 }
6259 switch (cur->standalone) {
6260 case 0:
6261 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6262 break;
6263 case 1:
6264 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6265 break;
6266 }
6267 xmlOutputBufferWriteString(buf, "?>\n");
6268 if (cur->children != NULL) {
6269 xmlNodePtr child = cur->children;
6270
6271 while (child != NULL) {
6272 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6273 xmlOutputBufferWriteString(buf, "\n");
6274 child = child->next;
6275 }
6276 }
6277}
6278
6279/************************************************************************
6280 * *
6281 * Saving functions front-ends *
6282 * *
6283 ************************************************************************/
6284
6285/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006286 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006287 * @out_doc: Document to generate XML text from
6288 * @doc_txt_ptr: Memory pointer for allocated XML text
6289 * @doc_txt_len: Length of the generated XML text
6290 * @txt_encoding: Character encoding to use when generating XML text
6291 * @format: should formatting spaces been added
6292 *
6293 * Dump the current DOM tree into memory using the character encoding specified
6294 * by the caller. Note it is up to the caller of this function to free the
6295 * allocated memory.
6296 */
6297
6298void
6299xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006300 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006301 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006302 int dummy = 0;
6303
6304 xmlCharEncoding doc_charset;
6305 xmlOutputBufferPtr out_buff = NULL;
6306 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6307
6308 if (doc_txt_len == NULL) {
6309 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6310 }
6311
6312 if (doc_txt_ptr == NULL) {
6313 *doc_txt_len = 0;
6314 xmlGenericError(xmlGenericErrorContext,
6315 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6316 return;
6317 }
6318
6319 *doc_txt_ptr = NULL;
6320 *doc_txt_len = 0;
6321
6322 if (out_doc == NULL) {
6323 /* No document, no output */
6324 xmlGenericError(xmlGenericErrorContext,
6325 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6326 return;
6327 }
6328
6329 /*
6330 * Validate the encoding value, if provided.
6331 * This logic is copied from xmlSaveFileEnc.
6332 */
6333
6334 if (txt_encoding == NULL)
6335 txt_encoding = (const char *) out_doc->encoding;
6336 if (txt_encoding != NULL) {
6337 doc_charset = xmlParseCharEncoding(txt_encoding);
6338
6339 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6340 xmlGenericError(xmlGenericErrorContext,
6341 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6342 return;
6343
6344 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6345 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6346 if ( conv_hdlr == NULL ) {
6347 xmlGenericError(xmlGenericErrorContext,
6348 "%s: %s %s '%s'\n",
6349 "xmlDocDumpFormatMemoryEnc",
6350 "Failed to identify encoding handler for",
6351 "character set",
6352 txt_encoding);
6353 return;
6354 }
6355 }
6356 }
6357
6358 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6359 xmlGenericError(xmlGenericErrorContext,
6360 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6361 return;
6362 }
6363
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006364 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006365 xmlOutputBufferFlush(out_buff);
6366 if (out_buff->conv != NULL) {
6367 *doc_txt_len = out_buff->conv->use;
6368 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6369 } else {
6370 *doc_txt_len = out_buff->buffer->use;
6371 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6372 }
6373 (void)xmlOutputBufferClose(out_buff);
6374
6375 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6376 *doc_txt_len = 0;
6377 xmlGenericError(xmlGenericErrorContext,
6378 "xmlDocDumpFormatMemoryEnc: %s\n",
6379 "Failed to allocate memory for document text representation.");
6380 }
6381
6382 return;
6383}
6384
6385/**
6386 * xmlDocDumpMemory:
6387 * @cur: the document
6388 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006389 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006390 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006391 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006392 * It's up to the caller to free the memory.
6393 */
6394void
6395xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6396 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6397}
6398
6399/**
6400 * xmlDocDumpFormatMemory:
6401 * @cur: the document
6402 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006403 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006404 * @format: should formatting spaces been added
6405 *
6406 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006407 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006408 * It's up to the caller to free the memory.
6409 */
6410void
6411xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6412 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6413}
6414
6415/**
6416 * xmlDocDumpMemoryEnc:
6417 * @out_doc: Document to generate XML text from
6418 * @doc_txt_ptr: Memory pointer for allocated XML text
6419 * @doc_txt_len: Length of the generated XML text
6420 * @txt_encoding: Character encoding to use when generating XML text
6421 *
6422 * Dump the current DOM tree into memory using the character encoding specified
6423 * by the caller. Note it is up to the caller of this function to free the
6424 * allocated memory.
6425 */
6426
6427void
6428xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6429 int * doc_txt_len, const char * txt_encoding) {
6430 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006431 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006432}
6433
6434/**
6435 * xmlGetDocCompressMode:
6436 * @doc: the document
6437 *
6438 * get the compression ratio for a document, ZLIB based
6439 * Returns 0 (uncompressed) to 9 (max compression)
6440 */
6441int
6442xmlGetDocCompressMode (xmlDocPtr doc) {
6443 if (doc == NULL) return(-1);
6444 return(doc->compression);
6445}
6446
6447/**
6448 * xmlSetDocCompressMode:
6449 * @doc: the document
6450 * @mode: the compression ratio
6451 *
6452 * set the compression ratio for a document, ZLIB based
6453 * Correct values: 0 (uncompressed) to 9 (max compression)
6454 */
6455void
6456xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6457 if (doc == NULL) return;
6458 if (mode < 0) doc->compression = 0;
6459 else if (mode > 9) doc->compression = 9;
6460 else doc->compression = mode;
6461}
6462
6463/**
6464 * xmlGetCompressMode:
6465 *
6466 * get the default compression mode used, ZLIB based.
6467 * Returns 0 (uncompressed) to 9 (max compression)
6468 */
6469int
6470 xmlGetCompressMode(void) {
6471 return(xmlCompressMode);
6472}
6473
6474/**
6475 * xmlSetCompressMode:
6476 * @mode: the compression ratio
6477 *
6478 * set the default compression mode used, ZLIB based
6479 * Correct values: 0 (uncompressed) to 9 (max compression)
6480 */
6481void
6482xmlSetCompressMode(int mode) {
6483 if (mode < 0) xmlCompressMode = 0;
6484 else if (mode > 9) xmlCompressMode = 9;
6485 else xmlCompressMode = mode;
6486}
6487
6488/**
6489 * xmlDocDump:
6490 * @f: the FILE*
6491 * @cur: the document
6492 *
6493 * Dump an XML document to an open FILE.
6494 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006495 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006496 */
6497int
6498xmlDocDump(FILE *f, xmlDocPtr cur) {
6499 xmlOutputBufferPtr buf;
6500 const char * encoding;
6501 xmlCharEncodingHandlerPtr handler = NULL;
6502 int ret;
6503
6504 if (cur == NULL) {
6505#ifdef DEBUG_TREE
6506 xmlGenericError(xmlGenericErrorContext,
6507 "xmlDocDump : document == NULL\n");
6508#endif
6509 return(-1);
6510 }
6511 encoding = (const char *) cur->encoding;
6512
6513 if (encoding != NULL) {
6514 xmlCharEncoding enc;
6515
6516 enc = xmlParseCharEncoding(encoding);
6517
6518 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6519 xmlGenericError(xmlGenericErrorContext,
6520 "xmlDocDump: document not in UTF8\n");
6521 return(-1);
6522 }
6523 if (enc != XML_CHAR_ENCODING_UTF8) {
6524 handler = xmlFindCharEncodingHandler(encoding);
6525 if (handler == NULL) {
6526 xmlFree((char *) cur->encoding);
6527 cur->encoding = NULL;
6528 }
6529 }
6530 }
6531 buf = xmlOutputBufferCreateFile(f, handler);
6532 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006533 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006534
6535 ret = xmlOutputBufferClose(buf);
6536 return(ret);
6537}
6538
6539/**
6540 * xmlSaveFileTo:
6541 * @buf: an output I/O buffer
6542 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006543 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006544 *
6545 * Dump an XML document to an I/O buffer.
6546 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006547 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006548 */
6549int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006550xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006551 int ret;
6552
6553 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006554 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006555 ret = xmlOutputBufferClose(buf);
6556 return(ret);
6557}
6558
6559/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006560 * xmlSaveFormatFileTo:
6561 * @buf: an output I/O buffer
6562 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006563 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006564 * @format: should formatting spaces been added
6565 *
6566 * Dump an XML document to an I/O buffer.
6567 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006568 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006569 */
6570int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006571xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006572 int ret;
6573
6574 if (buf == NULL) return(0);
6575 xmlDocContentDumpOutput(buf, cur, encoding, format);
6576 ret = xmlOutputBufferClose(buf);
6577 return(ret);
6578}
6579
6580/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006581 * xmlSaveFormatFileEnc
6582 * @filename: the filename or URL to output
6583 * @cur: the document being saved
6584 * @encoding: the name of the encoding to use or NULL.
6585 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006586 *
6587 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006588 */
6589int
Daniel Veillardf012a642001-07-23 19:10:52 +00006590xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6591 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006592 xmlOutputBufferPtr buf;
6593 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006594 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006595 int ret;
6596
6597 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006598
6599 enc = xmlParseCharEncoding(encoding);
6600 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6601 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006602 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006603 return(-1);
6604 }
6605 if (enc != XML_CHAR_ENCODING_UTF8) {
6606 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006607 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006608 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006609 }
6610 }
6611
Daniel Veillardf012a642001-07-23 19:10:52 +00006612#ifdef HAVE_ZLIB_H
6613 if (cur->compression < 0) cur->compression = xmlCompressMode;
6614#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006615 /*
6616 * save the content to a temp buffer.
6617 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006618 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006619 if (buf == NULL) return(-1);
6620
Daniel Veillardf012a642001-07-23 19:10:52 +00006621 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006622
6623 ret = xmlOutputBufferClose(buf);
6624 return(ret);
6625}
6626
Daniel Veillardf012a642001-07-23 19:10:52 +00006627
6628/**
6629 * xmlSaveFileEnc:
6630 * @filename: the filename (or URL)
6631 * @cur: the document
6632 * @encoding: the name of an encoding (or NULL)
6633 *
6634 * Dump an XML document, converting it to the given encoding
6635 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006636 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006637 */
6638int
6639xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6640 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6641}
6642
Owen Taylor3473f882001-02-23 17:55:21 +00006643/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006644 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006645 * @filename: the filename (or URL)
6646 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006647 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006648 *
6649 * Dump an XML document to a file. Will use compression if
6650 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006651 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006652 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006653 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006654 */
6655int
Daniel Veillard67fee942001-04-26 18:59:03 +00006656xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006657 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006658}
6659
Daniel Veillard67fee942001-04-26 18:59:03 +00006660/**
6661 * xmlSaveFile:
6662 * @filename: the filename (or URL)
6663 * @cur: the document
6664 *
6665 * Dump an XML document to a file. Will use compression if
6666 * compiled in and enabled. If @filename is "-" the stdout file is
6667 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006668 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006669 */
6670int
6671xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006672 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006673}
6674