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