blob: b75f304ab9870e4330d9c5067b536ff526107807 [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;
753 } else
754 xmlNodeAddContent(last, ent->content);
755
756 } else {
757 /*
758 * Create a new REFERENCE_REF node
759 */
760 node = xmlNewReference(doc, val);
761 if (node == NULL) {
762 if (val != NULL) xmlFree(val);
763 return(ret);
764 }
765 if (last == NULL) {
766 last = ret = node;
767 } else {
768 last = xmlAddNextSibling(last, node);
769 }
770 }
771 xmlFree(val);
772 }
773 cur++;
774 q = cur;
775 }
776 if (charval != 0) {
777 xmlChar buf[10];
778 int len;
779
780 len = xmlCopyCharMultiByte(buf, charval);
781 buf[len] = 0;
782 node = xmlNewDocText(doc, buf);
783 if (node != NULL) {
784 if (last == NULL) {
785 last = ret = node;
786 } else {
787 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000788 }
789 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000790
791 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000792 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000793 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000794 cur++;
795 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000796 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000797 /*
798 * Handle the last piece of text.
799 */
800 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
801 xmlNodeAddContentLen(last, q, cur - q);
802 } else {
803 node = xmlNewDocTextLen(doc, q, cur - q);
804 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000805 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000806 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000807 } else {
808 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000809 }
810 }
811 }
812 return(ret);
813}
814
815/**
816 * xmlNodeListGetString:
817 * @doc: the document
818 * @list: a Node list
819 * @inLine: should we replace entity contents or show their external form
820 *
821 * Returns the string equivalent to the text contained in the Node list
822 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000823 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000824 */
825xmlChar *
826xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
827 xmlNodePtr node = list;
828 xmlChar *ret = NULL;
829 xmlEntityPtr ent;
830
831 if (list == NULL) return(NULL);
832
833 while (node != NULL) {
834 if ((node->type == XML_TEXT_NODE) ||
835 (node->type == XML_CDATA_SECTION_NODE)) {
836 if (inLine) {
837#ifndef XML_USE_BUFFER_CONTENT
838 ret = xmlStrcat(ret, node->content);
839#else
840 ret = xmlStrcat(ret, xmlBufferContent(node->content));
841#endif
842 } else {
843 xmlChar *buffer;
844
845#ifndef XML_USE_BUFFER_CONTENT
846 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
847#else
848 buffer = xmlEncodeEntitiesReentrant(doc,
849 xmlBufferContent(node->content));
850#endif
851 if (buffer != NULL) {
852 ret = xmlStrcat(ret, buffer);
853 xmlFree(buffer);
854 }
855 }
856 } else if (node->type == XML_ENTITY_REF_NODE) {
857 if (inLine) {
858 ent = xmlGetDocEntity(doc, node->name);
859 if (ent != NULL)
860 ret = xmlStrcat(ret, ent->content);
861 else {
862#ifndef XML_USE_BUFFER_CONTENT
863 ret = xmlStrcat(ret, node->content);
864#else
865 ret = xmlStrcat(ret, xmlBufferContent(node->content));
866#endif
867 }
868 } else {
869 xmlChar buf[2];
870 buf[0] = '&'; buf[1] = 0;
871 ret = xmlStrncat(ret, buf, 1);
872 ret = xmlStrcat(ret, node->name);
873 buf[0] = ';'; buf[1] = 0;
874 ret = xmlStrncat(ret, buf, 1);
875 }
876 }
877#if 0
878 else {
879 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000880 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000881 node->type);
882 }
883#endif
884 node = node->next;
885 }
886 return(ret);
887}
888
889/**
890 * xmlNodeListGetRawString:
891 * @doc: the document
892 * @list: a Node list
893 * @inLine: should we replace entity contents or show their external form
894 *
895 * Returns the string equivalent to the text contained in the Node list
896 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
897 * this function doesn't do any character encoding handling.
898 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000899 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000900 */
901xmlChar *
902xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
903 xmlNodePtr node = list;
904 xmlChar *ret = NULL;
905 xmlEntityPtr ent;
906
907 if (list == NULL) return(NULL);
908
909 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000910 if ((node->type == XML_TEXT_NODE) ||
911 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000912 if (inLine) {
913#ifndef XML_USE_BUFFER_CONTENT
914 ret = xmlStrcat(ret, node->content);
915#else
916 ret = xmlStrcat(ret, xmlBufferContent(node->content));
917#endif
918 } else {
919 xmlChar *buffer;
920
921#ifndef XML_USE_BUFFER_CONTENT
922 buffer = xmlEncodeSpecialChars(doc, node->content);
923#else
924 buffer = xmlEncodeSpecialChars(doc,
925 xmlBufferContent(node->content));
926#endif
927 if (buffer != NULL) {
928 ret = xmlStrcat(ret, buffer);
929 xmlFree(buffer);
930 }
931 }
932 } else if (node->type == XML_ENTITY_REF_NODE) {
933 if (inLine) {
934 ent = xmlGetDocEntity(doc, node->name);
935 if (ent != NULL)
936 ret = xmlStrcat(ret, ent->content);
937 else {
938#ifndef XML_USE_BUFFER_CONTENT
939 ret = xmlStrcat(ret, node->content);
940#else
941 ret = xmlStrcat(ret, xmlBufferContent(node->content));
942#endif
943 }
944 } else {
945 xmlChar buf[2];
946 buf[0] = '&'; buf[1] = 0;
947 ret = xmlStrncat(ret, buf, 1);
948 ret = xmlStrcat(ret, node->name);
949 buf[0] = ';'; buf[1] = 0;
950 ret = xmlStrncat(ret, buf, 1);
951 }
952 }
953#if 0
954 else {
955 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000956 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000957 node->type);
958 }
959#endif
960 node = node->next;
961 }
962 return(ret);
963}
964
965/**
966 * xmlNewProp:
967 * @node: the holding node
968 * @name: the name of the attribute
969 * @value: the value of the attribute
970 *
971 * Create a new property carried by a node.
972 * Returns a pointer to the attribute
973 */
974xmlAttrPtr
975xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
976 xmlAttrPtr cur;
977 xmlDocPtr doc = NULL;
978
979 if (name == NULL) {
980#ifdef DEBUG_TREE
981 xmlGenericError(xmlGenericErrorContext,
982 "xmlNewProp : name == NULL\n");
983#endif
984 return(NULL);
985 }
986
987 /*
988 * Allocate a new property and fill the fields.
989 */
990 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
991 if (cur == NULL) {
992 xmlGenericError(xmlGenericErrorContext,
993 "xmlNewProp : malloc failed\n");
994 return(NULL);
995 }
996 memset(cur, 0, sizeof(xmlAttr));
997 cur->type = XML_ATTRIBUTE_NODE;
998
999 cur->parent = node;
1000 if (node != NULL) {
1001 doc = node->doc;
1002 cur->doc = doc;
1003 }
1004 cur->name = xmlStrdup(name);
1005 if (value != NULL) {
1006 xmlChar *buffer;
1007 xmlNodePtr tmp;
1008
1009 buffer = xmlEncodeEntitiesReentrant(doc, value);
1010 cur->children = xmlStringGetNodeList(doc, buffer);
1011 cur->last = NULL;
1012 tmp = cur->children;
1013 while (tmp != NULL) {
1014 tmp->parent = (xmlNodePtr) cur;
1015 tmp->doc = doc;
1016 if (tmp->next == NULL)
1017 cur->last = tmp;
1018 tmp = tmp->next;
1019 }
1020 xmlFree(buffer);
1021 }
1022
1023 /*
1024 * Add it at the end to preserve parsing order ...
1025 */
1026 if (node != NULL) {
1027 if (node->properties == NULL) {
1028 node->properties = cur;
1029 } else {
1030 xmlAttrPtr prev = node->properties;
1031
1032 while (prev->next != NULL) prev = prev->next;
1033 prev->next = cur;
1034 cur->prev = prev;
1035 }
1036 }
1037 return(cur);
1038}
1039
1040/**
1041 * xmlNewNsProp:
1042 * @node: the holding node
1043 * @ns: the namespace
1044 * @name: the name of the attribute
1045 * @value: the value of the attribute
1046 *
1047 * Create a new property tagged with a namespace and carried by a node.
1048 * Returns a pointer to the attribute
1049 */
1050xmlAttrPtr
1051xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1052 const xmlChar *value) {
1053 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001054 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001055
1056 if (name == NULL) {
1057#ifdef DEBUG_TREE
1058 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001059 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001060#endif
1061 return(NULL);
1062 }
1063
1064 /*
1065 * Allocate a new property and fill the fields.
1066 */
1067 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1068 if (cur == NULL) {
1069 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001070 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001071 return(NULL);
1072 }
1073 memset(cur, 0, sizeof(xmlAttr));
1074 cur->type = XML_ATTRIBUTE_NODE;
1075
1076 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001077 if (node != NULL) {
1078 doc = node->doc;
1079 cur->doc = doc;
1080 }
Owen Taylor3473f882001-02-23 17:55:21 +00001081 cur->ns = ns;
1082 cur->name = xmlStrdup(name);
1083 if (value != NULL) {
1084 xmlChar *buffer;
1085 xmlNodePtr tmp;
1086
Daniel Veillarda682b212001-06-07 19:59:42 +00001087 buffer = xmlEncodeEntitiesReentrant(doc, value);
1088 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001089 cur->last = NULL;
1090 tmp = cur->children;
1091 while (tmp != NULL) {
1092 tmp->parent = (xmlNodePtr) cur;
1093 if (tmp->next == NULL)
1094 cur->last = tmp;
1095 tmp = tmp->next;
1096 }
1097 xmlFree(buffer);
1098 }
1099
1100 /*
1101 * Add it at the end to preserve parsing order ...
1102 */
1103 if (node != NULL) {
1104 if (node->properties == NULL) {
1105 node->properties = cur;
1106 } else {
1107 xmlAttrPtr prev = node->properties;
1108
1109 while (prev->next != NULL) prev = prev->next;
1110 prev->next = cur;
1111 cur->prev = prev;
1112 }
1113 }
1114 return(cur);
1115}
1116
1117/**
1118 * xmlNewDocProp:
1119 * @doc: the document
1120 * @name: the name of the attribute
1121 * @value: the value of the attribute
1122 *
1123 * Create a new property carried by a document.
1124 * Returns a pointer to the attribute
1125 */
1126xmlAttrPtr
1127xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1128 xmlAttrPtr cur;
1129
1130 if (name == NULL) {
1131#ifdef DEBUG_TREE
1132 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001133 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001134#endif
1135 return(NULL);
1136 }
1137
1138 /*
1139 * Allocate a new property and fill the fields.
1140 */
1141 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1142 if (cur == NULL) {
1143 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001144 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001145 return(NULL);
1146 }
1147 memset(cur, 0, sizeof(xmlAttr));
1148 cur->type = XML_ATTRIBUTE_NODE;
1149
1150 cur->name = xmlStrdup(name);
1151 cur->doc = doc;
1152 if (value != NULL) {
1153 xmlNodePtr tmp;
1154
1155 cur->children = xmlStringGetNodeList(doc, value);
1156 cur->last = NULL;
1157
1158 tmp = cur->children;
1159 while (tmp != NULL) {
1160 tmp->parent = (xmlNodePtr) cur;
1161 if (tmp->next == NULL)
1162 cur->last = tmp;
1163 tmp = tmp->next;
1164 }
1165 }
1166 return(cur);
1167}
1168
1169/**
1170 * xmlFreePropList:
1171 * @cur: the first property in the list
1172 *
1173 * Free a property and all its siblings, all the children are freed too.
1174 */
1175void
1176xmlFreePropList(xmlAttrPtr cur) {
1177 xmlAttrPtr next;
1178 if (cur == NULL) {
1179#ifdef DEBUG_TREE
1180 xmlGenericError(xmlGenericErrorContext,
1181 "xmlFreePropList : property == NULL\n");
1182#endif
1183 return;
1184 }
1185 while (cur != NULL) {
1186 next = cur->next;
1187 xmlFreeProp(cur);
1188 cur = next;
1189 }
1190}
1191
1192/**
1193 * xmlFreeProp:
1194 * @cur: an attribute
1195 *
1196 * Free one attribute, all the content is freed too
1197 */
1198void
1199xmlFreeProp(xmlAttrPtr cur) {
1200 if (cur == NULL) {
1201#ifdef DEBUG_TREE
1202 xmlGenericError(xmlGenericErrorContext,
1203 "xmlFreeProp : property == NULL\n");
1204#endif
1205 return;
1206 }
1207 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001208 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1209 ((cur->parent->doc->intSubset != NULL) ||
1210 (cur->parent->doc->extSubset != NULL))) {
1211 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1212 xmlRemoveID(cur->parent->doc, cur);
1213 }
Owen Taylor3473f882001-02-23 17:55:21 +00001214 if (cur->name != NULL) xmlFree((char *) cur->name);
1215 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001216 xmlFree(cur);
1217}
1218
1219/**
1220 * xmlRemoveProp:
1221 * @cur: an attribute
1222 *
1223 * Unlink and free one attribute, all the content is freed too
1224 * Note this doesn't work for namespace definition attributes
1225 *
1226 * Returns 0 if success and -1 in case of error.
1227 */
1228int
1229xmlRemoveProp(xmlAttrPtr cur) {
1230 xmlAttrPtr tmp;
1231 if (cur == NULL) {
1232#ifdef DEBUG_TREE
1233 xmlGenericError(xmlGenericErrorContext,
1234 "xmlRemoveProp : cur == NULL\n");
1235#endif
1236 return(-1);
1237 }
1238 if (cur->parent == NULL) {
1239#ifdef DEBUG_TREE
1240 xmlGenericError(xmlGenericErrorContext,
1241 "xmlRemoveProp : cur->parent == NULL\n");
1242#endif
1243 return(-1);
1244 }
1245 tmp = cur->parent->properties;
1246 if (tmp == cur) {
1247 cur->parent->properties = cur->next;
1248 xmlFreeProp(cur);
1249 return(0);
1250 }
1251 while (tmp != NULL) {
1252 if (tmp->next == cur) {
1253 tmp->next = cur->next;
1254 if (tmp->next != NULL)
1255 tmp->next->prev = tmp;
1256 xmlFreeProp(cur);
1257 return(0);
1258 }
1259 tmp = tmp->next;
1260 }
1261#ifdef DEBUG_TREE
1262 xmlGenericError(xmlGenericErrorContext,
1263 "xmlRemoveProp : attribute not owned by its node\n");
1264#endif
1265 return(-1);
1266}
1267
1268/**
1269 * xmlNewPI:
1270 * @name: the processing instruction name
1271 * @content: the PI content
1272 *
1273 * Creation of a processing instruction element.
1274 * Returns a pointer to the new node object.
1275 */
1276xmlNodePtr
1277xmlNewPI(const xmlChar *name, const xmlChar *content) {
1278 xmlNodePtr cur;
1279
1280 if (name == NULL) {
1281#ifdef DEBUG_TREE
1282 xmlGenericError(xmlGenericErrorContext,
1283 "xmlNewPI : name == NULL\n");
1284#endif
1285 return(NULL);
1286 }
1287
1288 /*
1289 * Allocate a new node and fill the fields.
1290 */
1291 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1292 if (cur == NULL) {
1293 xmlGenericError(xmlGenericErrorContext,
1294 "xmlNewPI : malloc failed\n");
1295 return(NULL);
1296 }
1297 memset(cur, 0, sizeof(xmlNode));
1298 cur->type = XML_PI_NODE;
1299
1300 cur->name = xmlStrdup(name);
1301 if (content != NULL) {
1302#ifndef XML_USE_BUFFER_CONTENT
1303 cur->content = xmlStrdup(content);
1304#else
1305 cur->content = xmlBufferCreateSize(0);
1306 xmlBufferSetAllocationScheme(cur->content,
1307 xmlGetBufferAllocationScheme());
1308 xmlBufferAdd(cur->content, content, -1);
1309#endif
1310 }
1311 return(cur);
1312}
1313
1314/**
1315 * xmlNewNode:
1316 * @ns: namespace if any
1317 * @name: the node name
1318 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001319 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001320 *
1321 * Returns a pointer to the new node object.
1322 */
1323xmlNodePtr
1324xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1325 xmlNodePtr cur;
1326
1327 if (name == NULL) {
1328#ifdef DEBUG_TREE
1329 xmlGenericError(xmlGenericErrorContext,
1330 "xmlNewNode : name == NULL\n");
1331#endif
1332 return(NULL);
1333 }
1334
1335 /*
1336 * Allocate a new node and fill the fields.
1337 */
1338 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1339 if (cur == NULL) {
1340 xmlGenericError(xmlGenericErrorContext,
1341 "xmlNewNode : malloc failed\n");
1342 return(NULL);
1343 }
1344 memset(cur, 0, sizeof(xmlNode));
1345 cur->type = XML_ELEMENT_NODE;
1346
1347 cur->name = xmlStrdup(name);
1348 cur->ns = ns;
1349 return(cur);
1350}
1351
1352/**
1353 * xmlNewDocNode:
1354 * @doc: the document
1355 * @ns: namespace if any
1356 * @name: the node name
1357 * @content: the XML text content if any
1358 *
1359 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001360 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001361 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1362 * references, but XML special chars need to be escaped first by using
1363 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1364 * need entities support.
1365 *
1366 * Returns a pointer to the new node object.
1367 */
1368xmlNodePtr
1369xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1370 const xmlChar *name, const xmlChar *content) {
1371 xmlNodePtr cur;
1372
1373 cur = xmlNewNode(ns, name);
1374 if (cur != NULL) {
1375 cur->doc = doc;
1376 if (content != NULL) {
1377 cur->children = xmlStringGetNodeList(doc, content);
1378 UPDATE_LAST_CHILD_AND_PARENT(cur)
1379 }
1380 }
1381 return(cur);
1382}
1383
1384
1385/**
1386 * xmlNewDocRawNode:
1387 * @doc: the document
1388 * @ns: namespace if any
1389 * @name: the node name
1390 * @content: the text content if any
1391 *
1392 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001393 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001394 *
1395 * Returns a pointer to the new node object.
1396 */
1397xmlNodePtr
1398xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1399 const xmlChar *name, const xmlChar *content) {
1400 xmlNodePtr cur;
1401
1402 cur = xmlNewNode(ns, name);
1403 if (cur != NULL) {
1404 cur->doc = doc;
1405 if (content != NULL) {
1406 cur->children = xmlNewDocText(doc, content);
1407 UPDATE_LAST_CHILD_AND_PARENT(cur)
1408 }
1409 }
1410 return(cur);
1411}
1412
1413/**
1414 * xmlNewDocFragment:
1415 * @doc: the document owning the fragment
1416 *
1417 * Creation of a new Fragment node.
1418 * Returns a pointer to the new node object.
1419 */
1420xmlNodePtr
1421xmlNewDocFragment(xmlDocPtr doc) {
1422 xmlNodePtr cur;
1423
1424 /*
1425 * Allocate a new DocumentFragment node and fill the fields.
1426 */
1427 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1428 if (cur == NULL) {
1429 xmlGenericError(xmlGenericErrorContext,
1430 "xmlNewDocFragment : malloc failed\n");
1431 return(NULL);
1432 }
1433 memset(cur, 0, sizeof(xmlNode));
1434 cur->type = XML_DOCUMENT_FRAG_NODE;
1435
1436 cur->doc = doc;
1437 return(cur);
1438}
1439
1440/**
1441 * xmlNewText:
1442 * @content: the text content
1443 *
1444 * Creation of a new text node.
1445 * Returns a pointer to the new node object.
1446 */
1447xmlNodePtr
1448xmlNewText(const xmlChar *content) {
1449 xmlNodePtr cur;
1450
1451 /*
1452 * Allocate a new node and fill the fields.
1453 */
1454 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1455 if (cur == NULL) {
1456 xmlGenericError(xmlGenericErrorContext,
1457 "xmlNewText : malloc failed\n");
1458 return(NULL);
1459 }
1460 memset(cur, 0, sizeof(xmlNode));
1461 cur->type = XML_TEXT_NODE;
1462
1463 cur->name = xmlStringText;
1464 if (content != NULL) {
1465#ifndef XML_USE_BUFFER_CONTENT
1466 cur->content = xmlStrdup(content);
1467#else
1468 cur->content = xmlBufferCreateSize(0);
1469 xmlBufferSetAllocationScheme(cur->content,
1470 xmlGetBufferAllocationScheme());
1471 xmlBufferAdd(cur->content, content, -1);
1472#endif
1473 }
1474 return(cur);
1475}
1476
1477/**
1478 * xmlNewTextChild:
1479 * @parent: the parent node
1480 * @ns: a namespace if any
1481 * @name: the name of the child
1482 * @content: the text content of the child if any.
1483 *
1484 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001485 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001486 * a child TEXT node will be created containing the string content.
1487 *
1488 * Returns a pointer to the new node object.
1489 */
1490xmlNodePtr
1491xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1492 const xmlChar *name, const xmlChar *content) {
1493 xmlNodePtr cur, prev;
1494
1495 if (parent == NULL) {
1496#ifdef DEBUG_TREE
1497 xmlGenericError(xmlGenericErrorContext,
1498 "xmlNewTextChild : parent == NULL\n");
1499#endif
1500 return(NULL);
1501 }
1502
1503 if (name == NULL) {
1504#ifdef DEBUG_TREE
1505 xmlGenericError(xmlGenericErrorContext,
1506 "xmlNewTextChild : name == NULL\n");
1507#endif
1508 return(NULL);
1509 }
1510
1511 /*
1512 * Allocate a new node
1513 */
1514 if (ns == NULL)
1515 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1516 else
1517 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1518 if (cur == NULL) return(NULL);
1519
1520 /*
1521 * add the new element at the end of the children list.
1522 */
1523 cur->type = XML_ELEMENT_NODE;
1524 cur->parent = parent;
1525 cur->doc = parent->doc;
1526 if (parent->children == NULL) {
1527 parent->children = cur;
1528 parent->last = cur;
1529 } else {
1530 prev = parent->last;
1531 prev->next = cur;
1532 cur->prev = prev;
1533 parent->last = cur;
1534 }
1535
1536 return(cur);
1537}
1538
1539/**
1540 * xmlNewCharRef:
1541 * @doc: the document
1542 * @name: the char ref string, starting with # or "&# ... ;"
1543 *
1544 * Creation of a new character reference node.
1545 * Returns a pointer to the new node object.
1546 */
1547xmlNodePtr
1548xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1549 xmlNodePtr cur;
1550
1551 /*
1552 * Allocate a new node and fill the fields.
1553 */
1554 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1555 if (cur == NULL) {
1556 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001557 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001558 return(NULL);
1559 }
1560 memset(cur, 0, sizeof(xmlNode));
1561 cur->type = XML_ENTITY_REF_NODE;
1562
1563 cur->doc = doc;
1564 if (name[0] == '&') {
1565 int len;
1566 name++;
1567 len = xmlStrlen(name);
1568 if (name[len - 1] == ';')
1569 cur->name = xmlStrndup(name, len - 1);
1570 else
1571 cur->name = xmlStrndup(name, len);
1572 } else
1573 cur->name = xmlStrdup(name);
1574 return(cur);
1575}
1576
1577/**
1578 * xmlNewReference:
1579 * @doc: the document
1580 * @name: the reference name, or the reference string with & and ;
1581 *
1582 * Creation of a new reference node.
1583 * Returns a pointer to the new node object.
1584 */
1585xmlNodePtr
1586xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1587 xmlNodePtr cur;
1588 xmlEntityPtr ent;
1589
1590 /*
1591 * Allocate a new node and fill the fields.
1592 */
1593 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1594 if (cur == NULL) {
1595 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001596 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001597 return(NULL);
1598 }
1599 memset(cur, 0, sizeof(xmlNode));
1600 cur->type = XML_ENTITY_REF_NODE;
1601
1602 cur->doc = doc;
1603 if (name[0] == '&') {
1604 int len;
1605 name++;
1606 len = xmlStrlen(name);
1607 if (name[len - 1] == ';')
1608 cur->name = xmlStrndup(name, len - 1);
1609 else
1610 cur->name = xmlStrndup(name, len);
1611 } else
1612 cur->name = xmlStrdup(name);
1613
1614 ent = xmlGetDocEntity(doc, cur->name);
1615 if (ent != NULL) {
1616#ifndef XML_USE_BUFFER_CONTENT
1617 cur->content = ent->content;
1618#else
1619 /*
1620 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1621 * a copy of this pointer. Let's hope we don't manipulate it
1622 * later
1623 */
1624 cur->content = xmlBufferCreateSize(0);
1625 xmlBufferSetAllocationScheme(cur->content,
1626 xmlGetBufferAllocationScheme());
1627 if (ent->content != NULL)
1628 xmlBufferAdd(cur->content, ent->content, -1);
1629#endif
1630 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001631 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001632 * updated. Not sure if this is 100% correct.
1633 * -George
1634 */
1635 cur->children = (xmlNodePtr) ent;
1636 cur->last = (xmlNodePtr) ent;
1637 }
1638 return(cur);
1639}
1640
1641/**
1642 * xmlNewDocText:
1643 * @doc: the document
1644 * @content: the text content
1645 *
1646 * Creation of a new text node within a document.
1647 * Returns a pointer to the new node object.
1648 */
1649xmlNodePtr
1650xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1651 xmlNodePtr cur;
1652
1653 cur = xmlNewText(content);
1654 if (cur != NULL) cur->doc = doc;
1655 return(cur);
1656}
1657
1658/**
1659 * xmlNewTextLen:
1660 * @content: the text content
1661 * @len: the text len.
1662 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001663 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001664 * Returns a pointer to the new node object.
1665 */
1666xmlNodePtr
1667xmlNewTextLen(const xmlChar *content, int len) {
1668 xmlNodePtr cur;
1669
1670 /*
1671 * Allocate a new node and fill the fields.
1672 */
1673 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1674 if (cur == NULL) {
1675 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001676 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001677 return(NULL);
1678 }
1679 memset(cur, 0, sizeof(xmlNode));
1680 cur->type = XML_TEXT_NODE;
1681
1682 cur->name = xmlStringText;
1683 if (content != NULL) {
1684#ifndef XML_USE_BUFFER_CONTENT
1685 cur->content = xmlStrndup(content, len);
1686#else
1687 cur->content = xmlBufferCreateSize(len);
1688 xmlBufferSetAllocationScheme(cur->content,
1689 xmlGetBufferAllocationScheme());
1690 xmlBufferAdd(cur->content, content, len);
1691#endif
1692 }
1693 return(cur);
1694}
1695
1696/**
1697 * xmlNewDocTextLen:
1698 * @doc: the document
1699 * @content: the text content
1700 * @len: the text len.
1701 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001702 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001703 * text node pertain to a given document.
1704 * Returns a pointer to the new node object.
1705 */
1706xmlNodePtr
1707xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1708 xmlNodePtr cur;
1709
1710 cur = xmlNewTextLen(content, len);
1711 if (cur != NULL) cur->doc = doc;
1712 return(cur);
1713}
1714
1715/**
1716 * xmlNewComment:
1717 * @content: the comment content
1718 *
1719 * Creation of a new node containing a comment.
1720 * Returns a pointer to the new node object.
1721 */
1722xmlNodePtr
1723xmlNewComment(const xmlChar *content) {
1724 xmlNodePtr cur;
1725
1726 /*
1727 * Allocate a new node and fill the fields.
1728 */
1729 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1730 if (cur == NULL) {
1731 xmlGenericError(xmlGenericErrorContext,
1732 "xmlNewComment : malloc failed\n");
1733 return(NULL);
1734 }
1735 memset(cur, 0, sizeof(xmlNode));
1736 cur->type = XML_COMMENT_NODE;
1737
1738 cur->name = xmlStringComment;
1739 if (content != NULL) {
1740#ifndef XML_USE_BUFFER_CONTENT
1741 cur->content = xmlStrdup(content);
1742#else
1743 cur->content = xmlBufferCreateSize(0);
1744 xmlBufferSetAllocationScheme(cur->content,
1745 xmlGetBufferAllocationScheme());
1746 xmlBufferAdd(cur->content, content, -1);
1747#endif
1748 }
1749 return(cur);
1750}
1751
1752/**
1753 * xmlNewCDataBlock:
1754 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001755 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001756 * @len: the length of the block
1757 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001758 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001759 * Returns a pointer to the new node object.
1760 */
1761xmlNodePtr
1762xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1763 xmlNodePtr cur;
1764
1765 /*
1766 * Allocate a new node and fill the fields.
1767 */
1768 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1769 if (cur == NULL) {
1770 xmlGenericError(xmlGenericErrorContext,
1771 "xmlNewCDataBlock : malloc failed\n");
1772 return(NULL);
1773 }
1774 memset(cur, 0, sizeof(xmlNode));
1775 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001776 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001777
1778 if (content != NULL) {
1779#ifndef XML_USE_BUFFER_CONTENT
1780 cur->content = xmlStrndup(content, len);
1781#else
1782 cur->content = xmlBufferCreateSize(len);
1783 xmlBufferSetAllocationScheme(cur->content,
1784 xmlGetBufferAllocationScheme());
1785 xmlBufferAdd(cur->content, content, len);
1786#endif
1787 }
1788 return(cur);
1789}
1790
1791/**
1792 * xmlNewDocComment:
1793 * @doc: the document
1794 * @content: the comment content
1795 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001796 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001797 * Returns a pointer to the new node object.
1798 */
1799xmlNodePtr
1800xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1801 xmlNodePtr cur;
1802
1803 cur = xmlNewComment(content);
1804 if (cur != NULL) cur->doc = doc;
1805 return(cur);
1806}
1807
1808/**
1809 * xmlSetTreeDoc:
1810 * @tree: the top element
1811 * @doc: the document
1812 *
1813 * update all nodes under the tree to point to the right document
1814 */
1815void
1816xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001817 xmlAttrPtr prop;
1818
Owen Taylor3473f882001-02-23 17:55:21 +00001819 if (tree == NULL)
1820 return;
1821 if (tree->type == XML_ENTITY_DECL)
1822 return;
1823 if (tree->doc != doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001824 prop = tree->properties;
1825 while (prop != NULL) {
1826 prop->doc = doc;
1827 xmlSetListDoc(prop->children, doc);
1828 prop = prop->next;
1829 }
Owen Taylor3473f882001-02-23 17:55:21 +00001830 if (tree->children != NULL)
1831 xmlSetListDoc(tree->children, doc);
1832 tree->doc = doc;
1833 }
1834}
1835
1836/**
1837 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001838 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001839 * @doc: the document
1840 *
1841 * update all nodes in the list to point to the right document
1842 */
1843void
1844xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1845 xmlNodePtr cur;
1846
1847 if (list == NULL)
1848 return;
1849 cur = list;
1850 while (cur != NULL) {
1851 if (cur->doc != doc)
1852 xmlSetTreeDoc(cur, doc);
1853 cur = cur->next;
1854 }
1855}
1856
1857
1858/**
1859 * xmlNewChild:
1860 * @parent: the parent node
1861 * @ns: a namespace if any
1862 * @name: the name of the child
1863 * @content: the XML content of the child if any.
1864 *
1865 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001866 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001867 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1868 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1869 * references, but XML special chars need to be escaped first by using
1870 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1871 * support is not needed.
1872 *
1873 * Returns a pointer to the new node object.
1874 */
1875xmlNodePtr
1876xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1877 const xmlChar *name, const xmlChar *content) {
1878 xmlNodePtr cur, prev;
1879
1880 if (parent == NULL) {
1881#ifdef DEBUG_TREE
1882 xmlGenericError(xmlGenericErrorContext,
1883 "xmlNewChild : parent == NULL\n");
1884#endif
1885 return(NULL);
1886 }
1887
1888 if (name == NULL) {
1889#ifdef DEBUG_TREE
1890 xmlGenericError(xmlGenericErrorContext,
1891 "xmlNewChild : name == NULL\n");
1892#endif
1893 return(NULL);
1894 }
1895
1896 /*
1897 * Allocate a new node
1898 */
1899 if (ns == NULL)
1900 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1901 else
1902 cur = xmlNewDocNode(parent->doc, ns, name, content);
1903 if (cur == NULL) return(NULL);
1904
1905 /*
1906 * add the new element at the end of the children list.
1907 */
1908 cur->type = XML_ELEMENT_NODE;
1909 cur->parent = parent;
1910 cur->doc = parent->doc;
1911 if (parent->children == NULL) {
1912 parent->children = cur;
1913 parent->last = cur;
1914 } else {
1915 prev = parent->last;
1916 prev->next = cur;
1917 cur->prev = prev;
1918 parent->last = cur;
1919 }
1920
1921 return(cur);
1922}
1923
1924/**
1925 * xmlAddNextSibling:
1926 * @cur: the child node
1927 * @elem: the new node
1928 *
1929 * Add a new element @elem as the next siblings of @cur
1930 * If the new element was already inserted in a document it is
1931 * first unlinked from its existing context.
1932 * As a result of text merging @elem may be freed.
1933 *
1934 * Returns the new element or NULL in case of error.
1935 */
1936xmlNodePtr
1937xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1938 if (cur == NULL) {
1939#ifdef DEBUG_TREE
1940 xmlGenericError(xmlGenericErrorContext,
1941 "xmlAddNextSibling : cur == NULL\n");
1942#endif
1943 return(NULL);
1944 }
1945 if (elem == NULL) {
1946#ifdef DEBUG_TREE
1947 xmlGenericError(xmlGenericErrorContext,
1948 "xmlAddNextSibling : elem == NULL\n");
1949#endif
1950 return(NULL);
1951 }
1952
1953 xmlUnlinkNode(elem);
1954
1955 if (elem->type == XML_TEXT_NODE) {
1956 if (cur->type == XML_TEXT_NODE) {
1957#ifndef XML_USE_BUFFER_CONTENT
1958 xmlNodeAddContent(cur, elem->content);
1959#else
1960 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1961#endif
1962 xmlFreeNode(elem);
1963 return(cur);
1964 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001965 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1966 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001967#ifndef XML_USE_BUFFER_CONTENT
1968 xmlChar *tmp;
1969
1970 tmp = xmlStrdup(elem->content);
1971 tmp = xmlStrcat(tmp, cur->next->content);
1972 xmlNodeSetContent(cur->next, tmp);
1973 xmlFree(tmp);
1974#else
1975 xmlBufferAddHead(cur->next->content,
1976 xmlBufferContent(elem->content),
1977 xmlBufferLength(elem->content));
1978#endif
1979 xmlFreeNode(elem);
1980 return(cur->next);
1981 }
1982 }
1983
1984 if (elem->doc != cur->doc) {
1985 xmlSetTreeDoc(elem, cur->doc);
1986 }
1987 elem->parent = cur->parent;
1988 elem->prev = cur;
1989 elem->next = cur->next;
1990 cur->next = elem;
1991 if (elem->next != NULL)
1992 elem->next->prev = elem;
1993 if ((elem->parent != NULL) && (elem->parent->last == cur))
1994 elem->parent->last = elem;
1995 return(elem);
1996}
1997
1998/**
1999 * xmlAddPrevSibling:
2000 * @cur: the child node
2001 * @elem: the new node
2002 *
2003 * Add a new element @elem as the previous siblings of @cur
2004 * merging adjacent TEXT nodes (@elem may be freed)
2005 * If the new element was already inserted in a document it is
2006 * first unlinked from its existing context.
2007 *
2008 * Returns the new element or NULL in case of error.
2009 */
2010xmlNodePtr
2011xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2012 if (cur == NULL) {
2013#ifdef DEBUG_TREE
2014 xmlGenericError(xmlGenericErrorContext,
2015 "xmlAddPrevSibling : cur == NULL\n");
2016#endif
2017 return(NULL);
2018 }
2019 if (elem == NULL) {
2020#ifdef DEBUG_TREE
2021 xmlGenericError(xmlGenericErrorContext,
2022 "xmlAddPrevSibling : elem == NULL\n");
2023#endif
2024 return(NULL);
2025 }
2026
2027 xmlUnlinkNode(elem);
2028
2029 if (elem->type == XML_TEXT_NODE) {
2030 if (cur->type == XML_TEXT_NODE) {
2031#ifndef XML_USE_BUFFER_CONTENT
2032 xmlChar *tmp;
2033
2034 tmp = xmlStrdup(elem->content);
2035 tmp = xmlStrcat(tmp, cur->content);
2036 xmlNodeSetContent(cur, tmp);
2037 xmlFree(tmp);
2038#else
2039 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
2040 xmlBufferLength(elem->content));
2041#endif
2042 xmlFreeNode(elem);
2043 return(cur);
2044 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002045 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2046 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002047#ifndef XML_USE_BUFFER_CONTENT
2048 xmlNodeAddContent(cur->prev, elem->content);
2049#else
2050 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
2051#endif
2052 xmlFreeNode(elem);
2053 return(cur->prev);
2054 }
2055 }
2056
2057 if (elem->doc != cur->doc) {
2058 xmlSetTreeDoc(elem, cur->doc);
2059 }
2060 elem->parent = cur->parent;
2061 elem->next = cur;
2062 elem->prev = cur->prev;
2063 cur->prev = elem;
2064 if (elem->prev != NULL)
2065 elem->prev->next = elem;
2066 if ((elem->parent != NULL) && (elem->parent->children == cur))
2067 elem->parent->children = elem;
2068 return(elem);
2069}
2070
2071/**
2072 * xmlAddSibling:
2073 * @cur: the child node
2074 * @elem: the new node
2075 *
2076 * Add a new element @elem to the list of siblings of @cur
2077 * merging adjacent TEXT nodes (@elem may be freed)
2078 * If the new element was already inserted in a document it is
2079 * first unlinked from its existing context.
2080 *
2081 * Returns the new element or NULL in case of error.
2082 */
2083xmlNodePtr
2084xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2085 xmlNodePtr parent;
2086
2087 if (cur == NULL) {
2088#ifdef DEBUG_TREE
2089 xmlGenericError(xmlGenericErrorContext,
2090 "xmlAddSibling : cur == NULL\n");
2091#endif
2092 return(NULL);
2093 }
2094
2095 if (elem == NULL) {
2096#ifdef DEBUG_TREE
2097 xmlGenericError(xmlGenericErrorContext,
2098 "xmlAddSibling : elem == NULL\n");
2099#endif
2100 return(NULL);
2101 }
2102
2103 /*
2104 * Constant time is we can rely on the ->parent->last to find
2105 * the last sibling.
2106 */
2107 if ((cur->parent != NULL) &&
2108 (cur->parent->children != NULL) &&
2109 (cur->parent->last != NULL) &&
2110 (cur->parent->last->next == NULL)) {
2111 cur = cur->parent->last;
2112 } else {
2113 while (cur->next != NULL) cur = cur->next;
2114 }
2115
2116 xmlUnlinkNode(elem);
2117
2118 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2119#ifndef XML_USE_BUFFER_CONTENT
2120 xmlNodeAddContent(cur, elem->content);
2121#else
2122 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2123#endif
2124 xmlFreeNode(elem);
2125 return(cur);
2126 }
2127
2128 if (elem->doc != cur->doc) {
2129 xmlSetTreeDoc(elem, cur->doc);
2130 }
2131 parent = cur->parent;
2132 elem->prev = cur;
2133 elem->next = NULL;
2134 elem->parent = parent;
2135 cur->next = elem;
2136 if (parent != NULL)
2137 parent->last = elem;
2138
2139 return(elem);
2140}
2141
2142/**
2143 * xmlAddChildList:
2144 * @parent: the parent node
2145 * @cur: the first node in the list
2146 *
2147 * Add a list of node at the end of the child list of the parent
2148 * merging adjacent TEXT nodes (@cur may be freed)
2149 *
2150 * Returns the last child or NULL in case of error.
2151 */
2152xmlNodePtr
2153xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2154 xmlNodePtr prev;
2155
2156 if (parent == NULL) {
2157#ifdef DEBUG_TREE
2158 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002159 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002160#endif
2161 return(NULL);
2162 }
2163
2164 if (cur == NULL) {
2165#ifdef DEBUG_TREE
2166 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002167 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002168#endif
2169 return(NULL);
2170 }
2171
2172 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2173 (cur->doc != parent->doc)) {
2174#ifdef DEBUG_TREE
2175 xmlGenericError(xmlGenericErrorContext,
2176 "Elements moved to a different document\n");
2177#endif
2178 }
2179
2180 /*
2181 * add the first element at the end of the children list.
2182 */
2183 if (parent->children == NULL) {
2184 parent->children = cur;
2185 } else {
2186 /*
2187 * If cur and parent->last both are TEXT nodes, then merge them.
2188 */
2189 if ((cur->type == XML_TEXT_NODE) &&
2190 (parent->last->type == XML_TEXT_NODE) &&
2191 (cur->name == parent->last->name)) {
2192#ifndef XML_USE_BUFFER_CONTENT
2193 xmlNodeAddContent(parent->last, cur->content);
2194#else
2195 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2196#endif
2197 /*
2198 * if it's the only child, nothing more to be done.
2199 */
2200 if (cur->next == NULL) {
2201 xmlFreeNode(cur);
2202 return(parent->last);
2203 }
2204 prev = cur;
2205 cur = cur->next;
2206 xmlFreeNode(prev);
2207 }
2208 prev = parent->last;
2209 prev->next = cur;
2210 cur->prev = prev;
2211 }
2212 while (cur->next != NULL) {
2213 cur->parent = parent;
2214 if (cur->doc != parent->doc) {
2215 xmlSetTreeDoc(cur, parent->doc);
2216 }
2217 cur = cur->next;
2218 }
2219 cur->parent = parent;
2220 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2221 parent->last = cur;
2222
2223 return(cur);
2224}
2225
2226/**
2227 * xmlAddChild:
2228 * @parent: the parent node
2229 * @cur: the child node
2230 *
2231 * Add a new child element, to @parent, at the end of the child list
2232 * merging adjacent TEXT nodes (in which case @cur is freed)
2233 * Returns the child or NULL in case of error.
2234 */
2235xmlNodePtr
2236xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2237 xmlNodePtr prev;
2238
2239 if (parent == NULL) {
2240#ifdef DEBUG_TREE
2241 xmlGenericError(xmlGenericErrorContext,
2242 "xmlAddChild : parent == NULL\n");
2243#endif
2244 return(NULL);
2245 }
2246
2247 if (cur == NULL) {
2248#ifdef DEBUG_TREE
2249 xmlGenericError(xmlGenericErrorContext,
2250 "xmlAddChild : child == NULL\n");
2251#endif
2252 return(NULL);
2253 }
2254
Owen Taylor3473f882001-02-23 17:55:21 +00002255 /*
2256 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002257 * cur is then freed.
2258 */
2259 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002260 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002261 (parent->content != NULL)) {
2262#ifndef XML_USE_BUFFER_CONTENT
2263 xmlNodeAddContent(parent, cur->content);
2264#else
2265 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2266#endif
2267 xmlFreeNode(cur);
2268 return(parent);
2269 }
2270 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2271 (parent->last->name == cur->name)) {
2272#ifndef XML_USE_BUFFER_CONTENT
2273 xmlNodeAddContent(parent->last, cur->content);
2274#else
2275 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2276#endif
2277 xmlFreeNode(cur);
2278 return(parent->last);
2279 }
2280 }
2281
2282 /*
2283 * add the new element at the end of the children list.
2284 */
2285 cur->parent = parent;
2286 if (cur->doc != parent->doc) {
2287 xmlSetTreeDoc(cur, parent->doc);
2288 }
2289
2290 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002291 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002292 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002293 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002294 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002295#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002296 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002297#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002298 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00002299#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002300 xmlFreeNode(cur);
2301 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002302 }
2303 if (parent->children == NULL) {
2304 parent->children = cur;
2305 parent->last = cur;
2306 } else {
2307 prev = parent->last;
2308 prev->next = cur;
2309 cur->prev = prev;
2310 parent->last = cur;
2311 }
2312
2313 return(cur);
2314}
2315
2316/**
2317 * xmlGetLastChild:
2318 * @parent: the parent node
2319 *
2320 * Search the last child of a node.
2321 * Returns the last child or NULL if none.
2322 */
2323xmlNodePtr
2324xmlGetLastChild(xmlNodePtr parent) {
2325 if (parent == NULL) {
2326#ifdef DEBUG_TREE
2327 xmlGenericError(xmlGenericErrorContext,
2328 "xmlGetLastChild : parent == NULL\n");
2329#endif
2330 return(NULL);
2331 }
2332 return(parent->last);
2333}
2334
2335/**
2336 * xmlFreeNodeList:
2337 * @cur: the first node in the list
2338 *
2339 * Free a node and all its siblings, this is a recursive behaviour, all
2340 * the children are freed too.
2341 */
2342void
2343xmlFreeNodeList(xmlNodePtr cur) {
2344 xmlNodePtr next;
2345 if (cur == NULL) {
2346#ifdef DEBUG_TREE
2347 xmlGenericError(xmlGenericErrorContext,
2348 "xmlFreeNodeList : node == NULL\n");
2349#endif
2350 return;
2351 }
2352 while (cur != NULL) {
2353 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002354 /* unroll to speed up freeing the document */
2355 if (cur->type != XML_DTD_NODE) {
2356 if ((cur->children != NULL) &&
2357 (cur->type != XML_ENTITY_REF_NODE))
2358 xmlFreeNodeList(cur->children);
2359 if (cur->properties != NULL)
2360 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002361 if ((cur->type != XML_ELEMENT_NODE) &&
2362 (cur->type != XML_XINCLUDE_START) &&
2363 (cur->type != XML_XINCLUDE_END) &&
2364 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002365#ifndef XML_USE_BUFFER_CONTENT
2366 if (cur->content != NULL) xmlFree(cur->content);
2367#else
2368 if (cur->content != NULL) xmlBufferFree(cur->content);
2369#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002370 }
2371 if (((cur->type == XML_ELEMENT_NODE) ||
2372 (cur->type == XML_XINCLUDE_START) ||
2373 (cur->type == XML_XINCLUDE_END)) &&
2374 (cur->nsDef != NULL))
2375 xmlFreeNsList(cur->nsDef);
2376
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002377 /*
2378 * When a node is a text node or a comment, it uses a global static
2379 * variable for the name of the node.
2380 *
2381 * The xmlStrEqual comparisons need to be done when (happened with
2382 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002383 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002384 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002385 * the string addresses compare are not sufficient.
2386 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002387 if ((cur->name != NULL) &&
2388 (cur->name != xmlStringText) &&
2389 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002390 (cur->name != xmlStringComment)) {
2391 if (cur->type == XML_TEXT_NODE) {
2392 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2393 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2394 xmlFree((char *) cur->name);
2395 } else if (cur->type == XML_COMMENT_NODE) {
2396 if (!xmlStrEqual(cur->name, xmlStringComment))
2397 xmlFree((char *) cur->name);
2398 } else
2399 xmlFree((char *) cur->name);
2400 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002401 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002402 xmlFree(cur);
2403 }
Owen Taylor3473f882001-02-23 17:55:21 +00002404 cur = next;
2405 }
2406}
2407
2408/**
2409 * xmlFreeNode:
2410 * @cur: the node
2411 *
2412 * Free a node, this is a recursive behaviour, all the children are freed too.
2413 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2414 */
2415void
2416xmlFreeNode(xmlNodePtr cur) {
2417 if (cur == NULL) {
2418#ifdef DEBUG_TREE
2419 xmlGenericError(xmlGenericErrorContext,
2420 "xmlFreeNode : node == NULL\n");
2421#endif
2422 return;
2423 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002424 /* use xmlFreeDtd for DTD nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00002425 if (cur->type == XML_DTD_NODE)
2426 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002427 if ((cur->children != NULL) &&
2428 (cur->type != XML_ENTITY_REF_NODE))
2429 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002430 if (cur->properties != NULL)
2431 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002432 if ((cur->type != XML_ELEMENT_NODE) &&
2433 (cur->content != NULL) &&
2434 (cur->type != XML_ENTITY_REF_NODE) &&
2435 (cur->type != XML_XINCLUDE_END) &&
2436 (cur->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002437#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard7db37732001-07-12 01:20:08 +00002438 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002439#else
Daniel Veillard7db37732001-07-12 01:20:08 +00002440 xmlBufferFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002441#endif
Daniel Veillard7db37732001-07-12 01:20:08 +00002442 }
2443
Daniel Veillardacd370f2001-06-09 17:17:51 +00002444 /*
2445 * When a node is a text node or a comment, it uses a global static
2446 * variable for the name of the node.
2447 *
2448 * The xmlStrEqual comparisons need to be done when (happened with
2449 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002450 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002451 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002452 * are not sufficient.
2453 */
Owen Taylor3473f882001-02-23 17:55:21 +00002454 if ((cur->name != NULL) &&
2455 (cur->name != xmlStringText) &&
2456 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002457 (cur->name != xmlStringComment)) {
2458 if (cur->type == XML_TEXT_NODE) {
2459 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2460 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2461 xmlFree((char *) cur->name);
2462 } else if (cur->type == XML_COMMENT_NODE) {
2463 if (!xmlStrEqual(cur->name, xmlStringComment))
2464 xmlFree((char *) cur->name);
2465 } else
2466 xmlFree((char *) cur->name);
2467 }
2468
Owen Taylor3473f882001-02-23 17:55:21 +00002469 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002470 xmlFree(cur);
2471}
2472
2473/**
2474 * xmlUnlinkNode:
2475 * @cur: the node
2476 *
2477 * Unlink a node from it's current context, the node is not freed
2478 */
2479void
2480xmlUnlinkNode(xmlNodePtr cur) {
2481 if (cur == NULL) {
2482#ifdef DEBUG_TREE
2483 xmlGenericError(xmlGenericErrorContext,
2484 "xmlUnlinkNode : node == NULL\n");
2485#endif
2486 return;
2487 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002488 if (cur->type == XML_DTD_NODE) {
2489 xmlDocPtr doc;
2490 doc = cur->doc;
2491 if (doc->intSubset == (xmlDtdPtr) cur)
2492 doc->intSubset = NULL;
2493 if (doc->extSubset == (xmlDtdPtr) cur)
2494 doc->extSubset = NULL;
2495 }
Owen Taylor3473f882001-02-23 17:55:21 +00002496 if ((cur->parent != NULL) && (cur->parent->children == cur))
2497 cur->parent->children = cur->next;
2498 if ((cur->parent != NULL) && (cur->parent->last == cur))
2499 cur->parent->last = cur->prev;
2500 if (cur->next != NULL)
2501 cur->next->prev = cur->prev;
2502 if (cur->prev != NULL)
2503 cur->prev->next = cur->next;
2504 cur->next = cur->prev = NULL;
2505 cur->parent = NULL;
2506}
2507
2508/**
2509 * xmlReplaceNode:
2510 * @old: the old node
2511 * @cur: the node
2512 *
2513 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002514 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002515 * first unlinked from its existing context.
2516 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002517 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002518 */
2519xmlNodePtr
2520xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2521 if (old == NULL) {
2522#ifdef DEBUG_TREE
2523 xmlGenericError(xmlGenericErrorContext,
2524 "xmlReplaceNode : old == NULL\n");
2525#endif
2526 return(NULL);
2527 }
2528 if (cur == NULL) {
2529 xmlUnlinkNode(old);
2530 return(old);
2531 }
2532 if (cur == old) {
2533 return(old);
2534 }
2535 xmlUnlinkNode(cur);
2536 cur->doc = old->doc;
2537 cur->parent = old->parent;
2538 cur->next = old->next;
2539 if (cur->next != NULL)
2540 cur->next->prev = cur;
2541 cur->prev = old->prev;
2542 if (cur->prev != NULL)
2543 cur->prev->next = cur;
2544 if (cur->parent != NULL) {
2545 if (cur->parent->children == old)
2546 cur->parent->children = cur;
2547 if (cur->parent->last == old)
2548 cur->parent->last = cur;
2549 }
2550 old->next = old->prev = NULL;
2551 old->parent = NULL;
2552 return(old);
2553}
2554
2555/************************************************************************
2556 * *
2557 * Copy operations *
2558 * *
2559 ************************************************************************/
2560
2561/**
2562 * xmlCopyNamespace:
2563 * @cur: the namespace
2564 *
2565 * Do a copy of the namespace.
2566 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002567 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002568 */
2569xmlNsPtr
2570xmlCopyNamespace(xmlNsPtr cur) {
2571 xmlNsPtr ret;
2572
2573 if (cur == NULL) return(NULL);
2574 switch (cur->type) {
2575 case XML_LOCAL_NAMESPACE:
2576 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2577 break;
2578 default:
2579#ifdef DEBUG_TREE
2580 xmlGenericError(xmlGenericErrorContext,
2581 "xmlCopyNamespace: invalid type %d\n", cur->type);
2582#endif
2583 return(NULL);
2584 }
2585 return(ret);
2586}
2587
2588/**
2589 * xmlCopyNamespaceList:
2590 * @cur: the first namespace
2591 *
2592 * Do a copy of an namespace list.
2593 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002594 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002595 */
2596xmlNsPtr
2597xmlCopyNamespaceList(xmlNsPtr cur) {
2598 xmlNsPtr ret = NULL;
2599 xmlNsPtr p = NULL,q;
2600
2601 while (cur != NULL) {
2602 q = xmlCopyNamespace(cur);
2603 if (p == NULL) {
2604 ret = p = q;
2605 } else {
2606 p->next = q;
2607 p = q;
2608 }
2609 cur = cur->next;
2610 }
2611 return(ret);
2612}
2613
2614static xmlNodePtr
2615xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2616/**
2617 * xmlCopyProp:
2618 * @target: the element where the attribute will be grafted
2619 * @cur: the attribute
2620 *
2621 * Do a copy of the attribute.
2622 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002623 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002624 */
2625xmlAttrPtr
2626xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2627 xmlAttrPtr ret;
2628
2629 if (cur == NULL) return(NULL);
2630 if (target != NULL)
2631 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2632 else if (cur->parent != NULL)
2633 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2634 else if (cur->children != NULL)
2635 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2636 else
2637 ret = xmlNewDocProp(NULL, cur->name, NULL);
2638 if (ret == NULL) return(NULL);
2639 ret->parent = target;
2640
2641 if ((cur->ns != NULL) && (target != NULL)) {
2642 xmlNsPtr ns;
2643
2644 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2645 ret->ns = ns;
2646 } else
2647 ret->ns = NULL;
2648
2649 if (cur->children != NULL) {
2650 xmlNodePtr tmp;
2651
2652 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2653 ret->last = NULL;
2654 tmp = ret->children;
2655 while (tmp != NULL) {
2656 /* tmp->parent = (xmlNodePtr)ret; */
2657 if (tmp->next == NULL)
2658 ret->last = tmp;
2659 tmp = tmp->next;
2660 }
2661 }
2662 return(ret);
2663}
2664
2665/**
2666 * xmlCopyPropList:
2667 * @target: the element where the attributes will be grafted
2668 * @cur: the first attribute
2669 *
2670 * Do a copy of an attribute list.
2671 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002672 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002673 */
2674xmlAttrPtr
2675xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2676 xmlAttrPtr ret = NULL;
2677 xmlAttrPtr p = NULL,q;
2678
2679 while (cur != NULL) {
2680 q = xmlCopyProp(target, cur);
2681 if (p == NULL) {
2682 ret = p = q;
2683 } else {
2684 p->next = q;
2685 q->prev = p;
2686 p = q;
2687 }
2688 cur = cur->next;
2689 }
2690 return(ret);
2691}
2692
2693/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002694 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002695 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002696 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002697 * tricky reason: namespaces. Doing a direct copy of a node
2698 * say RPM:Copyright without changing the namespace pointer to
2699 * something else can produce stale links. One way to do it is
2700 * to keep a reference counter but this doesn't work as soon
2701 * as one move the element or the subtree out of the scope of
2702 * the existing namespace. The actual solution seems to add
2703 * a copy of the namespace at the top of the copied tree if
2704 * not available in the subtree.
2705 * Hence two functions, the public front-end call the inner ones
2706 */
2707
2708static xmlNodePtr
2709xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2710
2711static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002712xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002713 int recursive) {
2714 xmlNodePtr ret;
2715
2716 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002717 switch (node->type) {
2718 case XML_TEXT_NODE:
2719 case XML_CDATA_SECTION_NODE:
2720 case XML_ELEMENT_NODE:
2721 case XML_ENTITY_REF_NODE:
2722 case XML_ENTITY_NODE:
2723 case XML_PI_NODE:
2724 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002725 case XML_XINCLUDE_START:
2726 case XML_XINCLUDE_END:
2727 break;
2728 case XML_ATTRIBUTE_NODE:
2729 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2730 case XML_NAMESPACE_DECL:
2731 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2732
Daniel Veillard39196eb2001-06-19 18:09:42 +00002733 case XML_DOCUMENT_NODE:
2734 case XML_HTML_DOCUMENT_NODE:
2735#ifdef LIBXML_DOCB_ENABLED
2736 case XML_DOCB_DOCUMENT_NODE:
2737#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002738 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002739 case XML_DOCUMENT_TYPE_NODE:
2740 case XML_DOCUMENT_FRAG_NODE:
2741 case XML_NOTATION_NODE:
2742 case XML_DTD_NODE:
2743 case XML_ELEMENT_DECL:
2744 case XML_ATTRIBUTE_DECL:
2745 case XML_ENTITY_DECL:
2746 return(NULL);
2747 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002748
Owen Taylor3473f882001-02-23 17:55:21 +00002749 /*
2750 * Allocate a new node and fill the fields.
2751 */
2752 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2753 if (ret == NULL) {
2754 xmlGenericError(xmlGenericErrorContext,
2755 "xmlStaticCopyNode : malloc failed\n");
2756 return(NULL);
2757 }
2758 memset(ret, 0, sizeof(xmlNode));
2759 ret->type = node->type;
2760
2761 ret->doc = doc;
2762 ret->parent = parent;
2763 if (node->name == xmlStringText)
2764 ret->name = xmlStringText;
2765 else if (node->name == xmlStringTextNoenc)
2766 ret->name = xmlStringTextNoenc;
2767 else if (node->name == xmlStringComment)
2768 ret->name = xmlStringComment;
2769 else if (node->name != NULL)
2770 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002771 if ((node->type != XML_ELEMENT_NODE) &&
2772 (node->content != NULL) &&
2773 (node->type != XML_ENTITY_REF_NODE) &&
2774 (node->type != XML_XINCLUDE_END) &&
2775 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002776#ifndef XML_USE_BUFFER_CONTENT
2777 ret->content = xmlStrdup(node->content);
2778#else
2779 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2780 xmlBufferSetAllocationScheme(ret->content,
2781 xmlGetBufferAllocationScheme());
2782 xmlBufferAdd(ret->content,
2783 xmlBufferContent(node->content),
2784 xmlBufferLength(node->content));
2785#endif
2786 }
2787 if (parent != NULL)
2788 xmlAddChild(parent, ret);
2789
2790 if (!recursive) return(ret);
2791 if (node->nsDef != NULL)
2792 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2793
2794 if (node->ns != NULL) {
2795 xmlNsPtr ns;
2796
2797 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2798 if (ns == NULL) {
2799 /*
2800 * Humm, we are copying an element whose namespace is defined
2801 * out of the new tree scope. Search it in the original tree
2802 * and add it at the top of the new tree
2803 */
2804 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2805 if (ns != NULL) {
2806 xmlNodePtr root = ret;
2807
2808 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002809 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002810 }
2811 } else {
2812 /*
2813 * reference the existing namespace definition in our own tree.
2814 */
2815 ret->ns = ns;
2816 }
2817 }
2818 if (node->properties != NULL)
2819 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002820 if (node->type == XML_ENTITY_REF_NODE) {
2821 if ((doc == NULL) || (node->doc != doc)) {
2822 /*
2823 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002824 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002825 * we cannot keep the reference. Try to find it in the
2826 * target document.
2827 */
2828 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2829 } else {
2830 ret->children = node->children;
2831 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002832 ret->last = ret->children;
2833 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002834 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002835 UPDATE_LAST_CHILD_AND_PARENT(ret)
2836 }
Owen Taylor3473f882001-02-23 17:55:21 +00002837 return(ret);
2838}
2839
2840static xmlNodePtr
2841xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2842 xmlNodePtr ret = NULL;
2843 xmlNodePtr p = NULL,q;
2844
2845 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002846 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002847 if (doc == NULL) {
2848 node = node->next;
2849 continue;
2850 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002851 if (doc->intSubset == NULL) {
2852 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2853 q->doc = doc;
2854 q->parent = parent;
2855 doc->intSubset = (xmlDtdPtr) q;
2856 } else {
2857 q = (xmlNodePtr) doc->intSubset;
2858 }
2859 } else
2860 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002861 if (ret == NULL) {
2862 q->prev = NULL;
2863 ret = p = q;
2864 } else {
2865 p->next = q;
2866 q->prev = p;
2867 p = q;
2868 }
2869 node = node->next;
2870 }
2871 return(ret);
2872}
2873
2874/**
2875 * xmlCopyNode:
2876 * @node: the node
2877 * @recursive: if 1 do a recursive copy.
2878 *
2879 * Do a copy of the node.
2880 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002881 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002882 */
2883xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002884xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00002885 xmlNodePtr ret;
2886
2887 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2888 return(ret);
2889}
2890
2891/**
Daniel Veillard82daa812001-04-12 08:55:36 +00002892 * xmlDocCopyNode:
2893 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00002894 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00002895 * @recursive: if 1 do a recursive copy.
2896 *
2897 * Do a copy of the node to a given document.
2898 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002899 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00002900 */
2901xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002902xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00002903 xmlNodePtr ret;
2904
2905 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
2906 return(ret);
2907}
2908
2909/**
Owen Taylor3473f882001-02-23 17:55:21 +00002910 * xmlCopyNodeList:
2911 * @node: the first node in the list.
2912 *
2913 * Do a recursive copy of the node list.
2914 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002915 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002916 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002917xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002918 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2919 return(ret);
2920}
2921
2922/**
Owen Taylor3473f882001-02-23 17:55:21 +00002923 * xmlCopyDtd:
2924 * @dtd: the dtd
2925 *
2926 * Do a copy of the dtd.
2927 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002928 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002929 */
2930xmlDtdPtr
2931xmlCopyDtd(xmlDtdPtr dtd) {
2932 xmlDtdPtr ret;
2933
2934 if (dtd == NULL) return(NULL);
2935 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2936 if (ret == NULL) return(NULL);
2937 if (dtd->entities != NULL)
2938 ret->entities = (void *) xmlCopyEntitiesTable(
2939 (xmlEntitiesTablePtr) dtd->entities);
2940 if (dtd->notations != NULL)
2941 ret->notations = (void *) xmlCopyNotationTable(
2942 (xmlNotationTablePtr) dtd->notations);
2943 if (dtd->elements != NULL)
2944 ret->elements = (void *) xmlCopyElementTable(
2945 (xmlElementTablePtr) dtd->elements);
2946 if (dtd->attributes != NULL)
2947 ret->attributes = (void *) xmlCopyAttributeTable(
2948 (xmlAttributeTablePtr) dtd->attributes);
2949 return(ret);
2950}
2951
2952/**
2953 * xmlCopyDoc:
2954 * @doc: the document
2955 * @recursive: if 1 do a recursive copy.
2956 *
2957 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002958 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00002959 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002960 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002961 */
2962xmlDocPtr
2963xmlCopyDoc(xmlDocPtr doc, int recursive) {
2964 xmlDocPtr ret;
2965
2966 if (doc == NULL) return(NULL);
2967 ret = xmlNewDoc(doc->version);
2968 if (ret == NULL) return(NULL);
2969 if (doc->name != NULL)
2970 ret->name = xmlMemStrdup(doc->name);
2971 if (doc->encoding != NULL)
2972 ret->encoding = xmlStrdup(doc->encoding);
2973 ret->charset = doc->charset;
2974 ret->compression = doc->compression;
2975 ret->standalone = doc->standalone;
2976 if (!recursive) return(ret);
2977
Daniel Veillardb33c2012001-04-25 12:59:04 +00002978 ret->last = NULL;
2979 ret->children = NULL;
2980 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002981 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002982 ret->intSubset->doc = ret;
2983 ret->intSubset->parent = ret;
2984 }
Owen Taylor3473f882001-02-23 17:55:21 +00002985 if (doc->oldNs != NULL)
2986 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
2987 if (doc->children != NULL) {
2988 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00002989
2990 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2991 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002992 ret->last = NULL;
2993 tmp = ret->children;
2994 while (tmp != NULL) {
2995 if (tmp->next == NULL)
2996 ret->last = tmp;
2997 tmp = tmp->next;
2998 }
2999 }
3000 return(ret);
3001}
3002
3003/************************************************************************
3004 * *
3005 * Content access functions *
3006 * *
3007 ************************************************************************/
3008
3009/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003010 * xmlGetLineNo:
3011 * @node : valid node
3012 *
3013 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003014 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003015 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003016 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003017 */
3018long
3019xmlGetLineNo(xmlNodePtr node)
3020{
3021 long result = -1;
3022
3023 if (!node)
3024 return result;
3025 if (node->type == XML_ELEMENT_NODE)
3026 result = (long) node->content;
3027 else if ((node->prev != NULL) &&
3028 ((node->prev->type == XML_ELEMENT_NODE) ||
3029 (node->prev->type == XML_TEXT_NODE)))
3030 result = xmlGetLineNo(node->prev);
3031 else if ((node->parent != NULL) &&
3032 ((node->parent->type == XML_ELEMENT_NODE) ||
3033 (node->parent->type == XML_TEXT_NODE)))
3034 result = xmlGetLineNo(node->parent);
3035
3036 return result;
3037}
3038
3039/**
3040 * xmlGetNodePath:
3041 * @node: a node
3042 *
3043 * Build a structure based Path for the given node
3044 *
3045 * Returns the new path or NULL in case of error. The caller must free
3046 * the returned string
3047 */
3048xmlChar *
3049xmlGetNodePath(xmlNodePtr node)
3050{
3051 xmlNodePtr cur, tmp, next;
3052 xmlChar *buffer = NULL, *temp;
3053 size_t buf_len;
3054 xmlChar *buf;
3055 char sep;
3056 const char *name;
3057 char nametemp[100];
3058 int occur = 0;
3059
3060 if (node == NULL)
3061 return (NULL);
3062
3063 buf_len = 500;
3064 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3065 if (buffer == NULL)
3066 return (NULL);
3067 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3068 if (buf == NULL) {
3069 xmlFree(buffer);
3070 return (NULL);
3071 }
3072
3073 buffer[0] = 0;
3074 cur = node;
3075 do {
3076 name = "";
3077 sep = '?';
3078 occur = 0;
3079 if ((cur->type == XML_DOCUMENT_NODE) ||
3080 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3081 if (buffer[0] == '/')
3082 break;
3083 sep = '/';
3084 next = NULL;
3085 } else if (cur->type == XML_ELEMENT_NODE) {
3086 sep = '/';
3087 name = (const char *) cur->name;
3088 if (cur->ns) {
3089 snprintf(nametemp, sizeof(nametemp) - 1,
3090 "%s:%s", cur->ns->prefix, cur->name);
3091 nametemp[sizeof(nametemp) - 1] = 0;
3092 name = nametemp;
3093 }
3094 next = cur->parent;
3095
3096 /*
3097 * Thumbler index computation
3098 */
3099 tmp = cur->prev;
3100 while (tmp != NULL) {
3101 if (xmlStrEqual(cur->name, tmp->name))
3102 occur++;
3103 tmp = tmp->prev;
3104 }
3105 if (occur == 0) {
3106 tmp = cur->next;
3107 while (tmp != NULL) {
3108 if (xmlStrEqual(cur->name, tmp->name))
3109 occur++;
3110 tmp = tmp->next;
3111 }
3112 if (occur != 0)
3113 occur = 1;
3114 } else
3115 occur++;
3116 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3117 sep = '@';
3118 name = (const char *) (((xmlAttrPtr) cur)->name);
3119 next = ((xmlAttrPtr) cur)->parent;
3120 } else {
3121 next = cur->parent;
3122 }
3123
3124 /*
3125 * Make sure there is enough room
3126 */
3127 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3128 buf_len =
3129 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3130 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3131 if (temp == NULL) {
3132 xmlFree(buf);
3133 xmlFree(buffer);
3134 return (NULL);
3135 }
3136 buffer = temp;
3137 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3138 if (temp == NULL) {
3139 xmlFree(buf);
3140 xmlFree(buffer);
3141 return (NULL);
3142 }
3143 buf = temp;
3144 }
3145 if (occur == 0)
3146 snprintf((char *) buf, buf_len, "%c%s%s",
3147 sep, name, (char *) buffer);
3148 else
3149 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3150 sep, name, occur, (char *) buffer);
3151 snprintf((char *) buffer, buf_len, "%s", buf);
3152 cur = next;
3153 } while (cur != NULL);
3154 xmlFree(buf);
3155 return (buffer);
3156}
3157
3158/**
Owen Taylor3473f882001-02-23 17:55:21 +00003159 * xmlDocGetRootElement:
3160 * @doc: the document
3161 *
3162 * Get the root element of the document (doc->children is a list
3163 * containing possibly comments, PIs, etc ...).
3164 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003165 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003166 */
3167xmlNodePtr
3168xmlDocGetRootElement(xmlDocPtr doc) {
3169 xmlNodePtr ret;
3170
3171 if (doc == NULL) return(NULL);
3172 ret = doc->children;
3173 while (ret != NULL) {
3174 if (ret->type == XML_ELEMENT_NODE)
3175 return(ret);
3176 ret = ret->next;
3177 }
3178 return(ret);
3179}
3180
3181/**
3182 * xmlDocSetRootElement:
3183 * @doc: the document
3184 * @root: the new document root element
3185 *
3186 * Set the root element of the document (doc->children is a list
3187 * containing possibly comments, PIs, etc ...).
3188 *
3189 * Returns the old root element if any was found
3190 */
3191xmlNodePtr
3192xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3193 xmlNodePtr old = NULL;
3194
3195 if (doc == NULL) return(NULL);
3196 old = doc->children;
3197 while (old != NULL) {
3198 if (old->type == XML_ELEMENT_NODE)
3199 break;
3200 old = old->next;
3201 }
3202 if (old == NULL) {
3203 if (doc->children == NULL) {
3204 doc->children = root;
3205 doc->last = root;
3206 } else {
3207 xmlAddSibling(doc->children, root);
3208 }
3209 } else {
3210 xmlReplaceNode(old, root);
3211 }
3212 return(old);
3213}
3214
3215/**
3216 * xmlNodeSetLang:
3217 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003218 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003219 *
3220 * Set the language of a node, i.e. the values of the xml:lang
3221 * attribute.
3222 */
3223void
3224xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
3225 if (cur == NULL) return;
3226 switch(cur->type) {
3227 case XML_TEXT_NODE:
3228 case XML_CDATA_SECTION_NODE:
3229 case XML_COMMENT_NODE:
3230 case XML_DOCUMENT_NODE:
3231 case XML_DOCUMENT_TYPE_NODE:
3232 case XML_DOCUMENT_FRAG_NODE:
3233 case XML_NOTATION_NODE:
3234 case XML_HTML_DOCUMENT_NODE:
3235 case XML_DTD_NODE:
3236 case XML_ELEMENT_DECL:
3237 case XML_ATTRIBUTE_DECL:
3238 case XML_ENTITY_DECL:
3239 case XML_PI_NODE:
3240 case XML_ENTITY_REF_NODE:
3241 case XML_ENTITY_NODE:
3242 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003243#ifdef LIBXML_DOCB_ENABLED
3244 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003245#endif
3246 case XML_XINCLUDE_START:
3247 case XML_XINCLUDE_END:
3248 return;
3249 case XML_ELEMENT_NODE:
3250 case XML_ATTRIBUTE_NODE:
3251 break;
3252 }
3253 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
3254}
3255
3256/**
3257 * xmlNodeGetLang:
3258 * @cur: the node being checked
3259 *
3260 * Searches the language of a node, i.e. the values of the xml:lang
3261 * attribute or the one carried by the nearest ancestor.
3262 *
3263 * Returns a pointer to the lang value, or NULL if not found
3264 * It's up to the caller to free the memory.
3265 */
3266xmlChar *
3267xmlNodeGetLang(xmlNodePtr cur) {
3268 xmlChar *lang;
3269
3270 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003271 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003272 if (lang != NULL)
3273 return(lang);
3274 cur = cur->parent;
3275 }
3276 return(NULL);
3277}
3278
3279
3280/**
3281 * xmlNodeSetSpacePreserve:
3282 * @cur: the node being changed
3283 * @val: the xml:space value ("0": default, 1: "preserve")
3284 *
3285 * Set (or reset) the space preserving behaviour of a node, i.e. the
3286 * value of the xml:space attribute.
3287 */
3288void
3289xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
3290 if (cur == NULL) return;
3291 switch(cur->type) {
3292 case XML_TEXT_NODE:
3293 case XML_CDATA_SECTION_NODE:
3294 case XML_COMMENT_NODE:
3295 case XML_DOCUMENT_NODE:
3296 case XML_DOCUMENT_TYPE_NODE:
3297 case XML_DOCUMENT_FRAG_NODE:
3298 case XML_NOTATION_NODE:
3299 case XML_HTML_DOCUMENT_NODE:
3300 case XML_DTD_NODE:
3301 case XML_ELEMENT_DECL:
3302 case XML_ATTRIBUTE_DECL:
3303 case XML_ENTITY_DECL:
3304 case XML_PI_NODE:
3305 case XML_ENTITY_REF_NODE:
3306 case XML_ENTITY_NODE:
3307 case XML_NAMESPACE_DECL:
3308 case XML_XINCLUDE_START:
3309 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003310#ifdef LIBXML_DOCB_ENABLED
3311 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003312#endif
3313 return;
3314 case XML_ELEMENT_NODE:
3315 case XML_ATTRIBUTE_NODE:
3316 break;
3317 }
3318 switch (val) {
3319 case 0:
3320 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
3321 break;
3322 case 1:
3323 xmlSetProp(cur, BAD_CAST "xml:space",
3324 BAD_CAST "preserve");
3325 break;
3326 }
3327}
3328
3329/**
3330 * xmlNodeGetSpacePreserve:
3331 * @cur: the node being checked
3332 *
3333 * Searches the space preserving behaviour of a node, i.e. the values
3334 * of the xml:space attribute or the one carried by the nearest
3335 * ancestor.
3336 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003337 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003338 */
3339int
3340xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3341 xmlChar *space;
3342
3343 while (cur != NULL) {
3344 space = xmlGetProp(cur, BAD_CAST "xml:space");
3345 if (space != NULL) {
3346 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3347 xmlFree(space);
3348 return(1);
3349 }
3350 if (xmlStrEqual(space, BAD_CAST "default")) {
3351 xmlFree(space);
3352 return(0);
3353 }
3354 xmlFree(space);
3355 }
3356 cur = cur->parent;
3357 }
3358 return(-1);
3359}
3360
3361/**
3362 * xmlNodeSetName:
3363 * @cur: the node being changed
3364 * @name: the new tag name
3365 *
3366 * Set (or reset) the name of a node.
3367 */
3368void
3369xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3370 if (cur == NULL) return;
3371 if (name == NULL) return;
3372 switch(cur->type) {
3373 case XML_TEXT_NODE:
3374 case XML_CDATA_SECTION_NODE:
3375 case XML_COMMENT_NODE:
3376 case XML_DOCUMENT_TYPE_NODE:
3377 case XML_DOCUMENT_FRAG_NODE:
3378 case XML_NOTATION_NODE:
3379 case XML_HTML_DOCUMENT_NODE:
3380 case XML_NAMESPACE_DECL:
3381 case XML_XINCLUDE_START:
3382 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003383#ifdef LIBXML_DOCB_ENABLED
3384 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003385#endif
3386 return;
3387 case XML_ELEMENT_NODE:
3388 case XML_ATTRIBUTE_NODE:
3389 case XML_PI_NODE:
3390 case XML_ENTITY_REF_NODE:
3391 case XML_ENTITY_NODE:
3392 case XML_DTD_NODE:
3393 case XML_DOCUMENT_NODE:
3394 case XML_ELEMENT_DECL:
3395 case XML_ATTRIBUTE_DECL:
3396 case XML_ENTITY_DECL:
3397 break;
3398 }
3399 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3400 cur->name = xmlStrdup(name);
3401}
3402
3403/**
3404 * xmlNodeSetBase:
3405 * @cur: the node being changed
3406 * @uri: the new base URI
3407 *
3408 * Set (or reset) the base URI of a node, i.e. the value of the
3409 * xml:base attribute.
3410 */
3411void
3412xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3413 if (cur == NULL) return;
3414 switch(cur->type) {
3415 case XML_TEXT_NODE:
3416 case XML_CDATA_SECTION_NODE:
3417 case XML_COMMENT_NODE:
3418 case XML_DOCUMENT_NODE:
3419 case XML_DOCUMENT_TYPE_NODE:
3420 case XML_DOCUMENT_FRAG_NODE:
3421 case XML_NOTATION_NODE:
3422 case XML_HTML_DOCUMENT_NODE:
3423 case XML_DTD_NODE:
3424 case XML_ELEMENT_DECL:
3425 case XML_ATTRIBUTE_DECL:
3426 case XML_ENTITY_DECL:
3427 case XML_PI_NODE:
3428 case XML_ENTITY_REF_NODE:
3429 case XML_ENTITY_NODE:
3430 case XML_NAMESPACE_DECL:
3431 case XML_XINCLUDE_START:
3432 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003433#ifdef LIBXML_DOCB_ENABLED
3434 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003435#endif
3436 return;
3437 case XML_ELEMENT_NODE:
3438 case XML_ATTRIBUTE_NODE:
3439 break;
3440 }
3441 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3442}
3443
3444/**
Owen Taylor3473f882001-02-23 17:55:21 +00003445 * xmlNodeGetBase:
3446 * @doc: the document the node pertains to
3447 * @cur: the node being checked
3448 *
3449 * Searches for the BASE URL. The code should work on both XML
3450 * and HTML document even if base mechanisms are completely different.
3451 * It returns the base as defined in RFC 2396 sections
3452 * 5.1.1. Base URI within Document Content
3453 * and
3454 * 5.1.2. Base URI from the Encapsulating Entity
3455 * However it does not return the document base (5.1.3), use
3456 * xmlDocumentGetBase() for this
3457 *
3458 * Returns a pointer to the base URL, or NULL if not found
3459 * It's up to the caller to free the memory.
3460 */
3461xmlChar *
3462xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003463 xmlChar *oldbase = NULL;
3464 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003465
3466 if ((cur == NULL) && (doc == NULL))
3467 return(NULL);
3468 if (doc == NULL) doc = cur->doc;
3469 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3470 cur = doc->children;
3471 while ((cur != NULL) && (cur->name != NULL)) {
3472 if (cur->type != XML_ELEMENT_NODE) {
3473 cur = cur->next;
3474 continue;
3475 }
3476 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3477 cur = cur->children;
3478 continue;
3479 }
3480 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3481 cur = cur->children;
3482 continue;
3483 }
3484 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3485 return(xmlGetProp(cur, BAD_CAST "href"));
3486 }
3487 cur = cur->next;
3488 }
3489 return(NULL);
3490 }
3491 while (cur != NULL) {
3492 if (cur->type == XML_ENTITY_DECL) {
3493 xmlEntityPtr ent = (xmlEntityPtr) cur;
3494 return(xmlStrdup(ent->URI));
3495 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003496 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003497 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003498 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003499 if (oldbase != NULL) {
3500 newbase = xmlBuildURI(oldbase, base);
3501 if (newbase != NULL) {
3502 xmlFree(oldbase);
3503 xmlFree(base);
3504 oldbase = newbase;
3505 } else {
3506 xmlFree(oldbase);
3507 xmlFree(base);
3508 return(NULL);
3509 }
3510 } else {
3511 oldbase = base;
3512 }
3513 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3514 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3515 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3516 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003517 }
3518 }
Owen Taylor3473f882001-02-23 17:55:21 +00003519 cur = cur->parent;
3520 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003521 if ((doc != NULL) && (doc->URL != NULL)) {
3522 if (oldbase == NULL)
3523 return(xmlStrdup(doc->URL));
3524 newbase = xmlBuildURI(oldbase, doc->URL);
3525 xmlFree(oldbase);
3526 return(newbase);
3527 }
3528 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003529}
3530
3531/**
3532 * xmlNodeGetContent:
3533 * @cur: the node being read
3534 *
3535 * Read the value of a node, this can be either the text carried
3536 * directly by this node if it's a TEXT node or the aggregate string
3537 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003538 * Entity references are substituted.
3539 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003540 * It's up to the caller to free the memory.
3541 */
3542xmlChar *
3543xmlNodeGetContent(xmlNodePtr cur) {
3544 if (cur == NULL) return(NULL);
3545 switch (cur->type) {
3546 case XML_DOCUMENT_FRAG_NODE:
3547 case XML_ELEMENT_NODE: {
3548 xmlNodePtr tmp = cur;
3549 xmlBufferPtr buffer;
3550 xmlChar *ret;
3551
3552 buffer = xmlBufferCreate();
3553 if (buffer == NULL)
3554 return(NULL);
3555 while (tmp != NULL) {
3556 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003557 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003558 case XML_TEXT_NODE:
3559 if (tmp->content != NULL)
3560#ifndef XML_USE_BUFFER_CONTENT
3561 xmlBufferCat(buffer, tmp->content);
3562#else
3563 xmlBufferCat(buffer,
3564 xmlBufferContent(tmp->content));
3565#endif
3566 break;
3567 case XML_ENTITY_REF_NODE: {
3568 xmlEntityPtr ent;
3569
3570 ent = xmlGetDocEntity(cur->doc, tmp->name);
3571 if (ent != NULL)
3572 xmlBufferCat(buffer, ent->content);
3573 }
3574 default:
3575 break;
3576 }
3577 /*
3578 * Skip to next node
3579 */
3580 if (tmp->children != NULL) {
3581 if (tmp->children->type != XML_ENTITY_DECL) {
3582 tmp = tmp->children;
3583 continue;
3584 }
3585 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003586 if (tmp == cur)
3587 break;
3588
Owen Taylor3473f882001-02-23 17:55:21 +00003589 if (tmp->next != NULL) {
3590 tmp = tmp->next;
3591 continue;
3592 }
3593
3594 do {
3595 tmp = tmp->parent;
3596 if (tmp == NULL)
3597 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003598 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003599 tmp = NULL;
3600 break;
3601 }
3602 if (tmp->next != NULL) {
3603 tmp = tmp->next;
3604 break;
3605 }
3606 } while (tmp != NULL);
3607 }
3608 ret = buffer->content;
3609 buffer->content = NULL;
3610 xmlBufferFree(buffer);
3611 return(ret);
3612 }
3613 case XML_ATTRIBUTE_NODE: {
3614 xmlAttrPtr attr = (xmlAttrPtr) cur;
3615 if (attr->parent != NULL)
3616 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3617 else
3618 return(xmlNodeListGetString(NULL, attr->children, 1));
3619 break;
3620 }
3621 case XML_COMMENT_NODE:
3622 case XML_PI_NODE:
3623 if (cur->content != NULL)
3624#ifndef XML_USE_BUFFER_CONTENT
3625 return(xmlStrdup(cur->content));
3626#else
3627 return(xmlStrdup(xmlBufferContent(cur->content)));
3628#endif
3629 return(NULL);
3630 case XML_ENTITY_REF_NODE:
3631 /*
3632 * Locate the entity, and get it's content
3633 * @@@
3634 */
3635 return(NULL);
3636 case XML_ENTITY_NODE:
3637 case XML_DOCUMENT_NODE:
3638 case XML_HTML_DOCUMENT_NODE:
3639 case XML_DOCUMENT_TYPE_NODE:
3640 case XML_NOTATION_NODE:
3641 case XML_DTD_NODE:
3642 case XML_XINCLUDE_START:
3643 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003644#ifdef LIBXML_DOCB_ENABLED
3645 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003646#endif
3647 return(NULL);
3648 case XML_NAMESPACE_DECL:
3649 return(xmlStrdup(((xmlNsPtr)cur)->href));
3650 case XML_ELEMENT_DECL:
3651 /* TODO !!! */
3652 return(NULL);
3653 case XML_ATTRIBUTE_DECL:
3654 /* TODO !!! */
3655 return(NULL);
3656 case XML_ENTITY_DECL:
3657 /* TODO !!! */
3658 return(NULL);
3659 case XML_CDATA_SECTION_NODE:
3660 case XML_TEXT_NODE:
3661 if (cur->content != NULL)
3662#ifndef XML_USE_BUFFER_CONTENT
3663 return(xmlStrdup(cur->content));
3664#else
3665 return(xmlStrdup(xmlBufferContent(cur->content)));
3666#endif
3667 return(NULL);
3668 }
3669 return(NULL);
3670}
3671
3672/**
3673 * xmlNodeSetContent:
3674 * @cur: the node being modified
3675 * @content: the new value of the content
3676 *
3677 * Replace the content of a node.
3678 */
3679void
3680xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3681 if (cur == NULL) {
3682#ifdef DEBUG_TREE
3683 xmlGenericError(xmlGenericErrorContext,
3684 "xmlNodeSetContent : node == NULL\n");
3685#endif
3686 return;
3687 }
3688 switch (cur->type) {
3689 case XML_DOCUMENT_FRAG_NODE:
3690 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003691 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3692 cur->children = xmlStringGetNodeList(cur->doc, content);
3693 UPDATE_LAST_CHILD_AND_PARENT(cur)
3694 break;
3695 case XML_ATTRIBUTE_NODE:
3696 break;
3697 case XML_TEXT_NODE:
3698 case XML_CDATA_SECTION_NODE:
3699 case XML_ENTITY_REF_NODE:
3700 case XML_ENTITY_NODE:
3701 case XML_PI_NODE:
3702 case XML_COMMENT_NODE:
3703 if (cur->content != NULL) {
3704#ifndef XML_USE_BUFFER_CONTENT
3705 xmlFree(cur->content);
3706#else
3707 xmlBufferFree(cur->content);
3708#endif
3709 }
3710 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3711 cur->last = cur->children = NULL;
3712 if (content != NULL) {
3713#ifndef XML_USE_BUFFER_CONTENT
3714 cur->content = xmlStrdup(content);
3715#else
3716 cur->content = xmlBufferCreateSize(0);
3717 xmlBufferSetAllocationScheme(cur->content,
3718 xmlGetBufferAllocationScheme());
3719 xmlBufferAdd(cur->content, content, -1);
3720#endif
3721 } else
3722 cur->content = NULL;
3723 break;
3724 case XML_DOCUMENT_NODE:
3725 case XML_HTML_DOCUMENT_NODE:
3726 case XML_DOCUMENT_TYPE_NODE:
3727 case XML_XINCLUDE_START:
3728 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003729#ifdef LIBXML_DOCB_ENABLED
3730 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003731#endif
3732 break;
3733 case XML_NOTATION_NODE:
3734 break;
3735 case XML_DTD_NODE:
3736 break;
3737 case XML_NAMESPACE_DECL:
3738 break;
3739 case XML_ELEMENT_DECL:
3740 /* TODO !!! */
3741 break;
3742 case XML_ATTRIBUTE_DECL:
3743 /* TODO !!! */
3744 break;
3745 case XML_ENTITY_DECL:
3746 /* TODO !!! */
3747 break;
3748 }
3749}
3750
3751/**
3752 * xmlNodeSetContentLen:
3753 * @cur: the node being modified
3754 * @content: the new value of the content
3755 * @len: the size of @content
3756 *
3757 * Replace the content of a node.
3758 */
3759void
3760xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3761 if (cur == NULL) {
3762#ifdef DEBUG_TREE
3763 xmlGenericError(xmlGenericErrorContext,
3764 "xmlNodeSetContentLen : node == NULL\n");
3765#endif
3766 return;
3767 }
3768 switch (cur->type) {
3769 case XML_DOCUMENT_FRAG_NODE:
3770 case XML_ELEMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003771 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3772 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3773 UPDATE_LAST_CHILD_AND_PARENT(cur)
3774 break;
3775 case XML_ATTRIBUTE_NODE:
3776 break;
3777 case XML_TEXT_NODE:
3778 case XML_CDATA_SECTION_NODE:
3779 case XML_ENTITY_REF_NODE:
3780 case XML_ENTITY_NODE:
3781 case XML_PI_NODE:
3782 case XML_COMMENT_NODE:
3783 case XML_NOTATION_NODE:
3784 if (cur->content != NULL) {
3785#ifndef XML_USE_BUFFER_CONTENT
3786 xmlFree(cur->content);
3787#else
3788 xmlBufferFree(cur->content);
3789#endif
3790 }
3791 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3792 cur->children = cur->last = NULL;
3793 if (content != NULL) {
3794#ifndef XML_USE_BUFFER_CONTENT
3795 cur->content = xmlStrndup(content, len);
3796#else
3797 cur->content = xmlBufferCreateSize(len);
3798 xmlBufferSetAllocationScheme(cur->content,
3799 xmlGetBufferAllocationScheme());
3800 xmlBufferAdd(cur->content, content, len);
3801#endif
3802 } else
3803 cur->content = NULL;
3804 break;
3805 case XML_DOCUMENT_NODE:
3806 case XML_DTD_NODE:
3807 case XML_HTML_DOCUMENT_NODE:
3808 case XML_DOCUMENT_TYPE_NODE:
3809 case XML_NAMESPACE_DECL:
3810 case XML_XINCLUDE_START:
3811 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003812#ifdef LIBXML_DOCB_ENABLED
3813 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003814#endif
3815 break;
3816 case XML_ELEMENT_DECL:
3817 /* TODO !!! */
3818 break;
3819 case XML_ATTRIBUTE_DECL:
3820 /* TODO !!! */
3821 break;
3822 case XML_ENTITY_DECL:
3823 /* TODO !!! */
3824 break;
3825 }
3826}
3827
3828/**
3829 * xmlNodeAddContentLen:
3830 * @cur: the node being modified
3831 * @content: extra content
3832 * @len: the size of @content
3833 *
3834 * Append the extra substring to the node content.
3835 */
3836void
3837xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3838 if (cur == NULL) {
3839#ifdef DEBUG_TREE
3840 xmlGenericError(xmlGenericErrorContext,
3841 "xmlNodeAddContentLen : node == NULL\n");
3842#endif
3843 return;
3844 }
3845 if (len <= 0) return;
3846 switch (cur->type) {
3847 case XML_DOCUMENT_FRAG_NODE:
3848 case XML_ELEMENT_NODE: {
Daniel Veillard7db37732001-07-12 01:20:08 +00003849 xmlNodePtr last, newNode;
Owen Taylor3473f882001-02-23 17:55:21 +00003850
Daniel Veillard7db37732001-07-12 01:20:08 +00003851 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00003852 newNode = xmlNewTextLen(content, len);
3853 if (newNode != NULL) {
3854 xmlAddChild(cur, newNode);
3855 if ((last != NULL) && (last->next == newNode)) {
3856 xmlTextMerge(last, newNode);
3857 }
3858 }
3859 break;
3860 }
3861 case XML_ATTRIBUTE_NODE:
3862 break;
3863 case XML_TEXT_NODE:
3864 case XML_CDATA_SECTION_NODE:
3865 case XML_ENTITY_REF_NODE:
3866 case XML_ENTITY_NODE:
3867 case XML_PI_NODE:
3868 case XML_COMMENT_NODE:
3869 case XML_NOTATION_NODE:
3870 if (content != NULL) {
3871#ifndef XML_USE_BUFFER_CONTENT
3872 cur->content = xmlStrncat(cur->content, content, len);
3873#else
3874 xmlBufferAdd(cur->content, content, len);
3875#endif
3876 }
3877 case XML_DOCUMENT_NODE:
3878 case XML_DTD_NODE:
3879 case XML_HTML_DOCUMENT_NODE:
3880 case XML_DOCUMENT_TYPE_NODE:
3881 case XML_NAMESPACE_DECL:
3882 case XML_XINCLUDE_START:
3883 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003884#ifdef LIBXML_DOCB_ENABLED
3885 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003886#endif
3887 break;
3888 case XML_ELEMENT_DECL:
3889 case XML_ATTRIBUTE_DECL:
3890 case XML_ENTITY_DECL:
3891 break;
3892 }
3893}
3894
3895/**
3896 * xmlNodeAddContent:
3897 * @cur: the node being modified
3898 * @content: extra content
3899 *
3900 * Append the extra substring to the node content.
3901 */
3902void
3903xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
3904 int len;
3905
3906 if (cur == NULL) {
3907#ifdef DEBUG_TREE
3908 xmlGenericError(xmlGenericErrorContext,
3909 "xmlNodeAddContent : node == NULL\n");
3910#endif
3911 return;
3912 }
3913 if (content == NULL) return;
3914 len = xmlStrlen(content);
3915 xmlNodeAddContentLen(cur, content, len);
3916}
3917
3918/**
3919 * xmlTextMerge:
3920 * @first: the first text node
3921 * @second: the second text node being merged
3922 *
3923 * Merge two text nodes into one
3924 * Returns the first text node augmented
3925 */
3926xmlNodePtr
3927xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3928 if (first == NULL) return(second);
3929 if (second == NULL) return(first);
3930 if (first->type != XML_TEXT_NODE) return(first);
3931 if (second->type != XML_TEXT_NODE) return(first);
3932 if (second->name != first->name)
3933 return(first);
3934#ifndef XML_USE_BUFFER_CONTENT
3935 xmlNodeAddContent(first, second->content);
3936#else
3937 xmlNodeAddContent(first, xmlBufferContent(second->content));
3938#endif
3939 xmlUnlinkNode(second);
3940 xmlFreeNode(second);
3941 return(first);
3942}
3943
3944/**
3945 * xmlGetNsList:
3946 * @doc: the document
3947 * @node: the current node
3948 *
3949 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00003950 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00003951 * that need to be freed by the caller or NULL if no
3952 * namespace if defined
3953 */
3954xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00003955xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
3956{
Owen Taylor3473f882001-02-23 17:55:21 +00003957 xmlNsPtr cur;
3958 xmlNsPtr *ret = NULL;
3959 int nbns = 0;
3960 int maxns = 10;
3961 int i;
3962
3963 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00003964 if (node->type == XML_ELEMENT_NODE) {
3965 cur = node->nsDef;
3966 while (cur != NULL) {
3967 if (ret == NULL) {
3968 ret =
3969 (xmlNsPtr *) xmlMalloc((maxns + 1) *
3970 sizeof(xmlNsPtr));
3971 if (ret == NULL) {
3972 xmlGenericError(xmlGenericErrorContext,
3973 "xmlGetNsList : out of memory!\n");
3974 return (NULL);
3975 }
3976 ret[nbns] = NULL;
3977 }
3978 for (i = 0; i < nbns; i++) {
3979 if ((cur->prefix == ret[i]->prefix) ||
3980 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
3981 break;
3982 }
3983 if (i >= nbns) {
3984 if (nbns >= maxns) {
3985 maxns *= 2;
3986 ret = (xmlNsPtr *) xmlRealloc(ret,
3987 (maxns +
3988 1) *
3989 sizeof(xmlNsPtr));
3990 if (ret == NULL) {
3991 xmlGenericError(xmlGenericErrorContext,
3992 "xmlGetNsList : realloc failed!\n");
3993 return (NULL);
3994 }
3995 }
3996 ret[nbns++] = cur;
3997 ret[nbns] = NULL;
3998 }
Owen Taylor3473f882001-02-23 17:55:21 +00003999
Daniel Veillard77044732001-06-29 21:31:07 +00004000 cur = cur->next;
4001 }
4002 }
4003 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004004 }
Daniel Veillard77044732001-06-29 21:31:07 +00004005 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004006}
4007
4008/**
4009 * xmlSearchNs:
4010 * @doc: the document
4011 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004012 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004013 *
4014 * Search a Ns registered under a given name space for a document.
4015 * recurse on the parents until it finds the defined namespace
4016 * or return NULL otherwise.
4017 * @nameSpace can be NULL, this is a search for the default namespace.
4018 * We don't allow to cross entities boundaries. If you don't declare
4019 * the namespace within those you will be in troubles !!! A warning
4020 * is generated to cover this case.
4021 *
4022 * Returns the namespace pointer or NULL.
4023 */
4024xmlNsPtr
4025xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4026 xmlNsPtr cur;
4027
4028 if (node == NULL) return(NULL);
4029 if ((nameSpace != NULL) &&
4030 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
4031 if (doc->oldNs == NULL) {
4032 /*
4033 * Allocate a new Namespace and fill the fields.
4034 */
4035 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4036 if (doc->oldNs == NULL) {
4037 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004038 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004039 return(NULL);
4040 }
4041 memset(doc->oldNs, 0, sizeof(xmlNs));
4042 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4043
4044 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4045 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4046 }
4047 return(doc->oldNs);
4048 }
4049 while (node != NULL) {
4050 if ((node->type == XML_ENTITY_REF_NODE) ||
4051 (node->type == XML_ENTITY_NODE) ||
4052 (node->type == XML_ENTITY_DECL))
4053 return(NULL);
4054 if (node->type == XML_ELEMENT_NODE) {
4055 cur = node->nsDef;
4056 while (cur != NULL) {
4057 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4058 (cur->href != NULL))
4059 return(cur);
4060 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4061 (cur->href != NULL) &&
4062 (xmlStrEqual(cur->prefix, nameSpace)))
4063 return(cur);
4064 cur = cur->next;
4065 }
4066 }
4067 node = node->parent;
4068 }
4069 return(NULL);
4070}
4071
4072/**
4073 * xmlSearchNsByHref:
4074 * @doc: the document
4075 * @node: the current node
4076 * @href: the namespace value
4077 *
4078 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4079 * the defined namespace or return NULL otherwise.
4080 * Returns the namespace pointer or NULL.
4081 */
4082xmlNsPtr
4083xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4084 xmlNsPtr cur;
4085 xmlNodePtr orig = node;
4086
4087 if ((node == NULL) || (href == NULL)) return(NULL);
4088 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
4089 if (doc->oldNs == NULL) {
4090 /*
4091 * Allocate a new Namespace and fill the fields.
4092 */
4093 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4094 if (doc->oldNs == NULL) {
4095 xmlGenericError(xmlGenericErrorContext,
4096 "xmlSearchNsByHref : malloc failed\n");
4097 return(NULL);
4098 }
4099 memset(doc->oldNs, 0, sizeof(xmlNs));
4100 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4101
4102 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4103 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4104 }
4105 return(doc->oldNs);
4106 }
4107 while (node != NULL) {
4108 cur = node->nsDef;
4109 while (cur != NULL) {
4110 if ((cur->href != NULL) && (href != NULL) &&
4111 (xmlStrEqual(cur->href, href))) {
4112 /*
4113 * Check that the prefix is not shadowed between orig and node
4114 */
4115 xmlNodePtr check = orig;
4116 xmlNsPtr tst;
4117
4118 while (check != node) {
4119 tst = check->nsDef;
4120 while (tst != NULL) {
4121 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4122 goto shadowed;
4123 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4124 (xmlStrEqual(tst->prefix, cur->prefix)))
4125 goto shadowed;
4126 tst = tst->next;
4127 }
4128 check = check->parent;
4129 }
4130 return(cur);
4131 }
4132shadowed:
4133 cur = cur->next;
4134 }
4135 node = node->parent;
4136 }
4137 return(NULL);
4138}
4139
4140/**
4141 * xmlNewReconciliedNs
4142 * @doc: the document
4143 * @tree: a node expected to hold the new namespace
4144 * @ns: the original namespace
4145 *
4146 * This function tries to locate a namespace definition in a tree
4147 * ancestors, or create a new namespace definition node similar to
4148 * @ns trying to reuse the same prefix. However if the given prefix is
4149 * null (default namespace) or reused within the subtree defined by
4150 * @tree or on one of its ancestors then a new prefix is generated.
4151 * Returns the (new) namespace definition or NULL in case of error
4152 */
4153xmlNsPtr
4154xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4155 xmlNsPtr def;
4156 xmlChar prefix[50];
4157 int counter = 1;
4158
4159 if (tree == NULL) {
4160#ifdef DEBUG_TREE
4161 xmlGenericError(xmlGenericErrorContext,
4162 "xmlNewReconciliedNs : tree == NULL\n");
4163#endif
4164 return(NULL);
4165 }
4166 if (ns == NULL) {
4167#ifdef DEBUG_TREE
4168 xmlGenericError(xmlGenericErrorContext,
4169 "xmlNewReconciliedNs : ns == NULL\n");
4170#endif
4171 return(NULL);
4172 }
4173 /*
4174 * Search an existing namespace definition inherited.
4175 */
4176 def = xmlSearchNsByHref(doc, tree, ns->href);
4177 if (def != NULL)
4178 return(def);
4179
4180 /*
4181 * Find a close prefix which is not already in use.
4182 * Let's strip namespace prefixes longer than 20 chars !
4183 */
4184 sprintf((char *) prefix, "%.20s", ns->prefix);
4185 def = xmlSearchNs(doc, tree, prefix);
4186 while (def != NULL) {
4187 if (counter > 1000) return(NULL);
4188 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
4189 def = xmlSearchNs(doc, tree, prefix);
4190 }
4191
4192 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004193 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004194 */
4195 def = xmlNewNs(tree, ns->href, prefix);
4196 return(def);
4197}
4198
4199/**
4200 * xmlReconciliateNs
4201 * @doc: the document
4202 * @tree: a node defining the subtree to reconciliate
4203 *
4204 * This function checks that all the namespaces declared within the given
4205 * tree are properly declared. This is needed for example after Copy or Cut
4206 * and then paste operations. The subtree may still hold pointers to
4207 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004208 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004209 * the new environment. If not possible the new namespaces are redeclared
4210 * on @tree at the top of the given subtree.
4211 * Returns the number of namespace declarations created or -1 in case of error.
4212 */
4213int
4214xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4215 xmlNsPtr *oldNs = NULL;
4216 xmlNsPtr *newNs = NULL;
4217 int sizeCache = 0;
4218 int nbCache = 0;
4219
4220 xmlNsPtr n;
4221 xmlNodePtr node = tree;
4222 xmlAttrPtr attr;
4223 int ret = 0, i;
4224
4225 while (node != NULL) {
4226 /*
4227 * Reconciliate the node namespace
4228 */
4229 if (node->ns != NULL) {
4230 /*
4231 * initialize the cache if needed
4232 */
4233 if (sizeCache == 0) {
4234 sizeCache = 10;
4235 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4236 sizeof(xmlNsPtr));
4237 if (oldNs == NULL) {
4238 xmlGenericError(xmlGenericErrorContext,
4239 "xmlReconciliateNs : memory pbm\n");
4240 return(-1);
4241 }
4242 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4243 sizeof(xmlNsPtr));
4244 if (newNs == NULL) {
4245 xmlGenericError(xmlGenericErrorContext,
4246 "xmlReconciliateNs : memory pbm\n");
4247 xmlFree(oldNs);
4248 return(-1);
4249 }
4250 }
4251 for (i = 0;i < nbCache;i++) {
4252 if (oldNs[i] == node->ns) {
4253 node->ns = newNs[i];
4254 break;
4255 }
4256 }
4257 if (i == nbCache) {
4258 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004259 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004260 */
4261 n = xmlNewReconciliedNs(doc, tree, node->ns);
4262 if (n != NULL) { /* :-( what if else ??? */
4263 /*
4264 * check if we need to grow the cache buffers.
4265 */
4266 if (sizeCache <= nbCache) {
4267 sizeCache *= 2;
4268 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4269 sizeof(xmlNsPtr));
4270 if (oldNs == NULL) {
4271 xmlGenericError(xmlGenericErrorContext,
4272 "xmlReconciliateNs : memory pbm\n");
4273 xmlFree(newNs);
4274 return(-1);
4275 }
4276 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4277 sizeof(xmlNsPtr));
4278 if (newNs == NULL) {
4279 xmlGenericError(xmlGenericErrorContext,
4280 "xmlReconciliateNs : memory pbm\n");
4281 xmlFree(oldNs);
4282 return(-1);
4283 }
4284 }
4285 newNs[nbCache] = n;
4286 oldNs[nbCache++] = node->ns;
4287 node->ns = n;
4288 }
4289 }
4290 }
4291 /*
4292 * now check for namespace hold by attributes on the node.
4293 */
4294 attr = node->properties;
4295 while (attr != NULL) {
4296 if (attr->ns != NULL) {
4297 /*
4298 * initialize the cache if needed
4299 */
4300 if (sizeCache == 0) {
4301 sizeCache = 10;
4302 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4303 sizeof(xmlNsPtr));
4304 if (oldNs == NULL) {
4305 xmlGenericError(xmlGenericErrorContext,
4306 "xmlReconciliateNs : memory pbm\n");
4307 return(-1);
4308 }
4309 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4310 sizeof(xmlNsPtr));
4311 if (newNs == NULL) {
4312 xmlGenericError(xmlGenericErrorContext,
4313 "xmlReconciliateNs : memory pbm\n");
4314 xmlFree(oldNs);
4315 return(-1);
4316 }
4317 }
4318 for (i = 0;i < nbCache;i++) {
4319 if (oldNs[i] == attr->ns) {
4320 node->ns = newNs[i];
4321 break;
4322 }
4323 }
4324 if (i == nbCache) {
4325 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004326 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004327 */
4328 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4329 if (n != NULL) { /* :-( what if else ??? */
4330 /*
4331 * check if we need to grow the cache buffers.
4332 */
4333 if (sizeCache <= nbCache) {
4334 sizeCache *= 2;
4335 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4336 sizeof(xmlNsPtr));
4337 if (oldNs == NULL) {
4338 xmlGenericError(xmlGenericErrorContext,
4339 "xmlReconciliateNs : memory pbm\n");
4340 xmlFree(newNs);
4341 return(-1);
4342 }
4343 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4344 sizeof(xmlNsPtr));
4345 if (newNs == NULL) {
4346 xmlGenericError(xmlGenericErrorContext,
4347 "xmlReconciliateNs : memory pbm\n");
4348 xmlFree(oldNs);
4349 return(-1);
4350 }
4351 }
4352 newNs[nbCache] = n;
4353 oldNs[nbCache++] = attr->ns;
4354 attr->ns = n;
4355 }
4356 }
4357 }
4358 attr = attr->next;
4359 }
4360
4361 /*
4362 * Browse the full subtree, deep first
4363 */
4364 if (node->children != NULL) {
4365 /* deep first */
4366 node = node->children;
4367 } else if ((node != tree) && (node->next != NULL)) {
4368 /* then siblings */
4369 node = node->next;
4370 } else if (node != tree) {
4371 /* go up to parents->next if needed */
4372 while (node != tree) {
4373 if (node->parent != NULL)
4374 node = node->parent;
4375 if ((node != tree) && (node->next != NULL)) {
4376 node = node->next;
4377 break;
4378 }
4379 if (node->parent == NULL) {
4380 node = NULL;
4381 break;
4382 }
4383 }
4384 /* exit condition */
4385 if (node == tree)
4386 node = NULL;
4387 }
4388 }
4389 return(ret);
4390}
4391
4392/**
4393 * xmlHasProp:
4394 * @node: the node
4395 * @name: the attribute name
4396 *
4397 * Search an attribute associated to a node
4398 * This function also looks in DTD attribute declaration for #FIXED or
4399 * default declaration values unless DTD use has been turned off.
4400 *
4401 * Returns the attribute or the attribute declaration or NULL if
4402 * neither was found.
4403 */
4404xmlAttrPtr
4405xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4406 xmlAttrPtr prop;
4407 xmlDocPtr doc;
4408
4409 if ((node == NULL) || (name == NULL)) return(NULL);
4410 /*
4411 * Check on the properties attached to the node
4412 */
4413 prop = node->properties;
4414 while (prop != NULL) {
4415 if (xmlStrEqual(prop->name, name)) {
4416 return(prop);
4417 }
4418 prop = prop->next;
4419 }
4420 if (!xmlCheckDTD) return(NULL);
4421
4422 /*
4423 * Check if there is a default declaration in the internal
4424 * or external subsets
4425 */
4426 doc = node->doc;
4427 if (doc != NULL) {
4428 xmlAttributePtr attrDecl;
4429 if (doc->intSubset != NULL) {
4430 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4431 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4432 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4433 if (attrDecl != NULL)
4434 return((xmlAttrPtr) attrDecl);
4435 }
4436 }
4437 return(NULL);
4438}
4439
4440/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004441 * xmlHasNsProp:
4442 * @node: the node
4443 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004444 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004445 *
4446 * Search for an attribute associated to a node
4447 * This attribute has to be anchored in the namespace specified.
4448 * This does the entity substitution.
4449 * This function looks in DTD attribute declaration for #FIXED or
4450 * default declaration values unless DTD use has been turned off.
4451 *
4452 * Returns the attribute or the attribute declaration or NULL
4453 * if neither was found.
4454 */
4455xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004456xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004457 xmlAttrPtr prop;
4458 xmlDocPtr doc;
4459 xmlNsPtr ns;
4460
4461 if (node == NULL)
4462 return(NULL);
4463
4464 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004465 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004466 return(xmlHasProp(node, name));
4467 while (prop != NULL) {
4468 /*
4469 * One need to have
4470 * - same attribute names
4471 * - and the attribute carrying that namespace
4472 * or
4473 * no namespace on the attribute and the element carrying it
4474 */
4475 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004476 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4477 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004478 }
4479 prop = prop->next;
4480 }
4481 if (!xmlCheckDTD) return(NULL);
4482
4483 /*
4484 * Check if there is a default declaration in the internal
4485 * or external subsets
4486 */
4487 doc = node->doc;
4488 if (doc != NULL) {
4489 if (doc->intSubset != NULL) {
4490 xmlAttributePtr attrDecl;
4491
4492 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4493 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4494 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4495
4496 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4497 /*
4498 * The DTD declaration only allows a prefix search
4499 */
4500 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004501 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Daniel Veillarde95e2392001-06-06 10:46:28 +00004502 return((xmlAttrPtr) attrDecl);
4503 }
4504 }
4505 }
4506 return(NULL);
4507}
4508
4509/**
Owen Taylor3473f882001-02-23 17:55:21 +00004510 * xmlGetProp:
4511 * @node: the node
4512 * @name: the attribute name
4513 *
4514 * Search and get the value of an attribute associated to a node
4515 * This does the entity substitution.
4516 * This function looks in DTD attribute declaration for #FIXED or
4517 * default declaration values unless DTD use has been turned off.
4518 *
4519 * Returns the attribute value or NULL if not found.
4520 * It's up to the caller to free the memory.
4521 */
4522xmlChar *
4523xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4524 xmlAttrPtr prop;
4525 xmlDocPtr doc;
4526
4527 if ((node == NULL) || (name == NULL)) return(NULL);
4528 /*
4529 * Check on the properties attached to the node
4530 */
4531 prop = node->properties;
4532 while (prop != NULL) {
4533 if (xmlStrEqual(prop->name, name)) {
4534 xmlChar *ret;
4535
4536 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4537 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4538 return(ret);
4539 }
4540 prop = prop->next;
4541 }
4542 if (!xmlCheckDTD) return(NULL);
4543
4544 /*
4545 * Check if there is a default declaration in the internal
4546 * or external subsets
4547 */
4548 doc = node->doc;
4549 if (doc != NULL) {
4550 xmlAttributePtr attrDecl;
4551 if (doc->intSubset != NULL) {
4552 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4553 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4554 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4555 if (attrDecl != NULL)
4556 return(xmlStrdup(attrDecl->defaultValue));
4557 }
4558 }
4559 return(NULL);
4560}
4561
4562/**
4563 * xmlGetNsProp:
4564 * @node: the node
4565 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004566 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004567 *
4568 * Search and get the value of an attribute associated to a node
4569 * This attribute has to be anchored in the namespace specified.
4570 * This does the entity substitution.
4571 * This function looks in DTD attribute declaration for #FIXED or
4572 * default declaration values unless DTD use has been turned off.
4573 *
4574 * Returns the attribute value or NULL if not found.
4575 * It's up to the caller to free the memory.
4576 */
4577xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004578xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004579 xmlAttrPtr prop;
4580 xmlDocPtr doc;
4581 xmlNsPtr ns;
4582
4583 if (node == NULL)
4584 return(NULL);
4585
4586 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004587 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004588 return(xmlGetProp(node, name));
4589 while (prop != NULL) {
4590 /*
4591 * One need to have
4592 * - same attribute names
4593 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004594 */
4595 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004596 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004597 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004598 xmlChar *ret;
4599
4600 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4601 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4602 return(ret);
4603 }
4604 prop = prop->next;
4605 }
4606 if (!xmlCheckDTD) return(NULL);
4607
4608 /*
4609 * Check if there is a default declaration in the internal
4610 * or external subsets
4611 */
4612 doc = node->doc;
4613 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004614 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004615 xmlAttributePtr attrDecl;
4616
Owen Taylor3473f882001-02-23 17:55:21 +00004617 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4618 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4619 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4620
4621 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4622 /*
4623 * The DTD declaration only allows a prefix search
4624 */
4625 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004626 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004627 return(xmlStrdup(attrDecl->defaultValue));
4628 }
4629 }
4630 }
4631 return(NULL);
4632}
4633
4634/**
4635 * xmlSetProp:
4636 * @node: the node
4637 * @name: the attribute name
4638 * @value: the attribute value
4639 *
4640 * Set (or reset) an attribute carried by a node.
4641 * Returns the attribute pointer.
4642 */
4643xmlAttrPtr
4644xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004645 xmlAttrPtr prop;
4646 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004647
4648 if ((node == NULL) || (name == NULL))
4649 return(NULL);
4650 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004651 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004652 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004653 if ((xmlStrEqual(prop->name, name)) &&
4654 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004655 xmlNodePtr oldprop = prop->children;
4656
Owen Taylor3473f882001-02-23 17:55:21 +00004657 prop->children = NULL;
4658 prop->last = NULL;
4659 if (value != NULL) {
4660 xmlChar *buffer;
4661 xmlNodePtr tmp;
4662
4663 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4664 prop->children = xmlStringGetNodeList(node->doc, buffer);
4665 prop->last = NULL;
4666 prop->doc = doc;
4667 tmp = prop->children;
4668 while (tmp != NULL) {
4669 tmp->parent = (xmlNodePtr) prop;
4670 tmp->doc = doc;
4671 if (tmp->next == NULL)
4672 prop->last = tmp;
4673 tmp = tmp->next;
4674 }
4675 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004676 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004677 if (oldprop != NULL)
4678 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004679 return(prop);
4680 }
4681 prop = prop->next;
4682 }
4683 prop = xmlNewProp(node, name, value);
4684 return(prop);
4685}
4686
4687/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004688 * xmlUnsetProp:
4689 * @node: the node
4690 * @name: the attribute name
4691 *
4692 * Remove an attribute carried by a node.
4693 * Returns 0 if successful, -1 if not found
4694 */
4695int
4696xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4697 xmlAttrPtr prop = node->properties, prev = NULL;;
4698
4699 if ((node == NULL) || (name == NULL))
4700 return(-1);
4701 while (prop != NULL) {
4702 if ((xmlStrEqual(prop->name, name)) &&
4703 (prop->ns == NULL)) {
4704 if (prev == NULL)
4705 node->properties = prop->next;
4706 else
4707 prev->next = prop->next;
4708 xmlFreeProp(prop);
4709 return(0);
4710 }
4711 prev = prop;
4712 prop = prop->next;
4713 }
4714 return(-1);
4715}
4716
4717/**
Owen Taylor3473f882001-02-23 17:55:21 +00004718 * xmlSetNsProp:
4719 * @node: the node
4720 * @ns: the namespace definition
4721 * @name: the attribute name
4722 * @value: the attribute value
4723 *
4724 * Set (or reset) an attribute carried by a node.
4725 * The ns structure must be in scope, this is not checked.
4726 *
4727 * Returns the attribute pointer.
4728 */
4729xmlAttrPtr
4730xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4731 const xmlChar *value) {
4732 xmlAttrPtr prop;
4733
4734 if ((node == NULL) || (name == NULL))
4735 return(NULL);
4736
4737 if (ns == NULL)
4738 return(xmlSetProp(node, name, value));
4739 if (ns->href == NULL)
4740 return(NULL);
4741 prop = node->properties;
4742
4743 while (prop != NULL) {
4744 /*
4745 * One need to have
4746 * - same attribute names
4747 * - and the attribute carrying that namespace
4748 * or
4749 * no namespace on the attribute and the element carrying it
4750 */
4751 if ((xmlStrEqual(prop->name, name)) &&
4752 (((prop->ns == NULL) && (node->ns != NULL) &&
4753 (xmlStrEqual(node->ns->href, ns->href))) ||
4754 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4755 if (prop->children != NULL)
4756 xmlFreeNodeList(prop->children);
4757 prop->children = NULL;
4758 prop->last = NULL;
4759 prop->ns = ns;
4760 if (value != NULL) {
4761 xmlChar *buffer;
4762 xmlNodePtr tmp;
4763
4764 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4765 prop->children = xmlStringGetNodeList(node->doc, buffer);
4766 prop->last = NULL;
4767 tmp = prop->children;
4768 while (tmp != NULL) {
4769 tmp->parent = (xmlNodePtr) prop;
4770 if (tmp->next == NULL)
4771 prop->last = tmp;
4772 tmp = tmp->next;
4773 }
4774 xmlFree(buffer);
4775 }
4776 return(prop);
4777 }
4778 prop = prop->next;
4779 }
4780 prop = xmlNewNsProp(node, ns, name, value);
4781 return(prop);
4782}
4783
4784/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004785 * xmlUnsetNsProp:
4786 * @node: the node
4787 * @ns: the namespace definition
4788 * @name: the attribute name
4789 *
4790 * Remove an attribute carried by a node.
4791 * Returns 0 if successful, -1 if not found
4792 */
4793int
4794xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
4795 xmlAttrPtr prop = node->properties, prev = NULL;;
4796
4797 if ((node == NULL) || (name == NULL))
4798 return(-1);
4799 if (ns == NULL)
4800 return(xmlUnsetProp(node, name));
4801 if (ns->href == NULL)
4802 return(-1);
4803 while (prop != NULL) {
4804 if ((xmlStrEqual(prop->name, name)) &&
4805 (((prop->ns == NULL) && (node->ns != NULL) &&
4806 (xmlStrEqual(node->ns->href, ns->href))) ||
4807 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4808 if (prev == NULL)
4809 node->properties = prop->next;
4810 else
4811 prev->next = prop->next;
4812 xmlFreeProp(prop);
4813 return(0);
4814 }
4815 prev = prop;
4816 prop = prop->next;
4817 }
4818 return(-1);
4819}
4820
4821/**
Owen Taylor3473f882001-02-23 17:55:21 +00004822 * xmlNodeIsText:
4823 * @node: the node
4824 *
4825 * Is this node a Text node ?
4826 * Returns 1 yes, 0 no
4827 */
4828int
4829xmlNodeIsText(xmlNodePtr node) {
4830 if (node == NULL) return(0);
4831
4832 if (node->type == XML_TEXT_NODE) return(1);
4833 return(0);
4834}
4835
4836/**
4837 * xmlIsBlankNode:
4838 * @node: the node
4839 *
4840 * Checks whether this node is an empty or whitespace only
4841 * (and possibly ignorable) text-node.
4842 *
4843 * Returns 1 yes, 0 no
4844 */
4845int
4846xmlIsBlankNode(xmlNodePtr node) {
4847 const xmlChar *cur;
4848 if (node == NULL) return(0);
4849
Daniel Veillard7db37732001-07-12 01:20:08 +00004850 if ((node->type != XML_TEXT_NODE) &&
4851 (node->type != XML_CDATA_SECTION_NODE))
4852 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004853 if (node->content == NULL) return(1);
4854#ifndef XML_USE_BUFFER_CONTENT
4855 cur = node->content;
4856#else
4857 cur = xmlBufferContent(node->content);
4858#endif
4859 while (*cur != 0) {
4860 if (!IS_BLANK(*cur)) return(0);
4861 cur++;
4862 }
4863
4864 return(1);
4865}
4866
4867/**
4868 * xmlTextConcat:
4869 * @node: the node
4870 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00004871 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00004872 *
4873 * Concat the given string at the end of the existing node content
4874 */
4875
4876void
4877xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
4878 if (node == NULL) return;
4879
4880 if ((node->type != XML_TEXT_NODE) &&
4881 (node->type != XML_CDATA_SECTION_NODE)) {
4882#ifdef DEBUG_TREE
4883 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004884 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004885#endif
4886 return;
4887 }
4888#ifndef XML_USE_BUFFER_CONTENT
4889 node->content = xmlStrncat(node->content, content, len);
4890#else
4891 xmlBufferAdd(node->content, content, len);
4892#endif
4893}
4894
4895/************************************************************************
4896 * *
4897 * Output : to a FILE or in memory *
4898 * *
4899 ************************************************************************/
4900
Owen Taylor3473f882001-02-23 17:55:21 +00004901/**
4902 * xmlBufferCreate:
4903 *
4904 * routine to create an XML buffer.
4905 * returns the new structure.
4906 */
4907xmlBufferPtr
4908xmlBufferCreate(void) {
4909 xmlBufferPtr ret;
4910
4911 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4912 if (ret == NULL) {
4913 xmlGenericError(xmlGenericErrorContext,
4914 "xmlBufferCreate : out of memory!\n");
4915 return(NULL);
4916 }
4917 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00004918 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00004919 ret->alloc = xmlBufferAllocScheme;
4920 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4921 if (ret->content == NULL) {
4922 xmlGenericError(xmlGenericErrorContext,
4923 "xmlBufferCreate : out of memory!\n");
4924 xmlFree(ret);
4925 return(NULL);
4926 }
4927 ret->content[0] = 0;
4928 return(ret);
4929}
4930
4931/**
4932 * xmlBufferCreateSize:
4933 * @size: initial size of buffer
4934 *
4935 * routine to create an XML buffer.
4936 * returns the new structure.
4937 */
4938xmlBufferPtr
4939xmlBufferCreateSize(size_t size) {
4940 xmlBufferPtr ret;
4941
4942 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4943 if (ret == NULL) {
4944 xmlGenericError(xmlGenericErrorContext,
4945 "xmlBufferCreate : out of memory!\n");
4946 return(NULL);
4947 }
4948 ret->use = 0;
4949 ret->alloc = xmlBufferAllocScheme;
4950 ret->size = (size ? size+2 : 0); /* +1 for ending null */
4951 if (ret->size){
4952 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4953 if (ret->content == NULL) {
4954 xmlGenericError(xmlGenericErrorContext,
4955 "xmlBufferCreate : out of memory!\n");
4956 xmlFree(ret);
4957 return(NULL);
4958 }
4959 ret->content[0] = 0;
4960 } else
4961 ret->content = NULL;
4962 return(ret);
4963}
4964
4965/**
4966 * xmlBufferSetAllocationScheme:
4967 * @buf: the buffer to free
4968 * @scheme: allocation scheme to use
4969 *
4970 * Sets the allocation scheme for this buffer
4971 */
4972void
4973xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4974 xmlBufferAllocationScheme scheme) {
4975 if (buf == NULL) {
4976#ifdef DEBUG_BUFFER
4977 xmlGenericError(xmlGenericErrorContext,
4978 "xmlBufferSetAllocationScheme: buf == NULL\n");
4979#endif
4980 return;
4981 }
4982
4983 buf->alloc = scheme;
4984}
4985
4986/**
4987 * xmlBufferFree:
4988 * @buf: the buffer to free
4989 *
4990 * Frees an XML buffer.
4991 */
4992void
4993xmlBufferFree(xmlBufferPtr buf) {
4994 if (buf == NULL) {
4995#ifdef DEBUG_BUFFER
4996 xmlGenericError(xmlGenericErrorContext,
4997 "xmlBufferFree: buf == NULL\n");
4998#endif
4999 return;
5000 }
5001 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005002 xmlFree(buf->content);
5003 }
Owen Taylor3473f882001-02-23 17:55:21 +00005004 xmlFree(buf);
5005}
5006
5007/**
5008 * xmlBufferEmpty:
5009 * @buf: the buffer
5010 *
5011 * empty a buffer.
5012 */
5013void
5014xmlBufferEmpty(xmlBufferPtr buf) {
5015 if (buf->content == NULL) return;
5016 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005017 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005018}
5019
5020/**
5021 * xmlBufferShrink:
5022 * @buf: the buffer to dump
5023 * @len: the number of xmlChar to remove
5024 *
5025 * Remove the beginning of an XML buffer.
5026 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005027 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005028 */
5029int
5030xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5031 if (len == 0) return(0);
5032 if (len > buf->use) return(-1);
5033
5034 buf->use -= len;
5035 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5036
5037 buf->content[buf->use] = 0;
5038 return(len);
5039}
5040
5041/**
5042 * xmlBufferGrow:
5043 * @buf: the buffer
5044 * @len: the minimum free size to allocate
5045 *
5046 * Grow the available space of an XML buffer.
5047 *
5048 * Returns the new available space or -1 in case of error
5049 */
5050int
5051xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5052 int size;
5053 xmlChar *newbuf;
5054
5055 if (len + buf->use < buf->size) return(0);
5056
5057 size = buf->use + len + 100;
5058
5059 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5060 if (newbuf == NULL) return(-1);
5061 buf->content = newbuf;
5062 buf->size = size;
5063 return(buf->size - buf->use);
5064}
5065
5066/**
5067 * xmlBufferDump:
5068 * @file: the file output
5069 * @buf: the buffer to dump
5070 *
5071 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005072 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005073 */
5074int
5075xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5076 int ret;
5077
5078 if (buf == NULL) {
5079#ifdef DEBUG_BUFFER
5080 xmlGenericError(xmlGenericErrorContext,
5081 "xmlBufferDump: buf == NULL\n");
5082#endif
5083 return(0);
5084 }
5085 if (buf->content == NULL) {
5086#ifdef DEBUG_BUFFER
5087 xmlGenericError(xmlGenericErrorContext,
5088 "xmlBufferDump: buf->content == NULL\n");
5089#endif
5090 return(0);
5091 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005092 if (file == NULL)
5093 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005094 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5095 return(ret);
5096}
5097
5098/**
5099 * xmlBufferContent:
5100 * @buf: the buffer
5101 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005102 * Function to extract the content of a buffer
5103 *
Owen Taylor3473f882001-02-23 17:55:21 +00005104 * Returns the internal content
5105 */
5106
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005107const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005108xmlBufferContent(const xmlBufferPtr buf)
5109{
5110 if(!buf)
5111 return NULL;
5112
5113 return buf->content;
5114}
5115
5116/**
5117 * xmlBufferLength:
5118 * @buf: the buffer
5119 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005120 * Function to get the length of a buffer
5121 *
Owen Taylor3473f882001-02-23 17:55:21 +00005122 * Returns the length of data in the internal content
5123 */
5124
5125int
5126xmlBufferLength(const xmlBufferPtr buf)
5127{
5128 if(!buf)
5129 return 0;
5130
5131 return buf->use;
5132}
5133
5134/**
5135 * xmlBufferResize:
5136 * @buf: the buffer to resize
5137 * @size: the desired size
5138 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005139 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005140 *
5141 * Returns 0 in case of problems, 1 otherwise
5142 */
5143int
5144xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5145{
5146 unsigned int newSize;
5147 xmlChar* rebuf = NULL;
5148
5149 /*take care of empty case*/
5150 newSize = (buf->size ? buf->size*2 : size);
5151
5152 /* Don't resize if we don't have to */
5153 if (size < buf->size)
5154 return 1;
5155
5156 /* figure out new size */
5157 switch (buf->alloc){
5158 case XML_BUFFER_ALLOC_DOUBLEIT:
5159 while (size > newSize) newSize *= 2;
5160 break;
5161 case XML_BUFFER_ALLOC_EXACT:
5162 newSize = size+10;
5163 break;
5164 default:
5165 newSize = size+10;
5166 break;
5167 }
5168
5169 if (buf->content == NULL)
5170 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5171 else
5172 rebuf = (xmlChar *) xmlRealloc(buf->content,
5173 newSize * sizeof(xmlChar));
5174 if (rebuf == NULL) {
5175 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005176 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005177 return 0;
5178 }
5179 buf->content = rebuf;
5180 buf->size = newSize;
5181
5182 return 1;
5183}
5184
5185/**
5186 * xmlBufferAdd:
5187 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005188 * @str: the #xmlChar string
5189 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005190 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005191 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005192 * str is recomputed.
5193 */
5194void
5195xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5196 unsigned int needSize;
5197
5198 if (str == NULL) {
5199#ifdef DEBUG_BUFFER
5200 xmlGenericError(xmlGenericErrorContext,
5201 "xmlBufferAdd: str == NULL\n");
5202#endif
5203 return;
5204 }
5205 if (len < -1) {
5206#ifdef DEBUG_BUFFER
5207 xmlGenericError(xmlGenericErrorContext,
5208 "xmlBufferAdd: len < 0\n");
5209#endif
5210 return;
5211 }
5212 if (len == 0) return;
5213
5214 if (len < 0)
5215 len = xmlStrlen(str);
5216
5217 if (len <= 0) return;
5218
5219 needSize = buf->use + len + 2;
5220 if (needSize > buf->size){
5221 if (!xmlBufferResize(buf, needSize)){
5222 xmlGenericError(xmlGenericErrorContext,
5223 "xmlBufferAdd : out of memory!\n");
5224 return;
5225 }
5226 }
5227
5228 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5229 buf->use += len;
5230 buf->content[buf->use] = 0;
5231}
5232
5233/**
5234 * xmlBufferAddHead:
5235 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005236 * @str: the #xmlChar string
5237 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005238 *
5239 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005240 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005241 */
5242void
5243xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5244 unsigned int needSize;
5245
5246 if (str == NULL) {
5247#ifdef DEBUG_BUFFER
5248 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005249 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005250#endif
5251 return;
5252 }
5253 if (len < -1) {
5254#ifdef DEBUG_BUFFER
5255 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005256 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005257#endif
5258 return;
5259 }
5260 if (len == 0) return;
5261
5262 if (len < 0)
5263 len = xmlStrlen(str);
5264
5265 if (len <= 0) return;
5266
5267 needSize = buf->use + len + 2;
5268 if (needSize > buf->size){
5269 if (!xmlBufferResize(buf, needSize)){
5270 xmlGenericError(xmlGenericErrorContext,
5271 "xmlBufferAddHead : out of memory!\n");
5272 return;
5273 }
5274 }
5275
5276 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5277 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5278 buf->use += len;
5279 buf->content[buf->use] = 0;
5280}
5281
5282/**
5283 * xmlBufferCat:
5284 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005285 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005286 *
5287 * Append a zero terminated string to an XML buffer.
5288 */
5289void
5290xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5291 if (str != NULL)
5292 xmlBufferAdd(buf, str, -1);
5293}
5294
5295/**
5296 * xmlBufferCCat:
5297 * @buf: the buffer to dump
5298 * @str: the C char string
5299 *
5300 * Append a zero terminated C string to an XML buffer.
5301 */
5302void
5303xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5304 const char *cur;
5305
5306 if (str == NULL) {
5307#ifdef DEBUG_BUFFER
5308 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005309 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005310#endif
5311 return;
5312 }
5313 for (cur = str;*cur != 0;cur++) {
5314 if (buf->use + 10 >= buf->size) {
5315 if (!xmlBufferResize(buf, buf->use+10)){
5316 xmlGenericError(xmlGenericErrorContext,
5317 "xmlBufferCCat : out of memory!\n");
5318 return;
5319 }
5320 }
5321 buf->content[buf->use++] = *cur;
5322 }
5323 buf->content[buf->use] = 0;
5324}
5325
5326/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005327 * xmlBufferWriteXmlCHAR:
5328 * @buf: the XML buffer
5329 * @string: the string to add
5330 *
5331 * For VMS only.
5332 * routine which manages and grows an output buffer. This one adds
5333 * xmlChars at the end of the buffer.
5334 */
5335/**
Owen Taylor3473f882001-02-23 17:55:21 +00005336 * xmlBufferWriteCHAR:
5337 * @buf: the XML buffer
5338 * @string: the string to add
5339 *
5340 * routine which manages and grows an output buffer. This one adds
5341 * xmlChars at the end of the buffer.
5342 */
5343void
5344#ifdef VMS
5345xmlBufferWriteXmlCHAR
5346#else
5347xmlBufferWriteCHAR
5348#endif
5349(xmlBufferPtr buf, const xmlChar *string) {
5350 xmlBufferCat(buf, string);
5351}
5352
5353/**
5354 * xmlBufferWriteChar:
5355 * @buf: the XML buffer output
5356 * @string: the string to add
5357 *
5358 * routine which manage and grows an output buffer. This one add
5359 * C chars at the end of the array.
5360 */
5361void
5362xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5363 xmlBufferCCat(buf, string);
5364}
5365
5366
5367/**
5368 * xmlBufferWriteQuotedString:
5369 * @buf: the XML buffer output
5370 * @string: the string to add
5371 *
5372 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005373 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005374 * quote or double-quotes internally
5375 */
5376void
5377xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5378 if (xmlStrchr(string, '"')) {
5379 if (xmlStrchr(string, '\'')) {
5380#ifdef DEBUG_BUFFER
5381 xmlGenericError(xmlGenericErrorContext,
5382 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5383#endif
5384 }
5385 xmlBufferCCat(buf, "'");
5386 xmlBufferCat(buf, string);
5387 xmlBufferCCat(buf, "'");
5388 } else {
5389 xmlBufferCCat(buf, "\"");
5390 xmlBufferCat(buf, string);
5391 xmlBufferCCat(buf, "\"");
5392 }
5393}
5394
5395
5396/************************************************************************
5397 * *
5398 * Dumping XML tree content to a simple buffer *
5399 * *
5400 ************************************************************************/
5401
5402void
5403xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5404 int format);
5405static void
5406xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5407 int format);
5408void
5409htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5410
5411/**
5412 * xmlNsDump:
5413 * @buf: the XML buffer output
5414 * @cur: a namespace
5415 *
5416 * Dump a local Namespace definition.
5417 * Should be called in the context of attributes dumps.
5418 */
5419static void
5420xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5421 if (cur == NULL) {
5422#ifdef DEBUG_TREE
5423 xmlGenericError(xmlGenericErrorContext,
5424 "xmlNsDump : Ns == NULL\n");
5425#endif
5426 return;
5427 }
5428 if (cur->type == XML_LOCAL_NAMESPACE) {
5429 /* Within the context of an element attributes */
5430 if (cur->prefix != NULL) {
5431 xmlBufferWriteChar(buf, " xmlns:");
5432 xmlBufferWriteCHAR(buf, cur->prefix);
5433 } else
5434 xmlBufferWriteChar(buf, " xmlns");
5435 xmlBufferWriteChar(buf, "=");
5436 xmlBufferWriteQuotedString(buf, cur->href);
5437 }
5438}
5439
5440/**
5441 * xmlNsListDump:
5442 * @buf: the XML buffer output
5443 * @cur: the first namespace
5444 *
5445 * Dump a list of local Namespace definitions.
5446 * Should be called in the context of attributes dumps.
5447 */
5448static void
5449xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5450 while (cur != NULL) {
5451 xmlNsDump(buf, cur);
5452 cur = cur->next;
5453 }
5454}
5455
5456/**
5457 * xmlDtdDump:
5458 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005459 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005460 *
5461 * Dump the XML document DTD, if any.
5462 */
5463static void
5464xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5465 if (dtd == NULL) {
5466#ifdef DEBUG_TREE
5467 xmlGenericError(xmlGenericErrorContext,
5468 "xmlDtdDump : no internal subset\n");
5469#endif
5470 return;
5471 }
5472 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5473 xmlBufferWriteCHAR(buf, dtd->name);
5474 if (dtd->ExternalID != NULL) {
5475 xmlBufferWriteChar(buf, " PUBLIC ");
5476 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5477 xmlBufferWriteChar(buf, " ");
5478 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5479 } else if (dtd->SystemID != NULL) {
5480 xmlBufferWriteChar(buf, " SYSTEM ");
5481 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5482 }
5483 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5484 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5485 xmlBufferWriteChar(buf, ">");
5486 return;
5487 }
5488 xmlBufferWriteChar(buf, " [\n");
5489 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5490#if 0
5491 if (dtd->entities != NULL)
5492 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5493 if (dtd->notations != NULL)
5494 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5495 if (dtd->elements != NULL)
5496 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5497 if (dtd->attributes != NULL)
5498 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5499#endif
5500 xmlBufferWriteChar(buf, "]>");
5501}
5502
5503/**
5504 * xmlAttrDump:
5505 * @buf: the XML buffer output
5506 * @doc: the document
5507 * @cur: the attribute pointer
5508 *
5509 * Dump an XML attribute
5510 */
5511static void
5512xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5513 xmlChar *value;
5514
5515 if (cur == NULL) {
5516#ifdef DEBUG_TREE
5517 xmlGenericError(xmlGenericErrorContext,
5518 "xmlAttrDump : property == NULL\n");
5519#endif
5520 return;
5521 }
5522 xmlBufferWriteChar(buf, " ");
5523 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5524 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5525 xmlBufferWriteChar(buf, ":");
5526 }
5527 xmlBufferWriteCHAR(buf, cur->name);
5528 value = xmlNodeListGetString(doc, cur->children, 0);
5529 if (value != NULL) {
5530 xmlBufferWriteChar(buf, "=");
5531 xmlBufferWriteQuotedString(buf, value);
5532 xmlFree(value);
5533 } else {
5534 xmlBufferWriteChar(buf, "=\"\"");
5535 }
5536}
5537
5538/**
5539 * xmlAttrListDump:
5540 * @buf: the XML buffer output
5541 * @doc: the document
5542 * @cur: the first attribute pointer
5543 *
5544 * Dump a list of XML attributes
5545 */
5546static void
5547xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5548 if (cur == NULL) {
5549#ifdef DEBUG_TREE
5550 xmlGenericError(xmlGenericErrorContext,
5551 "xmlAttrListDump : property == NULL\n");
5552#endif
5553 return;
5554 }
5555 while (cur != NULL) {
5556 xmlAttrDump(buf, doc, cur);
5557 cur = cur->next;
5558 }
5559}
5560
5561
5562
5563/**
5564 * xmlNodeListDump:
5565 * @buf: the XML buffer output
5566 * @doc: the document
5567 * @cur: the first node
5568 * @level: the imbrication level for indenting
5569 * @format: is formatting allowed
5570 *
5571 * Dump an XML node list, recursive behaviour,children are printed too.
5572 */
5573static void
5574xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5575 int format) {
5576 int i;
5577
5578 if (cur == NULL) {
5579#ifdef DEBUG_TREE
5580 xmlGenericError(xmlGenericErrorContext,
5581 "xmlNodeListDump : node == NULL\n");
5582#endif
5583 return;
5584 }
5585 while (cur != NULL) {
5586 if ((format) && (xmlIndentTreeOutput) &&
5587 (cur->type == XML_ELEMENT_NODE))
5588 for (i = 0;i < level;i++)
5589 xmlBufferWriteChar(buf, " ");
5590 xmlNodeDump(buf, doc, cur, level, format);
5591 if (format) {
5592 xmlBufferWriteChar(buf, "\n");
5593 }
5594 cur = cur->next;
5595 }
5596}
5597
5598/**
5599 * xmlNodeDump:
5600 * @buf: the XML buffer output
5601 * @doc: the document
5602 * @cur: the current node
5603 * @level: the imbrication level for indenting
5604 * @format: is formatting allowed
5605 *
5606 * Dump an XML node, recursive behaviour,children are printed too.
5607 */
5608void
5609xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5610 int format) {
5611 int i;
5612 xmlNodePtr tmp;
5613
5614 if (cur == NULL) {
5615#ifdef DEBUG_TREE
5616 xmlGenericError(xmlGenericErrorContext,
5617 "xmlNodeDump : node == NULL\n");
5618#endif
5619 return;
5620 }
5621 if (cur->type == XML_XINCLUDE_START)
5622 return;
5623 if (cur->type == XML_XINCLUDE_END)
5624 return;
5625 if (cur->type == XML_DTD_NODE) {
5626 xmlDtdDump(buf, (xmlDtdPtr) cur);
5627 return;
5628 }
5629 if (cur->type == XML_ELEMENT_DECL) {
5630 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5631 return;
5632 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005633 if (cur->type == XML_ATTRIBUTE_NODE){
5634 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5635 return;
5636 }
Owen Taylor3473f882001-02-23 17:55:21 +00005637 if (cur->type == XML_ATTRIBUTE_DECL) {
5638 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5639 return;
5640 }
5641 if (cur->type == XML_ENTITY_DECL) {
5642 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5643 return;
5644 }
5645 if (cur->type == XML_TEXT_NODE) {
5646 if (cur->content != NULL) {
5647 if ((cur->name == xmlStringText) ||
5648 (cur->name != xmlStringTextNoenc)) {
5649 xmlChar *buffer;
5650
5651#ifndef XML_USE_BUFFER_CONTENT
5652 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5653#else
5654 buffer = xmlEncodeEntitiesReentrant(doc,
5655 xmlBufferContent(cur->content));
5656#endif
5657 if (buffer != NULL) {
5658 xmlBufferWriteCHAR(buf, buffer);
5659 xmlFree(buffer);
5660 }
5661 } else {
5662 /*
5663 * Disable escaping, needed for XSLT
5664 */
5665#ifndef XML_USE_BUFFER_CONTENT
5666 xmlBufferWriteCHAR(buf, cur->content);
5667#else
5668 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5669#endif
5670 }
5671 }
5672 return;
5673 }
5674 if (cur->type == XML_PI_NODE) {
5675 if (cur->content != NULL) {
5676 xmlBufferWriteChar(buf, "<?");
5677 xmlBufferWriteCHAR(buf, cur->name);
5678 if (cur->content != NULL) {
5679 xmlBufferWriteChar(buf, " ");
5680#ifndef XML_USE_BUFFER_CONTENT
5681 xmlBufferWriteCHAR(buf, cur->content);
5682#else
5683 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5684#endif
5685 }
5686 xmlBufferWriteChar(buf, "?>");
5687 } else {
5688 xmlBufferWriteChar(buf, "<?");
5689 xmlBufferWriteCHAR(buf, cur->name);
5690 xmlBufferWriteChar(buf, "?>");
5691 }
5692 return;
5693 }
5694 if (cur->type == XML_COMMENT_NODE) {
5695 if (cur->content != NULL) {
5696 xmlBufferWriteChar(buf, "<!--");
5697#ifndef XML_USE_BUFFER_CONTENT
5698 xmlBufferWriteCHAR(buf, cur->content);
5699#else
5700 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5701#endif
5702 xmlBufferWriteChar(buf, "-->");
5703 }
5704 return;
5705 }
5706 if (cur->type == XML_ENTITY_REF_NODE) {
5707 xmlBufferWriteChar(buf, "&");
5708 xmlBufferWriteCHAR(buf, cur->name);
5709 xmlBufferWriteChar(buf, ";");
5710 return;
5711 }
5712 if (cur->type == XML_CDATA_SECTION_NODE) {
5713 xmlBufferWriteChar(buf, "<![CDATA[");
5714 if (cur->content != NULL)
5715#ifndef XML_USE_BUFFER_CONTENT
5716 xmlBufferWriteCHAR(buf, cur->content);
5717#else
5718 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5719#endif
5720 xmlBufferWriteChar(buf, "]]>");
5721 return;
5722 }
5723
5724 if (format == 1) {
5725 tmp = cur->children;
5726 while (tmp != NULL) {
5727 if ((tmp->type == XML_TEXT_NODE) ||
5728 (tmp->type == XML_ENTITY_REF_NODE)) {
5729 format = 0;
5730 break;
5731 }
5732 tmp = tmp->next;
5733 }
5734 }
5735 xmlBufferWriteChar(buf, "<");
5736 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5737 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5738 xmlBufferWriteChar(buf, ":");
5739 }
5740
5741 xmlBufferWriteCHAR(buf, cur->name);
5742 if (cur->nsDef)
5743 xmlNsListDump(buf, cur->nsDef);
5744 if (cur->properties != NULL)
5745 xmlAttrListDump(buf, doc, cur->properties);
5746
Daniel Veillard7db37732001-07-12 01:20:08 +00005747 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
5748 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00005749 (!xmlSaveNoEmptyTags)) {
5750 xmlBufferWriteChar(buf, "/>");
5751 return;
5752 }
5753 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00005754 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005755 xmlChar *buffer;
5756
5757#ifndef XML_USE_BUFFER_CONTENT
5758 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5759#else
5760 buffer = xmlEncodeEntitiesReentrant(doc,
5761 xmlBufferContent(cur->content));
5762#endif
5763 if (buffer != NULL) {
5764 xmlBufferWriteCHAR(buf, buffer);
5765 xmlFree(buffer);
5766 }
5767 }
5768 if (cur->children != NULL) {
5769 if (format) xmlBufferWriteChar(buf, "\n");
5770 xmlNodeListDump(buf, doc, cur->children,
5771 (level >= 0?level+1:-1), format);
5772 if ((xmlIndentTreeOutput) && (format))
5773 for (i = 0;i < level;i++)
5774 xmlBufferWriteChar(buf, " ");
5775 }
5776 xmlBufferWriteChar(buf, "</");
5777 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5778 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5779 xmlBufferWriteChar(buf, ":");
5780 }
5781
5782 xmlBufferWriteCHAR(buf, cur->name);
5783 xmlBufferWriteChar(buf, ">");
5784}
5785
5786/**
5787 * xmlElemDump:
5788 * @f: the FILE * for the output
5789 * @doc: the document
5790 * @cur: the current node
5791 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005792 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00005793 */
5794void
5795xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5796 xmlBufferPtr buf;
5797
5798 if (cur == NULL) {
5799#ifdef DEBUG_TREE
5800 xmlGenericError(xmlGenericErrorContext,
5801 "xmlElemDump : cur == NULL\n");
5802#endif
5803 return;
5804 }
Owen Taylor3473f882001-02-23 17:55:21 +00005805#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005806 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005807 xmlGenericError(xmlGenericErrorContext,
5808 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005809 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005810#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00005811
Owen Taylor3473f882001-02-23 17:55:21 +00005812 buf = xmlBufferCreate();
5813 if (buf == NULL) return;
5814 if ((doc != NULL) &&
5815 (doc->type == XML_HTML_DOCUMENT_NODE)) {
5816#ifdef LIBXML_HTML_ENABLED
5817 htmlNodeDump(buf, doc, cur);
5818#else
5819 xmlGenericError(xmlGenericErrorContext,
5820 "HTML support not compiled in\n");
5821#endif /* LIBXML_HTML_ENABLED */
5822 } else
5823 xmlNodeDump(buf, doc, cur, 0, 1);
5824 xmlBufferDump(f, buf);
5825 xmlBufferFree(buf);
5826}
5827
5828/************************************************************************
5829 * *
5830 * Dumping XML tree content to an I/O output buffer *
5831 * *
5832 ************************************************************************/
5833
5834void
5835xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5836 int level, int format, const char *encoding);
5837static void
5838xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5839 int level, int format, const char *encoding);
5840/**
5841 * xmlNsDumpOutput:
5842 * @buf: the XML buffer output
5843 * @cur: a namespace
5844 *
5845 * Dump a local Namespace definition.
5846 * Should be called in the context of attributes dumps.
5847 */
5848static void
5849xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5850 if (cur == NULL) {
5851#ifdef DEBUG_TREE
5852 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005853 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005854#endif
5855 return;
5856 }
5857 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
5858 /* Within the context of an element attributes */
5859 if (cur->prefix != NULL) {
5860 xmlOutputBufferWriteString(buf, " xmlns:");
5861 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5862 } else
5863 xmlOutputBufferWriteString(buf, " xmlns");
5864 xmlOutputBufferWriteString(buf, "=");
5865 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5866 }
5867}
5868
5869/**
5870 * xmlNsListDumpOutput:
5871 * @buf: the XML buffer output
5872 * @cur: the first namespace
5873 *
5874 * Dump a list of local Namespace definitions.
5875 * Should be called in the context of attributes dumps.
5876 */
5877static void
5878xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5879 while (cur != NULL) {
5880 xmlNsDumpOutput(buf, cur);
5881 cur = cur->next;
5882 }
5883}
5884
5885/**
5886 * xmlDtdDumpOutput:
5887 * @buf: the XML buffer output
5888 * @doc: the document
5889 * @encoding: an optional encoding string
5890 *
5891 * Dump the XML document DTD, if any.
5892 */
5893static void
5894xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5895 if (dtd == NULL) {
5896#ifdef DEBUG_TREE
5897 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005898 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005899#endif
5900 return;
5901 }
5902 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5903 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5904 if (dtd->ExternalID != NULL) {
5905 xmlOutputBufferWriteString(buf, " PUBLIC ");
5906 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5907 xmlOutputBufferWriteString(buf, " ");
5908 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5909 } else if (dtd->SystemID != NULL) {
5910 xmlOutputBufferWriteString(buf, " SYSTEM ");
5911 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5912 }
5913 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5914 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5915 xmlOutputBufferWriteString(buf, ">");
5916 return;
5917 }
5918 xmlOutputBufferWriteString(buf, " [\n");
5919 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5920 xmlOutputBufferWriteString(buf, "]>");
5921}
5922
5923/**
5924 * xmlAttrDumpOutput:
5925 * @buf: the XML buffer output
5926 * @doc: the document
5927 * @cur: the attribute pointer
5928 * @encoding: an optional encoding string
5929 *
5930 * Dump an XML attribute
5931 */
5932static void
5933xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00005934 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005935 xmlChar *value;
5936
5937 if (cur == NULL) {
5938#ifdef DEBUG_TREE
5939 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005940 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005941#endif
5942 return;
5943 }
5944 xmlOutputBufferWriteString(buf, " ");
5945 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5946 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5947 xmlOutputBufferWriteString(buf, ":");
5948 }
5949 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5950 value = xmlNodeListGetString(doc, cur->children, 0);
5951 if (value) {
5952 xmlOutputBufferWriteString(buf, "=");
5953 xmlBufferWriteQuotedString(buf->buffer, value);
5954 xmlFree(value);
5955 } else {
5956 xmlOutputBufferWriteString(buf, "=\"\"");
5957 }
5958}
5959
5960/**
5961 * xmlAttrListDumpOutput:
5962 * @buf: the XML buffer output
5963 * @doc: the document
5964 * @cur: the first attribute pointer
5965 * @encoding: an optional encoding string
5966 *
5967 * Dump a list of XML attributes
5968 */
5969static void
5970xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5971 xmlAttrPtr cur, const char *encoding) {
5972 if (cur == NULL) {
5973#ifdef DEBUG_TREE
5974 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005975 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005976#endif
5977 return;
5978 }
5979 while (cur != NULL) {
5980 xmlAttrDumpOutput(buf, doc, cur, encoding);
5981 cur = cur->next;
5982 }
5983}
5984
5985
5986
5987/**
5988 * xmlNodeListDumpOutput:
5989 * @buf: the XML buffer output
5990 * @doc: the document
5991 * @cur: the first node
5992 * @level: the imbrication level for indenting
5993 * @format: is formatting allowed
5994 * @encoding: an optional encoding string
5995 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005996 * Dump an XML node list, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00005997 */
5998static void
5999xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6000 xmlNodePtr cur, int level, int format, const char *encoding) {
6001 int i;
6002
6003 if (cur == NULL) {
6004#ifdef DEBUG_TREE
6005 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006006 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006007#endif
6008 return;
6009 }
6010 while (cur != NULL) {
6011 if ((format) && (xmlIndentTreeOutput) &&
6012 (cur->type == XML_ELEMENT_NODE))
6013 for (i = 0;i < level;i++)
6014 xmlOutputBufferWriteString(buf, " ");
6015 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6016 if (format) {
6017 xmlOutputBufferWriteString(buf, "\n");
6018 }
6019 cur = cur->next;
6020 }
6021}
6022
6023/**
6024 * xmlNodeDumpOutput:
6025 * @buf: the XML buffer output
6026 * @doc: the document
6027 * @cur: the current node
6028 * @level: the imbrication level for indenting
6029 * @format: is formatting allowed
6030 * @encoding: an optional encoding string
6031 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006032 * Dump an XML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006033 */
6034void
6035xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6036 int level, int format, const char *encoding) {
6037 int i;
6038 xmlNodePtr tmp;
6039
6040 if (cur == NULL) {
6041#ifdef DEBUG_TREE
6042 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006043 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006044#endif
6045 return;
6046 }
6047 if (cur->type == XML_XINCLUDE_START)
6048 return;
6049 if (cur->type == XML_XINCLUDE_END)
6050 return;
6051 if (cur->type == XML_DTD_NODE) {
6052 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6053 return;
6054 }
6055 if (cur->type == XML_ELEMENT_DECL) {
6056 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6057 return;
6058 }
6059 if (cur->type == XML_ATTRIBUTE_DECL) {
6060 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6061 return;
6062 }
6063 if (cur->type == XML_ENTITY_DECL) {
6064 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6065 return;
6066 }
6067 if (cur->type == XML_TEXT_NODE) {
6068 if (cur->content != NULL) {
6069 if ((cur->name == xmlStringText) ||
6070 (cur->name != xmlStringTextNoenc)) {
6071 xmlChar *buffer;
6072
6073#ifndef XML_USE_BUFFER_CONTENT
6074 if (encoding == NULL)
6075 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6076 else
6077 buffer = xmlEncodeSpecialChars(doc, cur->content);
6078#else
6079 if (encoding == NULL)
6080 buffer = xmlEncodeEntitiesReentrant(doc,
6081 xmlBufferContent(cur->content));
6082 else
6083 buffer = xmlEncodeSpecialChars(doc,
6084 xmlBufferContent(cur->content));
6085#endif
6086 if (buffer != NULL) {
6087 xmlOutputBufferWriteString(buf, (const char *)buffer);
6088 xmlFree(buffer);
6089 }
6090 } else {
6091 /*
6092 * Disable escaping, needed for XSLT
6093 */
6094#ifndef XML_USE_BUFFER_CONTENT
6095 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6096#else
6097 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
6098#endif
6099 }
6100 }
6101
6102 return;
6103 }
6104 if (cur->type == XML_PI_NODE) {
6105 if (cur->content != NULL) {
6106 xmlOutputBufferWriteString(buf, "<?");
6107 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6108 if (cur->content != NULL) {
6109 xmlOutputBufferWriteString(buf, " ");
6110#ifndef XML_USE_BUFFER_CONTENT
6111 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6112#else
6113 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6114#endif
6115 }
6116 xmlOutputBufferWriteString(buf, "?>");
6117 } else {
6118 xmlOutputBufferWriteString(buf, "<?");
6119 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6120 xmlOutputBufferWriteString(buf, "?>");
6121 }
6122 return;
6123 }
6124 if (cur->type == XML_COMMENT_NODE) {
6125 if (cur->content != NULL) {
6126 xmlOutputBufferWriteString(buf, "<!--");
6127#ifndef XML_USE_BUFFER_CONTENT
6128 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6129#else
6130 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6131#endif
6132 xmlOutputBufferWriteString(buf, "-->");
6133 }
6134 return;
6135 }
6136 if (cur->type == XML_ENTITY_REF_NODE) {
6137 xmlOutputBufferWriteString(buf, "&");
6138 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6139 xmlOutputBufferWriteString(buf, ";");
6140 return;
6141 }
6142 if (cur->type == XML_CDATA_SECTION_NODE) {
6143 xmlOutputBufferWriteString(buf, "<![CDATA[");
6144 if (cur->content != NULL)
6145#ifndef XML_USE_BUFFER_CONTENT
6146 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6147#else
6148 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
6149#endif
6150 xmlOutputBufferWriteString(buf, "]]>");
6151 return;
6152 }
6153
6154 if (format == 1) {
6155 tmp = cur->children;
6156 while (tmp != NULL) {
6157 if ((tmp->type == XML_TEXT_NODE) ||
6158 (tmp->type == XML_ENTITY_REF_NODE)) {
6159 format = 0;
6160 break;
6161 }
6162 tmp = tmp->next;
6163 }
6164 }
6165 xmlOutputBufferWriteString(buf, "<");
6166 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6167 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6168 xmlOutputBufferWriteString(buf, ":");
6169 }
6170
6171 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6172 if (cur->nsDef)
6173 xmlNsListDumpOutput(buf, cur->nsDef);
6174 if (cur->properties != NULL)
6175 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6176
Daniel Veillard7db37732001-07-12 01:20:08 +00006177 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6178 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006179 xmlOutputBufferWriteString(buf, "/>");
6180 return;
6181 }
6182 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006183 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006184 xmlChar *buffer;
6185
6186#ifndef XML_USE_BUFFER_CONTENT
6187 if (encoding == NULL)
6188 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6189 else
6190 buffer = xmlEncodeSpecialChars(doc, cur->content);
6191#else
6192 if (encoding == NULL)
6193 buffer = xmlEncodeEntitiesReentrant(doc,
6194 xmlBufferContent(cur->content));
6195 else
6196 buffer = xmlEncodeSpecialChars(doc,
6197 xmlBufferContent(cur->content));
6198#endif
6199 if (buffer != NULL) {
6200 xmlOutputBufferWriteString(buf, (const char *)buffer);
6201 xmlFree(buffer);
6202 }
6203 }
6204 if (cur->children != NULL) {
6205 if (format) xmlOutputBufferWriteString(buf, "\n");
6206 xmlNodeListDumpOutput(buf, doc, cur->children,
6207 (level >= 0?level+1:-1), format, encoding);
6208 if ((xmlIndentTreeOutput) && (format))
6209 for (i = 0;i < level;i++)
6210 xmlOutputBufferWriteString(buf, " ");
6211 }
6212 xmlOutputBufferWriteString(buf, "</");
6213 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6214 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6215 xmlOutputBufferWriteString(buf, ":");
6216 }
6217
6218 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6219 xmlOutputBufferWriteString(buf, ">");
6220}
6221
6222/**
6223 * xmlDocContentDumpOutput:
6224 * @buf: the XML buffer output
6225 * @cur: the document
6226 * @encoding: an optional encoding string
6227 * @format: should formatting spaces been added
6228 *
6229 * Dump an XML document.
6230 */
6231static void
6232xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6233 const char *encoding, int format) {
6234 xmlOutputBufferWriteString(buf, "<?xml version=");
6235 if (cur->version != NULL)
6236 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6237 else
6238 xmlOutputBufferWriteString(buf, "\"1.0\"");
6239 if (encoding == NULL) {
6240 if (cur->encoding != NULL)
6241 encoding = (const char *) cur->encoding;
6242 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6243 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6244 }
6245 if (encoding != NULL) {
6246 xmlOutputBufferWriteString(buf, " encoding=");
6247 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6248 }
6249 switch (cur->standalone) {
6250 case 0:
6251 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6252 break;
6253 case 1:
6254 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6255 break;
6256 }
6257 xmlOutputBufferWriteString(buf, "?>\n");
6258 if (cur->children != NULL) {
6259 xmlNodePtr child = cur->children;
6260
6261 while (child != NULL) {
6262 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6263 xmlOutputBufferWriteString(buf, "\n");
6264 child = child->next;
6265 }
6266 }
6267}
6268
6269/************************************************************************
6270 * *
6271 * Saving functions front-ends *
6272 * *
6273 ************************************************************************/
6274
6275/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006276 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006277 * @out_doc: Document to generate XML text from
6278 * @doc_txt_ptr: Memory pointer for allocated XML text
6279 * @doc_txt_len: Length of the generated XML text
6280 * @txt_encoding: Character encoding to use when generating XML text
6281 * @format: should formatting spaces been added
6282 *
6283 * Dump the current DOM tree into memory using the character encoding specified
6284 * by the caller. Note it is up to the caller of this function to free the
6285 * allocated memory.
6286 */
6287
6288void
6289xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006290 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006291 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006292 int dummy = 0;
6293
6294 xmlCharEncoding doc_charset;
6295 xmlOutputBufferPtr out_buff = NULL;
6296 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6297
6298 if (doc_txt_len == NULL) {
6299 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6300 }
6301
6302 if (doc_txt_ptr == NULL) {
6303 *doc_txt_len = 0;
6304 xmlGenericError(xmlGenericErrorContext,
6305 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6306 return;
6307 }
6308
6309 *doc_txt_ptr = NULL;
6310 *doc_txt_len = 0;
6311
6312 if (out_doc == NULL) {
6313 /* No document, no output */
6314 xmlGenericError(xmlGenericErrorContext,
6315 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6316 return;
6317 }
6318
6319 /*
6320 * Validate the encoding value, if provided.
6321 * This logic is copied from xmlSaveFileEnc.
6322 */
6323
6324 if (txt_encoding == NULL)
6325 txt_encoding = (const char *) out_doc->encoding;
6326 if (txt_encoding != NULL) {
6327 doc_charset = xmlParseCharEncoding(txt_encoding);
6328
6329 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6330 xmlGenericError(xmlGenericErrorContext,
6331 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6332 return;
6333
6334 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6335 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6336 if ( conv_hdlr == NULL ) {
6337 xmlGenericError(xmlGenericErrorContext,
6338 "%s: %s %s '%s'\n",
6339 "xmlDocDumpFormatMemoryEnc",
6340 "Failed to identify encoding handler for",
6341 "character set",
6342 txt_encoding);
6343 return;
6344 }
6345 }
6346 }
6347
6348 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6349 xmlGenericError(xmlGenericErrorContext,
6350 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6351 return;
6352 }
6353
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006354 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006355 xmlOutputBufferFlush(out_buff);
6356 if (out_buff->conv != NULL) {
6357 *doc_txt_len = out_buff->conv->use;
6358 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6359 } else {
6360 *doc_txt_len = out_buff->buffer->use;
6361 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6362 }
6363 (void)xmlOutputBufferClose(out_buff);
6364
6365 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6366 *doc_txt_len = 0;
6367 xmlGenericError(xmlGenericErrorContext,
6368 "xmlDocDumpFormatMemoryEnc: %s\n",
6369 "Failed to allocate memory for document text representation.");
6370 }
6371
6372 return;
6373}
6374
6375/**
6376 * xmlDocDumpMemory:
6377 * @cur: the document
6378 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006379 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006380 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006381 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006382 * It's up to the caller to free the memory.
6383 */
6384void
6385xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6386 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6387}
6388
6389/**
6390 * xmlDocDumpFormatMemory:
6391 * @cur: the document
6392 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006393 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006394 * @format: should formatting spaces been added
6395 *
6396 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006397 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006398 * It's up to the caller to free the memory.
6399 */
6400void
6401xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6402 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6403}
6404
6405/**
6406 * xmlDocDumpMemoryEnc:
6407 * @out_doc: Document to generate XML text from
6408 * @doc_txt_ptr: Memory pointer for allocated XML text
6409 * @doc_txt_len: Length of the generated XML text
6410 * @txt_encoding: Character encoding to use when generating XML text
6411 *
6412 * Dump the current DOM tree into memory using the character encoding specified
6413 * by the caller. Note it is up to the caller of this function to free the
6414 * allocated memory.
6415 */
6416
6417void
6418xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6419 int * doc_txt_len, const char * txt_encoding) {
6420 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006421 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006422}
6423
6424/**
6425 * xmlGetDocCompressMode:
6426 * @doc: the document
6427 *
6428 * get the compression ratio for a document, ZLIB based
6429 * Returns 0 (uncompressed) to 9 (max compression)
6430 */
6431int
6432xmlGetDocCompressMode (xmlDocPtr doc) {
6433 if (doc == NULL) return(-1);
6434 return(doc->compression);
6435}
6436
6437/**
6438 * xmlSetDocCompressMode:
6439 * @doc: the document
6440 * @mode: the compression ratio
6441 *
6442 * set the compression ratio for a document, ZLIB based
6443 * Correct values: 0 (uncompressed) to 9 (max compression)
6444 */
6445void
6446xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6447 if (doc == NULL) return;
6448 if (mode < 0) doc->compression = 0;
6449 else if (mode > 9) doc->compression = 9;
6450 else doc->compression = mode;
6451}
6452
6453/**
6454 * xmlGetCompressMode:
6455 *
6456 * get the default compression mode used, ZLIB based.
6457 * Returns 0 (uncompressed) to 9 (max compression)
6458 */
6459int
6460 xmlGetCompressMode(void) {
6461 return(xmlCompressMode);
6462}
6463
6464/**
6465 * xmlSetCompressMode:
6466 * @mode: the compression ratio
6467 *
6468 * set the default compression mode used, ZLIB based
6469 * Correct values: 0 (uncompressed) to 9 (max compression)
6470 */
6471void
6472xmlSetCompressMode(int mode) {
6473 if (mode < 0) xmlCompressMode = 0;
6474 else if (mode > 9) xmlCompressMode = 9;
6475 else xmlCompressMode = mode;
6476}
6477
6478/**
6479 * xmlDocDump:
6480 * @f: the FILE*
6481 * @cur: the document
6482 *
6483 * Dump an XML document to an open FILE.
6484 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006485 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006486 */
6487int
6488xmlDocDump(FILE *f, xmlDocPtr cur) {
6489 xmlOutputBufferPtr buf;
6490 const char * encoding;
6491 xmlCharEncodingHandlerPtr handler = NULL;
6492 int ret;
6493
6494 if (cur == NULL) {
6495#ifdef DEBUG_TREE
6496 xmlGenericError(xmlGenericErrorContext,
6497 "xmlDocDump : document == NULL\n");
6498#endif
6499 return(-1);
6500 }
6501 encoding = (const char *) cur->encoding;
6502
6503 if (encoding != NULL) {
6504 xmlCharEncoding enc;
6505
6506 enc = xmlParseCharEncoding(encoding);
6507
6508 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6509 xmlGenericError(xmlGenericErrorContext,
6510 "xmlDocDump: document not in UTF8\n");
6511 return(-1);
6512 }
6513 if (enc != XML_CHAR_ENCODING_UTF8) {
6514 handler = xmlFindCharEncodingHandler(encoding);
6515 if (handler == NULL) {
6516 xmlFree((char *) cur->encoding);
6517 cur->encoding = NULL;
6518 }
6519 }
6520 }
6521 buf = xmlOutputBufferCreateFile(f, handler);
6522 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006523 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006524
6525 ret = xmlOutputBufferClose(buf);
6526 return(ret);
6527}
6528
6529/**
6530 * xmlSaveFileTo:
6531 * @buf: an output I/O buffer
6532 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006533 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006534 *
6535 * Dump an XML document to an I/O buffer.
6536 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006537 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006538 */
6539int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006540xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006541 int ret;
6542
6543 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006544 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006545 ret = xmlOutputBufferClose(buf);
6546 return(ret);
6547}
6548
6549/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006550 * xmlSaveFormatFileTo:
6551 * @buf: an output I/O buffer
6552 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006553 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006554 * @format: should formatting spaces been added
6555 *
6556 * Dump an XML document to an I/O buffer.
6557 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006558 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006559 */
6560int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006561xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006562 int ret;
6563
6564 if (buf == NULL) return(0);
6565 xmlDocContentDumpOutput(buf, cur, encoding, format);
6566 ret = xmlOutputBufferClose(buf);
6567 return(ret);
6568}
6569
6570/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006571 * xmlSaveFormatFileEnc
6572 * @filename: the filename or URL to output
6573 * @cur: the document being saved
6574 * @encoding: the name of the encoding to use or NULL.
6575 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006576 *
6577 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006578 */
6579int
Daniel Veillardf012a642001-07-23 19:10:52 +00006580xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6581 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006582 xmlOutputBufferPtr buf;
6583 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006584 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006585 int ret;
6586
6587 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006588
6589 enc = xmlParseCharEncoding(encoding);
6590 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6591 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006592 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006593 return(-1);
6594 }
6595 if (enc != XML_CHAR_ENCODING_UTF8) {
6596 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006597 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006598 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006599 }
6600 }
6601
Daniel Veillardf012a642001-07-23 19:10:52 +00006602#ifdef HAVE_ZLIB_H
6603 if (cur->compression < 0) cur->compression = xmlCompressMode;
6604#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006605 /*
6606 * save the content to a temp buffer.
6607 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006608 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006609 if (buf == NULL) return(-1);
6610
Daniel Veillardf012a642001-07-23 19:10:52 +00006611 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006612
6613 ret = xmlOutputBufferClose(buf);
6614 return(ret);
6615}
6616
Daniel Veillardf012a642001-07-23 19:10:52 +00006617
6618/**
6619 * xmlSaveFileEnc:
6620 * @filename: the filename (or URL)
6621 * @cur: the document
6622 * @encoding: the name of an encoding (or NULL)
6623 *
6624 * Dump an XML document, converting it to the given encoding
6625 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006626 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006627 */
6628int
6629xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6630 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6631}
6632
Owen Taylor3473f882001-02-23 17:55:21 +00006633/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006634 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006635 * @filename: the filename (or URL)
6636 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006637 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006638 *
6639 * Dump an XML document to a file. Will use compression if
6640 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006641 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006642 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006643 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006644 */
6645int
Daniel Veillard67fee942001-04-26 18:59:03 +00006646xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006647 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006648}
6649
Daniel Veillard67fee942001-04-26 18:59:03 +00006650/**
6651 * xmlSaveFile:
6652 * @filename: the filename (or URL)
6653 * @cur: the document
6654 *
6655 * Dump an XML document to a file. Will use compression if
6656 * compiled in and enabled. If @filename is "-" the stdout file is
6657 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006658 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006659 */
6660int
6661xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006662 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006663}
6664