blob: eee620b50ab8eb4ddf27672783f19811a9583cc6 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
12 */
13
Daniel Veillard34ce8be2002-03-18 19:37:11 +000014#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000015#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000016
Owen Taylor3473f882001-02-23 17:55:21 +000017#include <string.h> /* for memset() only ! */
18
19#ifdef HAVE_CTYPE_H
20#include <ctype.h>
21#endif
22#ifdef HAVE_STDLIB_H
23#include <stdlib.h>
24#endif
25#ifdef HAVE_ZLIB_H
26#include <zlib.h>
27#endif
28
29#include <libxml/xmlmemory.h>
30#include <libxml/tree.h>
31#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000032#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000033#include <libxml/entities.h>
34#include <libxml/valid.h>
35#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000036#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000037#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000038
Daniel Veillard56a4cb82001-03-24 17:00:36 +000039xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
40
41/************************************************************************
42 * *
43 * A few static variables and macros *
44 * *
45 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000046/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000047const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000050 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000051/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000052const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
53
Owen Taylor3473f882001-02-23 17:55:21 +000054static int xmlCompressMode = 0;
55static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000056
Owen Taylor3473f882001-02-23 17:55:21 +000057#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
58 xmlNodePtr ulccur = (n)->children; \
59 if (ulccur == NULL) { \
60 (n)->last = NULL; \
61 } else { \
62 while (ulccur->next != NULL) { \
63 ulccur->parent = (n); \
64 ulccur = ulccur->next; \
65 } \
66 ulccur->parent = (n); \
67 (n)->last = ulccur; \
68}}
69
70/* #define DEBUG_BUFFER */
71/* #define DEBUG_TREE */
72
73/************************************************************************
74 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000075 * Functions to move to entities.c once the *
76 * API freeze is smoothen and they can be made public. *
77 * *
78 ************************************************************************/
79#include <libxml/hash.h>
80
81/**
82 * xmlGetEntityFromDtd:
83 * @dtd: A pointer to the DTD to search
84 * @name: The entity name
85 *
86 * Do an entity lookup in the DTD entity hash table and
87 * return the corresponding entity, if found.
88 *
89 * Returns A pointer to the entity structure or NULL if not found.
90 */
91static xmlEntityPtr
92xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
93 xmlEntitiesTablePtr table;
94
95 if((dtd != NULL) && (dtd->entities != NULL)) {
96 table = (xmlEntitiesTablePtr) dtd->entities;
97 return((xmlEntityPtr) xmlHashLookup(table, name));
98 /* return(xmlGetEntityFromTable(table, name)); */
99 }
100 return(NULL);
101}
102/**
103 * xmlGetParameterEntityFromDtd:
104 * @dtd: A pointer to the DTD to search
105 * @name: The entity name
106 *
107 * Do an entity lookup in the DTD pararmeter entity hash table and
108 * return the corresponding entity, if found.
109 *
110 * Returns A pointer to the entity structure or NULL if not found.
111 */
112static xmlEntityPtr
113xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
114 xmlEntitiesTablePtr table;
115
116 if ((dtd != NULL) && (dtd->pentities != NULL)) {
117 table = (xmlEntitiesTablePtr) dtd->pentities;
118 return((xmlEntityPtr) xmlHashLookup(table, name));
119 /* return(xmlGetEntityFromTable(table, name)); */
120 }
121 return(NULL);
122}
123
124/************************************************************************
125 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000126 * Allocation and deallocation of basic structures *
127 * *
128 ************************************************************************/
129
130/**
131 * xmlSetBufferAllocationScheme:
132 * @scheme: allocation method to use
133 *
134 * Set the buffer allocation method. Types are
135 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
136 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
137 * improves performance
138 */
139void
140xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
141 xmlBufferAllocScheme = scheme;
142}
143
144/**
145 * xmlGetBufferAllocationScheme:
146 *
147 * Types are
148 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
149 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
150 * improves performance
151 *
152 * Returns the current allocation scheme
153 */
154xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000155xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000156 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000157}
158
159/**
160 * xmlNewNs:
161 * @node: the element carrying the namespace
162 * @href: the URI associated
163 * @prefix: the prefix for the namespace
164 *
165 * Creation of a new Namespace. This function will refuse to create
166 * a namespace with a similar prefix than an existing one present on this
167 * node.
168 * We use href==NULL in the case of an element creation where the namespace
169 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000170 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000171 */
172xmlNsPtr
173xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
174 xmlNsPtr cur;
175
176 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
177 return(NULL);
178
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000179 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
180 return(NULL);
181
Owen Taylor3473f882001-02-23 17:55:21 +0000182 /*
183 * Allocate a new Namespace and fill the fields.
184 */
185 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
186 if (cur == NULL) {
187 xmlGenericError(xmlGenericErrorContext,
188 "xmlNewNs : malloc failed\n");
189 return(NULL);
190 }
191 memset(cur, 0, sizeof(xmlNs));
192 cur->type = XML_LOCAL_NAMESPACE;
193
194 if (href != NULL)
195 cur->href = xmlStrdup(href);
196 if (prefix != NULL)
197 cur->prefix = xmlStrdup(prefix);
198
199 /*
200 * Add it at the end to preserve parsing order ...
201 * and checks for existing use of the prefix
202 */
203 if (node != NULL) {
204 if (node->nsDef == NULL) {
205 node->nsDef = cur;
206 } else {
207 xmlNsPtr prev = node->nsDef;
208
209 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
210 (xmlStrEqual(prev->prefix, cur->prefix))) {
211 xmlFreeNs(cur);
212 return(NULL);
213 }
214 while (prev->next != NULL) {
215 prev = prev->next;
216 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
217 (xmlStrEqual(prev->prefix, cur->prefix))) {
218 xmlFreeNs(cur);
219 return(NULL);
220 }
221 }
222 prev->next = cur;
223 }
224 }
225 return(cur);
226}
227
228/**
229 * xmlSetNs:
230 * @node: a node in the document
231 * @ns: a namespace pointer
232 *
233 * Associate a namespace to a node, a posteriori.
234 */
235void
236xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
237 if (node == NULL) {
238#ifdef DEBUG_TREE
239 xmlGenericError(xmlGenericErrorContext,
240 "xmlSetNs: node == NULL\n");
241#endif
242 return;
243 }
244 node->ns = ns;
245}
246
247/**
248 * xmlFreeNs:
249 * @cur: the namespace pointer
250 *
251 * Free up the structures associated to a namespace
252 */
253void
254xmlFreeNs(xmlNsPtr cur) {
255 if (cur == NULL) {
256#ifdef DEBUG_TREE
257 xmlGenericError(xmlGenericErrorContext,
258 "xmlFreeNs : ns == NULL\n");
259#endif
260 return;
261 }
262 if (cur->href != NULL) xmlFree((char *) cur->href);
263 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000264 xmlFree(cur);
265}
266
267/**
268 * xmlFreeNsList:
269 * @cur: the first namespace pointer
270 *
271 * Free up all the structures associated to the chained namespaces.
272 */
273void
274xmlFreeNsList(xmlNsPtr cur) {
275 xmlNsPtr next;
276 if (cur == NULL) {
277#ifdef DEBUG_TREE
278 xmlGenericError(xmlGenericErrorContext,
279 "xmlFreeNsList : ns == NULL\n");
280#endif
281 return;
282 }
283 while (cur != NULL) {
284 next = cur->next;
285 xmlFreeNs(cur);
286 cur = next;
287 }
288}
289
290/**
291 * xmlNewDtd:
292 * @doc: the document pointer
293 * @name: the DTD name
294 * @ExternalID: the external ID
295 * @SystemID: the system ID
296 *
297 * Creation of a new DTD for the external subset. To create an
298 * internal subset, use xmlCreateIntSubset().
299 *
300 * Returns a pointer to the new DTD structure
301 */
302xmlDtdPtr
303xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
304 const xmlChar *ExternalID, const xmlChar *SystemID) {
305 xmlDtdPtr cur;
306
307 if ((doc != NULL) && (doc->extSubset != NULL)) {
308#ifdef DEBUG_TREE
309 xmlGenericError(xmlGenericErrorContext,
310 "xmlNewDtd(%s): document %s already have a DTD %s\n",
311 /* !!! */ (char *) name, doc->name,
312 /* !!! */ (char *)doc->extSubset->name);
313#endif
314 return(NULL);
315 }
316
317 /*
318 * Allocate a new DTD and fill the fields.
319 */
320 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
321 if (cur == NULL) {
322 xmlGenericError(xmlGenericErrorContext,
323 "xmlNewDtd : malloc failed\n");
324 return(NULL);
325 }
326 memset(cur, 0 , sizeof(xmlDtd));
327 cur->type = XML_DTD_NODE;
328
329 if (name != NULL)
330 cur->name = xmlStrdup(name);
331 if (ExternalID != NULL)
332 cur->ExternalID = xmlStrdup(ExternalID);
333 if (SystemID != NULL)
334 cur->SystemID = xmlStrdup(SystemID);
335 if (doc != NULL)
336 doc->extSubset = cur;
337 cur->doc = doc;
338
339 return(cur);
340}
341
342/**
343 * xmlGetIntSubset:
344 * @doc: the document pointer
345 *
346 * Get the internal subset of a document
347 * Returns a pointer to the DTD structure or NULL if not found
348 */
349
350xmlDtdPtr
351xmlGetIntSubset(xmlDocPtr doc) {
352 xmlNodePtr cur;
353
354 if (doc == NULL)
355 return(NULL);
356 cur = doc->children;
357 while (cur != NULL) {
358 if (cur->type == XML_DTD_NODE)
359 return((xmlDtdPtr) cur);
360 cur = cur->next;
361 }
362 return((xmlDtdPtr) doc->intSubset);
363}
364
365/**
366 * xmlCreateIntSubset:
367 * @doc: the document pointer
368 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000369 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000370 * @SystemID: the system ID
371 *
372 * Create the internal subset of a document
373 * Returns a pointer to the new DTD structure
374 */
375xmlDtdPtr
376xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
377 const xmlChar *ExternalID, const xmlChar *SystemID) {
378 xmlDtdPtr cur;
379
380 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
381#ifdef DEBUG_TREE
382 xmlGenericError(xmlGenericErrorContext,
383
384 "xmlCreateIntSubset(): document %s already have an internal subset\n",
385 doc->name);
386#endif
387 return(NULL);
388 }
389
390 /*
391 * Allocate a new DTD and fill the fields.
392 */
393 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
394 if (cur == NULL) {
395 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000396 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000397 return(NULL);
398 }
399 memset(cur, 0, sizeof(xmlDtd));
400 cur->type = XML_DTD_NODE;
401
402 if (name != NULL)
403 cur->name = xmlStrdup(name);
404 if (ExternalID != NULL)
405 cur->ExternalID = xmlStrdup(ExternalID);
406 if (SystemID != NULL)
407 cur->SystemID = xmlStrdup(SystemID);
408 if (doc != NULL) {
409 doc->intSubset = cur;
410 cur->parent = doc;
411 cur->doc = doc;
412 if (doc->children == NULL) {
413 doc->children = (xmlNodePtr) cur;
414 doc->last = (xmlNodePtr) cur;
415 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000416 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000417 xmlNodePtr prev;
418
Owen Taylor3473f882001-02-23 17:55:21 +0000419 prev = doc->children;
420 prev->prev = (xmlNodePtr) cur;
421 cur->next = prev;
422 doc->children = (xmlNodePtr) cur;
423 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000424 xmlNodePtr next;
425
426 next = doc->children;
427 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
428 next = next->next;
429 if (next == NULL) {
430 cur->prev = doc->last;
431 cur->prev->next = (xmlNodePtr) cur;
432 cur->next = NULL;
433 doc->last = (xmlNodePtr) cur;
434 } else {
435 cur->next = next;
436 cur->prev = next->prev;
437 if (cur->prev == NULL)
438 doc->children = (xmlNodePtr) cur;
439 else
440 cur->prev->next = (xmlNodePtr) cur;
441 next->prev = (xmlNodePtr) cur;
442 }
Owen Taylor3473f882001-02-23 17:55:21 +0000443 }
444 }
445 }
446 return(cur);
447}
448
449/**
450 * xmlFreeDtd:
451 * @cur: the DTD structure to free up
452 *
453 * Free a DTD structure.
454 */
455void
456xmlFreeDtd(xmlDtdPtr cur) {
457 if (cur == NULL) {
458#ifdef DEBUG_TREE
459 xmlGenericError(xmlGenericErrorContext,
460 "xmlFreeDtd : DTD == NULL\n");
461#endif
462 return;
463 }
464 if (cur->children != NULL) {
465 xmlNodePtr next, c = cur->children;
466
467 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000468 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000469 * indexes.
470 */
471 while (c != NULL) {
472 next = c->next;
473 if (c->type == XML_COMMENT_NODE) {
474 xmlUnlinkNode(c);
475 xmlFreeNode(c);
476 }
477 c = next;
478 }
479 }
480 if (cur->name != NULL) xmlFree((char *) cur->name);
481 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
482 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
483 /* TODO !!! */
484 if (cur->notations != NULL)
485 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
486
487 if (cur->elements != NULL)
488 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
489 if (cur->attributes != NULL)
490 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
491 if (cur->entities != NULL)
492 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
493 if (cur->pentities != NULL)
494 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
495
Owen Taylor3473f882001-02-23 17:55:21 +0000496 xmlFree(cur);
497}
498
499/**
500 * xmlNewDoc:
501 * @version: xmlChar string giving the version of XML "1.0"
502 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000503 * Creates a new XML document
504 *
Owen Taylor3473f882001-02-23 17:55:21 +0000505 * Returns a new document
506 */
507xmlDocPtr
508xmlNewDoc(const xmlChar *version) {
509 xmlDocPtr cur;
510
511 if (version == NULL)
512 version = (const xmlChar *) "1.0";
513
514 /*
515 * Allocate a new document and fill the fields.
516 */
517 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
518 if (cur == NULL) {
519 xmlGenericError(xmlGenericErrorContext,
520 "xmlNewDoc : malloc failed\n");
521 return(NULL);
522 }
523 memset(cur, 0, sizeof(xmlDoc));
524 cur->type = XML_DOCUMENT_NODE;
525
526 cur->version = xmlStrdup(version);
527 cur->standalone = -1;
528 cur->compression = -1; /* not initialized */
529 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000530 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000531 return(cur);
532}
533
534/**
535 * xmlFreeDoc:
536 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000537 *
538 * Free up all the structures used by a document, tree included.
539 */
540void
541xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000542 xmlDtdPtr extSubset, intSubset;
543
Owen Taylor3473f882001-02-23 17:55:21 +0000544 if (cur == NULL) {
545#ifdef DEBUG_TREE
546 xmlGenericError(xmlGenericErrorContext,
547 "xmlFreeDoc : document == NULL\n");
548#endif
549 return;
550 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000551 /*
552 * Do this before freeing the children list to avoid ID lookups
553 */
554 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
555 cur->ids = NULL;
556 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
557 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000558 extSubset = cur->extSubset;
559 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000560 if (intSubset == extSubset)
561 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000562 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000563 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000564 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000565 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000567 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000569 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000570 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000571 }
572
573 if (cur->children != NULL) xmlFreeNodeList(cur->children);
574
Owen Taylor3473f882001-02-23 17:55:21 +0000575 if (cur->version != NULL) xmlFree((char *) cur->version);
576 if (cur->name != NULL) xmlFree((char *) cur->name);
577 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000578 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000579 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000580 xmlFree(cur);
581}
582
583/**
584 * xmlStringLenGetNodeList:
585 * @doc: the document
586 * @value: the value of the text
587 * @len: the length of the string value
588 *
589 * Parse the value string and build the node list associated. Should
590 * produce a flat tree with only TEXTs and ENTITY_REFs.
591 * Returns a pointer to the first child
592 */
593xmlNodePtr
594xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
595 xmlNodePtr ret = NULL, last = NULL;
596 xmlNodePtr node;
597 xmlChar *val;
598 const xmlChar *cur = value;
599 const xmlChar *q;
600 xmlEntityPtr ent;
601
602 if (value == NULL) return(NULL);
603
604 q = cur;
605 while ((*cur != 0) && (cur - value < len)) {
606 if (*cur == '&') {
607 /*
608 * Save the current text.
609 */
610 if (cur != q) {
611 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
612 xmlNodeAddContentLen(last, q, cur - q);
613 } else {
614 node = xmlNewDocTextLen(doc, q, cur - q);
615 if (node == NULL) return(ret);
616 if (last == NULL)
617 last = ret = node;
618 else {
619 last->next = node;
620 node->prev = last;
621 last = node;
622 }
623 }
624 }
625 /*
626 * Read the entity string
627 */
628 cur++;
629 q = cur;
630 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
631 if ((*cur == 0) || (cur - value >= len)) {
632#ifdef DEBUG_TREE
633 xmlGenericError(xmlGenericErrorContext,
634 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
635#endif
636 return(ret);
637 }
638 if (cur != q) {
639 /*
640 * Predefined entities don't generate nodes
641 */
642 val = xmlStrndup(q, cur - q);
643 ent = xmlGetDocEntity(doc, val);
644 if ((ent != NULL) &&
645 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
646 if (last == NULL) {
647 node = xmlNewDocText(doc, ent->content);
648 last = ret = node;
649 } else
650 xmlNodeAddContent(last, ent->content);
651
652 } else {
653 /*
654 * Create a new REFERENCE_REF node
655 */
656 node = xmlNewReference(doc, val);
657 if (node == NULL) {
658 if (val != NULL) xmlFree(val);
659 return(ret);
660 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000661 else if ((ent != NULL) && (ent->children == NULL)) {
662 xmlNodePtr tmp;
663
664 ent->children =
665 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
666 tmp = ent->children;
667 while (tmp) {
668 tmp->parent = (xmlNodePtr)ent;
669 tmp = tmp->next;
670 }
671 }
Owen Taylor3473f882001-02-23 17:55:21 +0000672 if (last == NULL)
673 last = ret = node;
674 else {
675 last->next = node;
676 node->prev = last;
677 last = node;
678 }
679 }
680 xmlFree(val);
681 }
682 cur++;
683 q = cur;
684 } else
685 cur++;
686 }
687 if (cur != q) {
688 /*
689 * Handle the last piece of text.
690 */
691 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
692 xmlNodeAddContentLen(last, q, cur - q);
693 } else {
694 node = xmlNewDocTextLen(doc, q, cur - q);
695 if (node == NULL) return(ret);
696 if (last == NULL)
697 last = ret = node;
698 else {
699 last->next = node;
700 node->prev = last;
701 last = node;
702 }
703 }
704 }
705 return(ret);
706}
707
708/**
709 * xmlStringGetNodeList:
710 * @doc: the document
711 * @value: the value of the attribute
712 *
713 * Parse the value string and build the node list associated. Should
714 * produce a flat tree with only TEXTs and ENTITY_REFs.
715 * Returns a pointer to the first child
716 */
717xmlNodePtr
718xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
719 xmlNodePtr ret = NULL, last = NULL;
720 xmlNodePtr node;
721 xmlChar *val;
722 const xmlChar *cur = value;
723 const xmlChar *q;
724 xmlEntityPtr ent;
725
726 if (value == NULL) return(NULL);
727
728 q = cur;
729 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000730 if (cur[0] == '&') {
731 int charval = 0;
732 xmlChar tmp;
733
Owen Taylor3473f882001-02-23 17:55:21 +0000734 /*
735 * Save the current text.
736 */
737 if (cur != q) {
738 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
739 xmlNodeAddContentLen(last, q, cur - q);
740 } else {
741 node = xmlNewDocTextLen(doc, q, cur - q);
742 if (node == NULL) return(ret);
743 if (last == NULL)
744 last = ret = node;
745 else {
746 last->next = node;
747 node->prev = last;
748 last = node;
749 }
750 }
751 }
Owen Taylor3473f882001-02-23 17:55:21 +0000752 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000753 if ((cur[1] == '#') && (cur[2] == 'x')) {
754 cur += 3;
755 tmp = *cur;
756 while (tmp != ';') { /* Non input consuming loop */
757 if ((tmp >= '0') && (tmp <= '9'))
758 charval = charval * 16 + (tmp - '0');
759 else if ((tmp >= 'a') && (tmp <= 'f'))
760 charval = charval * 16 + (tmp - 'a') + 10;
761 else if ((tmp >= 'A') && (tmp <= 'F'))
762 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000763 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000764 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000765 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000766 charval = 0;
767 break;
768 }
769 cur++;
770 tmp = *cur;
771 }
772 if (tmp == ';')
773 cur++;
774 q = cur;
775 } else if (cur[1] == '#') {
776 cur += 2;
777 tmp = *cur;
778 while (tmp != ';') { /* Non input consuming loops */
779 if ((tmp >= '0') && (tmp <= '9'))
780 charval = charval * 10 + (tmp - '0');
781 else {
782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000783 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000784 charval = 0;
785 break;
786 }
787 cur++;
788 tmp = *cur;
789 }
790 if (tmp == ';')
791 cur++;
792 q = cur;
793 } else {
794 /*
795 * Read the entity string
796 */
797 cur++;
798 q = cur;
799 while ((*cur != 0) && (*cur != ';')) cur++;
800 if (*cur == 0) {
801#ifdef DEBUG_TREE
802 xmlGenericError(xmlGenericErrorContext,
803 "xmlStringGetNodeList: unterminated entity %30s\n", q);
804#endif
805 return(ret);
806 }
807 if (cur != q) {
808 /*
809 * Predefined entities don't generate nodes
810 */
811 val = xmlStrndup(q, cur - q);
812 ent = xmlGetDocEntity(doc, val);
813 if ((ent != NULL) &&
814 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
815 if (last == NULL) {
816 node = xmlNewDocText(doc, ent->content);
817 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000818 } else if (last->type != XML_TEXT_NODE) {
819 node = xmlNewDocText(doc, ent->content);
820 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000821 } else
822 xmlNodeAddContent(last, ent->content);
823
824 } else {
825 /*
826 * Create a new REFERENCE_REF node
827 */
828 node = xmlNewReference(doc, val);
829 if (node == NULL) {
830 if (val != NULL) xmlFree(val);
831 return(ret);
832 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000833 else if ((ent != NULL) && (ent->children == NULL)) {
834 xmlNodePtr temp;
835
836 ent->children = xmlStringGetNodeList(doc,
837 (const xmlChar*)node->content);
838 temp = ent->children;
839 while (temp) {
840 temp->parent = (xmlNodePtr)ent;
841 temp = temp->next;
842 }
843 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000844 if (last == NULL) {
845 last = ret = node;
846 } else {
847 last = xmlAddNextSibling(last, node);
848 }
849 }
850 xmlFree(val);
851 }
852 cur++;
853 q = cur;
854 }
855 if (charval != 0) {
856 xmlChar buf[10];
857 int len;
858
859 len = xmlCopyCharMultiByte(buf, charval);
860 buf[len] = 0;
861 node = xmlNewDocText(doc, buf);
862 if (node != NULL) {
863 if (last == NULL) {
864 last = ret = node;
865 } else {
866 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000867 }
868 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000869
870 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000871 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000872 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000873 cur++;
874 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000875 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000876 /*
877 * Handle the last piece of text.
878 */
879 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
880 xmlNodeAddContentLen(last, q, cur - q);
881 } else {
882 node = xmlNewDocTextLen(doc, q, cur - q);
883 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000884 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000885 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000886 } else {
887 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000888 }
889 }
890 }
891 return(ret);
892}
893
894/**
895 * xmlNodeListGetString:
896 * @doc: the document
897 * @list: a Node list
898 * @inLine: should we replace entity contents or show their external form
899 *
900 * Returns the string equivalent to the text contained in the Node list
901 * made of TEXTs and ENTITY_REFs
Daniel Veillardd1640922001-12-17 15:30:10 +0000902 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000903 */
904xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000905xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
906{
Owen Taylor3473f882001-02-23 17:55:21 +0000907 xmlNodePtr node = list;
908 xmlChar *ret = NULL;
909 xmlEntityPtr ent;
910
Daniel Veillard7646b182002-04-20 06:41:40 +0000911 if (list == NULL)
912 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000913
914 while (node != NULL) {
915 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000916 (node->type == XML_CDATA_SECTION_NODE)) {
917 if (inLine) {
918 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000919 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000920 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000921
Daniel Veillard7646b182002-04-20 06:41:40 +0000922 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
923 if (buffer != NULL) {
924 ret = xmlStrcat(ret, buffer);
925 xmlFree(buffer);
926 }
927 }
928 } else if (node->type == XML_ENTITY_REF_NODE) {
929 if (inLine) {
930 ent = xmlGetDocEntity(doc, node->name);
931 if (ent != NULL) {
932 xmlChar *buffer;
933
934 /* an entity content can be any "well balanced chunk",
935 * i.e. the result of the content [43] production:
936 * http://www.w3.org/TR/REC-xml#NT-content.
937 * So it can contain text, CDATA section or nested
938 * entity reference nodes (among others).
939 * -> we recursive call xmlNodeListGetString()
940 * which handles these types */
941 buffer = xmlNodeListGetString(doc, ent->children, 1);
942 if (buffer != NULL) {
943 ret = xmlStrcat(ret, buffer);
944 xmlFree(buffer);
945 }
946 } else {
947 ret = xmlStrcat(ret, node->content);
948 }
949 } else {
950 xmlChar buf[2];
951
952 buf[0] = '&';
953 buf[1] = 0;
954 ret = xmlStrncat(ret, buf, 1);
955 ret = xmlStrcat(ret, node->name);
956 buf[0] = ';';
957 buf[1] = 0;
958 ret = xmlStrncat(ret, buf, 1);
959 }
960 }
961#if 0
962 else {
963 xmlGenericError(xmlGenericErrorContext,
964 "xmlGetNodeListString : invalid node type %d\n",
965 node->type);
966 }
967#endif
968 node = node->next;
969 }
970 return (ret);
971}
Owen Taylor3473f882001-02-23 17:55:21 +0000972/**
973 * xmlNodeListGetRawString:
974 * @doc: the document
975 * @list: a Node list
976 * @inLine: should we replace entity contents or show their external form
977 *
978 * Returns the string equivalent to the text contained in the Node list
979 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
980 * this function doesn't do any character encoding handling.
981 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000982 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000983 */
984xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000985xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
986{
Owen Taylor3473f882001-02-23 17:55:21 +0000987 xmlNodePtr node = list;
988 xmlChar *ret = NULL;
989 xmlEntityPtr ent;
990
Daniel Veillard7646b182002-04-20 06:41:40 +0000991 if (list == NULL)
992 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000993
994 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000995 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000996 (node->type == XML_CDATA_SECTION_NODE)) {
997 if (inLine) {
998 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001000 xmlChar *buffer;
1001
1002 buffer = xmlEncodeSpecialChars(doc, node->content);
1003 if (buffer != NULL) {
1004 ret = xmlStrcat(ret, buffer);
1005 xmlFree(buffer);
1006 }
1007 }
1008 } else if (node->type == XML_ENTITY_REF_NODE) {
1009 if (inLine) {
1010 ent = xmlGetDocEntity(doc, node->name);
1011 if (ent != NULL) {
1012 xmlChar *buffer;
1013
1014 /* an entity content can be any "well balanced chunk",
1015 * i.e. the result of the content [43] production:
1016 * http://www.w3.org/TR/REC-xml#NT-content.
1017 * So it can contain text, CDATA section or nested
1018 * entity reference nodes (among others).
1019 * -> we recursive call xmlNodeListGetRawString()
1020 * which handles these types */
1021 buffer =
1022 xmlNodeListGetRawString(doc, ent->children, 1);
1023 if (buffer != NULL) {
1024 ret = xmlStrcat(ret, buffer);
1025 xmlFree(buffer);
1026 }
1027 } else {
1028 ret = xmlStrcat(ret, node->content);
1029 }
1030 } else {
1031 xmlChar buf[2];
1032
1033 buf[0] = '&';
1034 buf[1] = 0;
1035 ret = xmlStrncat(ret, buf, 1);
1036 ret = xmlStrcat(ret, node->name);
1037 buf[0] = ';';
1038 buf[1] = 0;
1039 ret = xmlStrncat(ret, buf, 1);
1040 }
1041 }
Owen Taylor3473f882001-02-23 17:55:21 +00001042#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001043 else {
1044 xmlGenericError(xmlGenericErrorContext,
1045 "xmlGetNodeListString : invalid node type %d\n",
1046 node->type);
1047 }
Owen Taylor3473f882001-02-23 17:55:21 +00001048#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001049 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001050 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001051 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001052}
1053
1054/**
1055 * xmlNewProp:
1056 * @node: the holding node
1057 * @name: the name of the attribute
1058 * @value: the value of the attribute
1059 *
1060 * Create a new property carried by a node.
1061 * Returns a pointer to the attribute
1062 */
1063xmlAttrPtr
1064xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1065 xmlAttrPtr cur;
1066 xmlDocPtr doc = NULL;
1067
1068 if (name == NULL) {
1069#ifdef DEBUG_TREE
1070 xmlGenericError(xmlGenericErrorContext,
1071 "xmlNewProp : name == NULL\n");
1072#endif
1073 return(NULL);
1074 }
1075
1076 /*
1077 * Allocate a new property and fill the fields.
1078 */
1079 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1080 if (cur == NULL) {
1081 xmlGenericError(xmlGenericErrorContext,
1082 "xmlNewProp : malloc failed\n");
1083 return(NULL);
1084 }
1085 memset(cur, 0, sizeof(xmlAttr));
1086 cur->type = XML_ATTRIBUTE_NODE;
1087
1088 cur->parent = node;
1089 if (node != NULL) {
1090 doc = node->doc;
1091 cur->doc = doc;
1092 }
1093 cur->name = xmlStrdup(name);
1094 if (value != NULL) {
1095 xmlChar *buffer;
1096 xmlNodePtr tmp;
1097
1098 buffer = xmlEncodeEntitiesReentrant(doc, value);
1099 cur->children = xmlStringGetNodeList(doc, buffer);
1100 cur->last = NULL;
1101 tmp = cur->children;
1102 while (tmp != NULL) {
1103 tmp->parent = (xmlNodePtr) cur;
1104 tmp->doc = doc;
1105 if (tmp->next == NULL)
1106 cur->last = tmp;
1107 tmp = tmp->next;
1108 }
1109 xmlFree(buffer);
1110 }
1111
1112 /*
1113 * Add it at the end to preserve parsing order ...
1114 */
1115 if (node != NULL) {
1116 if (node->properties == NULL) {
1117 node->properties = cur;
1118 } else {
1119 xmlAttrPtr prev = node->properties;
1120
1121 while (prev->next != NULL) prev = prev->next;
1122 prev->next = cur;
1123 cur->prev = prev;
1124 }
1125 }
1126 return(cur);
1127}
1128
1129/**
1130 * xmlNewNsProp:
1131 * @node: the holding node
1132 * @ns: the namespace
1133 * @name: the name of the attribute
1134 * @value: the value of the attribute
1135 *
1136 * Create a new property tagged with a namespace and carried by a node.
1137 * Returns a pointer to the attribute
1138 */
1139xmlAttrPtr
1140xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1141 const xmlChar *value) {
1142 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001143 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001144
1145 if (name == NULL) {
1146#ifdef DEBUG_TREE
1147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001148 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001149#endif
1150 return(NULL);
1151 }
1152
1153 /*
1154 * Allocate a new property and fill the fields.
1155 */
1156 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1157 if (cur == NULL) {
1158 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001159 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001160 return(NULL);
1161 }
1162 memset(cur, 0, sizeof(xmlAttr));
1163 cur->type = XML_ATTRIBUTE_NODE;
1164
1165 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001166 if (node != NULL) {
1167 doc = node->doc;
1168 cur->doc = doc;
1169 }
Owen Taylor3473f882001-02-23 17:55:21 +00001170 cur->ns = ns;
1171 cur->name = xmlStrdup(name);
1172 if (value != NULL) {
1173 xmlChar *buffer;
1174 xmlNodePtr tmp;
1175
Daniel Veillarda682b212001-06-07 19:59:42 +00001176 buffer = xmlEncodeEntitiesReentrant(doc, value);
1177 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001178 cur->last = NULL;
1179 tmp = cur->children;
1180 while (tmp != NULL) {
1181 tmp->parent = (xmlNodePtr) cur;
1182 if (tmp->next == NULL)
1183 cur->last = tmp;
1184 tmp = tmp->next;
1185 }
1186 xmlFree(buffer);
1187 }
1188
1189 /*
1190 * Add it at the end to preserve parsing order ...
1191 */
1192 if (node != NULL) {
1193 if (node->properties == NULL) {
1194 node->properties = cur;
1195 } else {
1196 xmlAttrPtr prev = node->properties;
1197
1198 while (prev->next != NULL) prev = prev->next;
1199 prev->next = cur;
1200 cur->prev = prev;
1201 }
1202 }
1203 return(cur);
1204}
1205
1206/**
1207 * xmlNewDocProp:
1208 * @doc: the document
1209 * @name: the name of the attribute
1210 * @value: the value of the attribute
1211 *
1212 * Create a new property carried by a document.
1213 * Returns a pointer to the attribute
1214 */
1215xmlAttrPtr
1216xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1217 xmlAttrPtr cur;
1218
1219 if (name == NULL) {
1220#ifdef DEBUG_TREE
1221 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001222 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001223#endif
1224 return(NULL);
1225 }
1226
1227 /*
1228 * Allocate a new property and fill the fields.
1229 */
1230 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1231 if (cur == NULL) {
1232 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001233 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001234 return(NULL);
1235 }
1236 memset(cur, 0, sizeof(xmlAttr));
1237 cur->type = XML_ATTRIBUTE_NODE;
1238
1239 cur->name = xmlStrdup(name);
1240 cur->doc = doc;
1241 if (value != NULL) {
1242 xmlNodePtr tmp;
1243
1244 cur->children = xmlStringGetNodeList(doc, value);
1245 cur->last = NULL;
1246
1247 tmp = cur->children;
1248 while (tmp != NULL) {
1249 tmp->parent = (xmlNodePtr) cur;
1250 if (tmp->next == NULL)
1251 cur->last = tmp;
1252 tmp = tmp->next;
1253 }
1254 }
1255 return(cur);
1256}
1257
1258/**
1259 * xmlFreePropList:
1260 * @cur: the first property in the list
1261 *
1262 * Free a property and all its siblings, all the children are freed too.
1263 */
1264void
1265xmlFreePropList(xmlAttrPtr cur) {
1266 xmlAttrPtr next;
1267 if (cur == NULL) {
1268#ifdef DEBUG_TREE
1269 xmlGenericError(xmlGenericErrorContext,
1270 "xmlFreePropList : property == NULL\n");
1271#endif
1272 return;
1273 }
1274 while (cur != NULL) {
1275 next = cur->next;
1276 xmlFreeProp(cur);
1277 cur = next;
1278 }
1279}
1280
1281/**
1282 * xmlFreeProp:
1283 * @cur: an attribute
1284 *
1285 * Free one attribute, all the content is freed too
1286 */
1287void
1288xmlFreeProp(xmlAttrPtr cur) {
1289 if (cur == NULL) {
1290#ifdef DEBUG_TREE
1291 xmlGenericError(xmlGenericErrorContext,
1292 "xmlFreeProp : property == NULL\n");
1293#endif
1294 return;
1295 }
1296 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001297 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1298 ((cur->parent->doc->intSubset != NULL) ||
1299 (cur->parent->doc->extSubset != NULL))) {
1300 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1301 xmlRemoveID(cur->parent->doc, cur);
1302 }
Owen Taylor3473f882001-02-23 17:55:21 +00001303 if (cur->name != NULL) xmlFree((char *) cur->name);
1304 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001305 xmlFree(cur);
1306}
1307
1308/**
1309 * xmlRemoveProp:
1310 * @cur: an attribute
1311 *
1312 * Unlink and free one attribute, all the content is freed too
1313 * Note this doesn't work for namespace definition attributes
1314 *
1315 * Returns 0 if success and -1 in case of error.
1316 */
1317int
1318xmlRemoveProp(xmlAttrPtr cur) {
1319 xmlAttrPtr tmp;
1320 if (cur == NULL) {
1321#ifdef DEBUG_TREE
1322 xmlGenericError(xmlGenericErrorContext,
1323 "xmlRemoveProp : cur == NULL\n");
1324#endif
1325 return(-1);
1326 }
1327 if (cur->parent == NULL) {
1328#ifdef DEBUG_TREE
1329 xmlGenericError(xmlGenericErrorContext,
1330 "xmlRemoveProp : cur->parent == NULL\n");
1331#endif
1332 return(-1);
1333 }
1334 tmp = cur->parent->properties;
1335 if (tmp == cur) {
1336 cur->parent->properties = cur->next;
1337 xmlFreeProp(cur);
1338 return(0);
1339 }
1340 while (tmp != NULL) {
1341 if (tmp->next == cur) {
1342 tmp->next = cur->next;
1343 if (tmp->next != NULL)
1344 tmp->next->prev = tmp;
1345 xmlFreeProp(cur);
1346 return(0);
1347 }
1348 tmp = tmp->next;
1349 }
1350#ifdef DEBUG_TREE
1351 xmlGenericError(xmlGenericErrorContext,
1352 "xmlRemoveProp : attribute not owned by its node\n");
1353#endif
1354 return(-1);
1355}
1356
1357/**
1358 * xmlNewPI:
1359 * @name: the processing instruction name
1360 * @content: the PI content
1361 *
1362 * Creation of a processing instruction element.
1363 * Returns a pointer to the new node object.
1364 */
1365xmlNodePtr
1366xmlNewPI(const xmlChar *name, const xmlChar *content) {
1367 xmlNodePtr cur;
1368
1369 if (name == NULL) {
1370#ifdef DEBUG_TREE
1371 xmlGenericError(xmlGenericErrorContext,
1372 "xmlNewPI : name == NULL\n");
1373#endif
1374 return(NULL);
1375 }
1376
1377 /*
1378 * Allocate a new node and fill the fields.
1379 */
1380 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1381 if (cur == NULL) {
1382 xmlGenericError(xmlGenericErrorContext,
1383 "xmlNewPI : malloc failed\n");
1384 return(NULL);
1385 }
1386 memset(cur, 0, sizeof(xmlNode));
1387 cur->type = XML_PI_NODE;
1388
1389 cur->name = xmlStrdup(name);
1390 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001391 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001392 }
1393 return(cur);
1394}
1395
1396/**
1397 * xmlNewNode:
1398 * @ns: namespace if any
1399 * @name: the node name
1400 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001401 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001402 *
1403 * Returns a pointer to the new node object.
1404 */
1405xmlNodePtr
1406xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1407 xmlNodePtr cur;
1408
1409 if (name == NULL) {
1410#ifdef DEBUG_TREE
1411 xmlGenericError(xmlGenericErrorContext,
1412 "xmlNewNode : name == NULL\n");
1413#endif
1414 return(NULL);
1415 }
1416
1417 /*
1418 * Allocate a new node and fill the fields.
1419 */
1420 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1421 if (cur == NULL) {
1422 xmlGenericError(xmlGenericErrorContext,
1423 "xmlNewNode : malloc failed\n");
1424 return(NULL);
1425 }
1426 memset(cur, 0, sizeof(xmlNode));
1427 cur->type = XML_ELEMENT_NODE;
1428
1429 cur->name = xmlStrdup(name);
1430 cur->ns = ns;
1431 return(cur);
1432}
1433
1434/**
1435 * xmlNewDocNode:
1436 * @doc: the document
1437 * @ns: namespace if any
1438 * @name: the node name
1439 * @content: the XML text content if any
1440 *
1441 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001442 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001443 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1444 * references, but XML special chars need to be escaped first by using
1445 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1446 * need entities support.
1447 *
1448 * Returns a pointer to the new node object.
1449 */
1450xmlNodePtr
1451xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1452 const xmlChar *name, const xmlChar *content) {
1453 xmlNodePtr cur;
1454
1455 cur = xmlNewNode(ns, name);
1456 if (cur != NULL) {
1457 cur->doc = doc;
1458 if (content != NULL) {
1459 cur->children = xmlStringGetNodeList(doc, content);
1460 UPDATE_LAST_CHILD_AND_PARENT(cur)
1461 }
1462 }
1463 return(cur);
1464}
1465
1466
1467/**
1468 * xmlNewDocRawNode:
1469 * @doc: the document
1470 * @ns: namespace if any
1471 * @name: the node name
1472 * @content: the text content if any
1473 *
1474 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001475 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001476 *
1477 * Returns a pointer to the new node object.
1478 */
1479xmlNodePtr
1480xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1481 const xmlChar *name, const xmlChar *content) {
1482 xmlNodePtr cur;
1483
1484 cur = xmlNewNode(ns, name);
1485 if (cur != NULL) {
1486 cur->doc = doc;
1487 if (content != NULL) {
1488 cur->children = xmlNewDocText(doc, content);
1489 UPDATE_LAST_CHILD_AND_PARENT(cur)
1490 }
1491 }
1492 return(cur);
1493}
1494
1495/**
1496 * xmlNewDocFragment:
1497 * @doc: the document owning the fragment
1498 *
1499 * Creation of a new Fragment node.
1500 * Returns a pointer to the new node object.
1501 */
1502xmlNodePtr
1503xmlNewDocFragment(xmlDocPtr doc) {
1504 xmlNodePtr cur;
1505
1506 /*
1507 * Allocate a new DocumentFragment node and fill the fields.
1508 */
1509 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1510 if (cur == NULL) {
1511 xmlGenericError(xmlGenericErrorContext,
1512 "xmlNewDocFragment : malloc failed\n");
1513 return(NULL);
1514 }
1515 memset(cur, 0, sizeof(xmlNode));
1516 cur->type = XML_DOCUMENT_FRAG_NODE;
1517
1518 cur->doc = doc;
1519 return(cur);
1520}
1521
1522/**
1523 * xmlNewText:
1524 * @content: the text content
1525 *
1526 * Creation of a new text node.
1527 * Returns a pointer to the new node object.
1528 */
1529xmlNodePtr
1530xmlNewText(const xmlChar *content) {
1531 xmlNodePtr cur;
1532
1533 /*
1534 * Allocate a new node and fill the fields.
1535 */
1536 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1537 if (cur == NULL) {
1538 xmlGenericError(xmlGenericErrorContext,
1539 "xmlNewText : malloc failed\n");
1540 return(NULL);
1541 }
1542 memset(cur, 0, sizeof(xmlNode));
1543 cur->type = XML_TEXT_NODE;
1544
1545 cur->name = xmlStringText;
1546 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001547 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001548 }
1549 return(cur);
1550}
1551
1552/**
1553 * xmlNewTextChild:
1554 * @parent: the parent node
1555 * @ns: a namespace if any
1556 * @name: the name of the child
1557 * @content: the text content of the child if any.
1558 *
1559 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001560 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001561 * a child TEXT node will be created containing the string content.
1562 *
1563 * Returns a pointer to the new node object.
1564 */
1565xmlNodePtr
1566xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1567 const xmlChar *name, const xmlChar *content) {
1568 xmlNodePtr cur, prev;
1569
1570 if (parent == NULL) {
1571#ifdef DEBUG_TREE
1572 xmlGenericError(xmlGenericErrorContext,
1573 "xmlNewTextChild : parent == NULL\n");
1574#endif
1575 return(NULL);
1576 }
1577
1578 if (name == NULL) {
1579#ifdef DEBUG_TREE
1580 xmlGenericError(xmlGenericErrorContext,
1581 "xmlNewTextChild : name == NULL\n");
1582#endif
1583 return(NULL);
1584 }
1585
1586 /*
1587 * Allocate a new node
1588 */
1589 if (ns == NULL)
1590 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1591 else
1592 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1593 if (cur == NULL) return(NULL);
1594
1595 /*
1596 * add the new element at the end of the children list.
1597 */
1598 cur->type = XML_ELEMENT_NODE;
1599 cur->parent = parent;
1600 cur->doc = parent->doc;
1601 if (parent->children == NULL) {
1602 parent->children = cur;
1603 parent->last = cur;
1604 } else {
1605 prev = parent->last;
1606 prev->next = cur;
1607 cur->prev = prev;
1608 parent->last = cur;
1609 }
1610
1611 return(cur);
1612}
1613
1614/**
1615 * xmlNewCharRef:
1616 * @doc: the document
1617 * @name: the char ref string, starting with # or "&# ... ;"
1618 *
1619 * Creation of a new character reference node.
1620 * Returns a pointer to the new node object.
1621 */
1622xmlNodePtr
1623xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1624 xmlNodePtr cur;
1625
1626 /*
1627 * Allocate a new node and fill the fields.
1628 */
1629 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1630 if (cur == NULL) {
1631 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001632 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001633 return(NULL);
1634 }
1635 memset(cur, 0, sizeof(xmlNode));
1636 cur->type = XML_ENTITY_REF_NODE;
1637
1638 cur->doc = doc;
1639 if (name[0] == '&') {
1640 int len;
1641 name++;
1642 len = xmlStrlen(name);
1643 if (name[len - 1] == ';')
1644 cur->name = xmlStrndup(name, len - 1);
1645 else
1646 cur->name = xmlStrndup(name, len);
1647 } else
1648 cur->name = xmlStrdup(name);
1649 return(cur);
1650}
1651
1652/**
1653 * xmlNewReference:
1654 * @doc: the document
1655 * @name: the reference name, or the reference string with & and ;
1656 *
1657 * Creation of a new reference node.
1658 * Returns a pointer to the new node object.
1659 */
1660xmlNodePtr
1661xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1662 xmlNodePtr cur;
1663 xmlEntityPtr ent;
1664
1665 /*
1666 * Allocate a new node and fill the fields.
1667 */
1668 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1669 if (cur == NULL) {
1670 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001671 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001672 return(NULL);
1673 }
1674 memset(cur, 0, sizeof(xmlNode));
1675 cur->type = XML_ENTITY_REF_NODE;
1676
1677 cur->doc = doc;
1678 if (name[0] == '&') {
1679 int len;
1680 name++;
1681 len = xmlStrlen(name);
1682 if (name[len - 1] == ';')
1683 cur->name = xmlStrndup(name, len - 1);
1684 else
1685 cur->name = xmlStrndup(name, len);
1686 } else
1687 cur->name = xmlStrdup(name);
1688
1689 ent = xmlGetDocEntity(doc, cur->name);
1690 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001691 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001692 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001693 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001694 * updated. Not sure if this is 100% correct.
1695 * -George
1696 */
1697 cur->children = (xmlNodePtr) ent;
1698 cur->last = (xmlNodePtr) ent;
1699 }
1700 return(cur);
1701}
1702
1703/**
1704 * xmlNewDocText:
1705 * @doc: the document
1706 * @content: the text content
1707 *
1708 * Creation of a new text node within a document.
1709 * Returns a pointer to the new node object.
1710 */
1711xmlNodePtr
1712xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1713 xmlNodePtr cur;
1714
1715 cur = xmlNewText(content);
1716 if (cur != NULL) cur->doc = doc;
1717 return(cur);
1718}
1719
1720/**
1721 * xmlNewTextLen:
1722 * @content: the text content
1723 * @len: the text len.
1724 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001725 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001726 * Returns a pointer to the new node object.
1727 */
1728xmlNodePtr
1729xmlNewTextLen(const xmlChar *content, int len) {
1730 xmlNodePtr cur;
1731
1732 /*
1733 * Allocate a new node and fill the fields.
1734 */
1735 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1736 if (cur == NULL) {
1737 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001738 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001739 return(NULL);
1740 }
1741 memset(cur, 0, sizeof(xmlNode));
1742 cur->type = XML_TEXT_NODE;
1743
1744 cur->name = xmlStringText;
1745 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001746 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001747 }
1748 return(cur);
1749}
1750
1751/**
1752 * xmlNewDocTextLen:
1753 * @doc: the document
1754 * @content: the text content
1755 * @len: the text len.
1756 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001757 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001758 * text node pertain to a given document.
1759 * Returns a pointer to the new node object.
1760 */
1761xmlNodePtr
1762xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1763 xmlNodePtr cur;
1764
1765 cur = xmlNewTextLen(content, len);
1766 if (cur != NULL) cur->doc = doc;
1767 return(cur);
1768}
1769
1770/**
1771 * xmlNewComment:
1772 * @content: the comment content
1773 *
1774 * Creation of a new node containing a comment.
1775 * Returns a pointer to the new node object.
1776 */
1777xmlNodePtr
1778xmlNewComment(const xmlChar *content) {
1779 xmlNodePtr cur;
1780
1781 /*
1782 * Allocate a new node and fill the fields.
1783 */
1784 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1785 if (cur == NULL) {
1786 xmlGenericError(xmlGenericErrorContext,
1787 "xmlNewComment : malloc failed\n");
1788 return(NULL);
1789 }
1790 memset(cur, 0, sizeof(xmlNode));
1791 cur->type = XML_COMMENT_NODE;
1792
1793 cur->name = xmlStringComment;
1794 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001795 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001796 }
1797 return(cur);
1798}
1799
1800/**
1801 * xmlNewCDataBlock:
1802 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001803 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001804 * @len: the length of the block
1805 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001806 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001807 * Returns a pointer to the new node object.
1808 */
1809xmlNodePtr
1810xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1811 xmlNodePtr cur;
1812
1813 /*
1814 * Allocate a new node and fill the fields.
1815 */
1816 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1817 if (cur == NULL) {
1818 xmlGenericError(xmlGenericErrorContext,
1819 "xmlNewCDataBlock : malloc failed\n");
1820 return(NULL);
1821 }
1822 memset(cur, 0, sizeof(xmlNode));
1823 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001824 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001825
1826 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001827 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001828 }
1829 return(cur);
1830}
1831
1832/**
1833 * xmlNewDocComment:
1834 * @doc: the document
1835 * @content: the comment content
1836 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001837 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001838 * Returns a pointer to the new node object.
1839 */
1840xmlNodePtr
1841xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1842 xmlNodePtr cur;
1843
1844 cur = xmlNewComment(content);
1845 if (cur != NULL) cur->doc = doc;
1846 return(cur);
1847}
1848
1849/**
1850 * xmlSetTreeDoc:
1851 * @tree: the top element
1852 * @doc: the document
1853 *
1854 * update all nodes under the tree to point to the right document
1855 */
1856void
1857xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001858 xmlAttrPtr prop;
1859
Owen Taylor3473f882001-02-23 17:55:21 +00001860 if (tree == NULL)
1861 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001862 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00001863 if(tree->type == XML_ELEMENT_NODE) {
1864 prop = tree->properties;
1865 while (prop != NULL) {
1866 prop->doc = doc;
1867 xmlSetListDoc(prop->children, doc);
1868 prop = prop->next;
1869 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00001870 }
Owen Taylor3473f882001-02-23 17:55:21 +00001871 if (tree->children != NULL)
1872 xmlSetListDoc(tree->children, doc);
1873 tree->doc = doc;
1874 }
1875}
1876
1877/**
1878 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001879 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001880 * @doc: the document
1881 *
1882 * update all nodes in the list to point to the right document
1883 */
1884void
1885xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1886 xmlNodePtr cur;
1887
1888 if (list == NULL)
1889 return;
1890 cur = list;
1891 while (cur != NULL) {
1892 if (cur->doc != doc)
1893 xmlSetTreeDoc(cur, doc);
1894 cur = cur->next;
1895 }
1896}
1897
1898
1899/**
1900 * xmlNewChild:
1901 * @parent: the parent node
1902 * @ns: a namespace if any
1903 * @name: the name of the child
1904 * @content: the XML content of the child if any.
1905 *
1906 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001907 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001908 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1909 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1910 * references, but XML special chars need to be escaped first by using
1911 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1912 * support is not needed.
1913 *
1914 * Returns a pointer to the new node object.
1915 */
1916xmlNodePtr
1917xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1918 const xmlChar *name, const xmlChar *content) {
1919 xmlNodePtr cur, prev;
1920
1921 if (parent == NULL) {
1922#ifdef DEBUG_TREE
1923 xmlGenericError(xmlGenericErrorContext,
1924 "xmlNewChild : parent == NULL\n");
1925#endif
1926 return(NULL);
1927 }
1928
1929 if (name == NULL) {
1930#ifdef DEBUG_TREE
1931 xmlGenericError(xmlGenericErrorContext,
1932 "xmlNewChild : name == NULL\n");
1933#endif
1934 return(NULL);
1935 }
1936
1937 /*
1938 * Allocate a new node
1939 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00001940 if (parent->type == XML_ELEMENT_NODE) {
1941 if (ns == NULL)
1942 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1943 else
1944 cur = xmlNewDocNode(parent->doc, ns, name, content);
1945 } else if ((parent->type == XML_DOCUMENT_NODE) ||
1946 (parent->type == XML_HTML_DOCUMENT_NODE)) {
1947 if (ns == NULL)
1948 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
1949 else
1950 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
1951 } else {
1952 return(NULL);
1953 }
Owen Taylor3473f882001-02-23 17:55:21 +00001954 if (cur == NULL) return(NULL);
1955
1956 /*
1957 * add the new element at the end of the children list.
1958 */
1959 cur->type = XML_ELEMENT_NODE;
1960 cur->parent = parent;
1961 cur->doc = parent->doc;
1962 if (parent->children == NULL) {
1963 parent->children = cur;
1964 parent->last = cur;
1965 } else {
1966 prev = parent->last;
1967 prev->next = cur;
1968 cur->prev = prev;
1969 parent->last = cur;
1970 }
1971
1972 return(cur);
1973}
1974
1975/**
1976 * xmlAddNextSibling:
1977 * @cur: the child node
1978 * @elem: the new node
1979 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001980 * Add a new node @elem as the next sibling of @cur
1981 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00001982 * first unlinked from its existing context.
1983 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001984 * If the new node is ATTRIBUTE, it is added into properties instead of children.
1985 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00001986 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001987 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001988 */
1989xmlNodePtr
1990xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1991 if (cur == NULL) {
1992#ifdef DEBUG_TREE
1993 xmlGenericError(xmlGenericErrorContext,
1994 "xmlAddNextSibling : cur == NULL\n");
1995#endif
1996 return(NULL);
1997 }
1998 if (elem == NULL) {
1999#ifdef DEBUG_TREE
2000 xmlGenericError(xmlGenericErrorContext,
2001 "xmlAddNextSibling : elem == NULL\n");
2002#endif
2003 return(NULL);
2004 }
2005
2006 xmlUnlinkNode(elem);
2007
2008 if (elem->type == XML_TEXT_NODE) {
2009 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002010 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002011 xmlFreeNode(elem);
2012 return(cur);
2013 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002014 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2015 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002016 xmlChar *tmp;
2017
2018 tmp = xmlStrdup(elem->content);
2019 tmp = xmlStrcat(tmp, cur->next->content);
2020 xmlNodeSetContent(cur->next, tmp);
2021 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002022 xmlFreeNode(elem);
2023 return(cur->next);
2024 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002025 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2026 /* check if an attribute with the same name exists */
2027 xmlAttrPtr attr;
2028
2029 if (elem->ns == NULL)
2030 attr = xmlHasProp(cur->parent, elem->name);
2031 else
2032 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2033 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2034 /* different instance, destroy it (attributes must be unique) */
2035 xmlFreeProp(attr);
2036 }
Owen Taylor3473f882001-02-23 17:55:21 +00002037 }
2038
2039 if (elem->doc != cur->doc) {
2040 xmlSetTreeDoc(elem, cur->doc);
2041 }
2042 elem->parent = cur->parent;
2043 elem->prev = cur;
2044 elem->next = cur->next;
2045 cur->next = elem;
2046 if (elem->next != NULL)
2047 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002048 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002049 elem->parent->last = elem;
2050 return(elem);
2051}
2052
2053/**
2054 * xmlAddPrevSibling:
2055 * @cur: the child node
2056 * @elem: the new node
2057 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002058 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002059 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002060 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002061 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002062 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2063 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002064 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002065 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002066 */
2067xmlNodePtr
2068xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2069 if (cur == NULL) {
2070#ifdef DEBUG_TREE
2071 xmlGenericError(xmlGenericErrorContext,
2072 "xmlAddPrevSibling : cur == NULL\n");
2073#endif
2074 return(NULL);
2075 }
2076 if (elem == NULL) {
2077#ifdef DEBUG_TREE
2078 xmlGenericError(xmlGenericErrorContext,
2079 "xmlAddPrevSibling : elem == NULL\n");
2080#endif
2081 return(NULL);
2082 }
2083
2084 xmlUnlinkNode(elem);
2085
2086 if (elem->type == XML_TEXT_NODE) {
2087 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002088 xmlChar *tmp;
2089
2090 tmp = xmlStrdup(elem->content);
2091 tmp = xmlStrcat(tmp, cur->content);
2092 xmlNodeSetContent(cur, tmp);
2093 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002094 xmlFreeNode(elem);
2095 return(cur);
2096 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002097 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2098 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002099 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002100 xmlFreeNode(elem);
2101 return(cur->prev);
2102 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002103 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2104 /* check if an attribute with the same name exists */
2105 xmlAttrPtr attr;
2106
2107 if (elem->ns == NULL)
2108 attr = xmlHasProp(cur->parent, elem->name);
2109 else
2110 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2111 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2112 /* different instance, destroy it (attributes must be unique) */
2113 xmlFreeProp(attr);
2114 }
Owen Taylor3473f882001-02-23 17:55:21 +00002115 }
2116
2117 if (elem->doc != cur->doc) {
2118 xmlSetTreeDoc(elem, cur->doc);
2119 }
2120 elem->parent = cur->parent;
2121 elem->next = cur;
2122 elem->prev = cur->prev;
2123 cur->prev = elem;
2124 if (elem->prev != NULL)
2125 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002126 if (elem->parent != NULL) {
2127 if (elem->type == XML_ATTRIBUTE_NODE) {
2128 if (elem->parent->properties == (xmlAttrPtr) cur) {
2129 elem->parent->properties = (xmlAttrPtr) elem;
2130 }
2131 } else {
2132 if (elem->parent->children == cur) {
2133 elem->parent->children = elem;
2134 }
2135 }
2136 }
Owen Taylor3473f882001-02-23 17:55:21 +00002137 return(elem);
2138}
2139
2140/**
2141 * xmlAddSibling:
2142 * @cur: the child node
2143 * @elem: the new node
2144 *
2145 * Add a new element @elem to the list of siblings of @cur
2146 * merging adjacent TEXT nodes (@elem may be freed)
2147 * If the new element was already inserted in a document it is
2148 * first unlinked from its existing context.
2149 *
2150 * Returns the new element or NULL in case of error.
2151 */
2152xmlNodePtr
2153xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2154 xmlNodePtr parent;
2155
2156 if (cur == NULL) {
2157#ifdef DEBUG_TREE
2158 xmlGenericError(xmlGenericErrorContext,
2159 "xmlAddSibling : cur == NULL\n");
2160#endif
2161 return(NULL);
2162 }
2163
2164 if (elem == NULL) {
2165#ifdef DEBUG_TREE
2166 xmlGenericError(xmlGenericErrorContext,
2167 "xmlAddSibling : elem == NULL\n");
2168#endif
2169 return(NULL);
2170 }
2171
2172 /*
2173 * Constant time is we can rely on the ->parent->last to find
2174 * the last sibling.
2175 */
2176 if ((cur->parent != NULL) &&
2177 (cur->parent->children != NULL) &&
2178 (cur->parent->last != NULL) &&
2179 (cur->parent->last->next == NULL)) {
2180 cur = cur->parent->last;
2181 } else {
2182 while (cur->next != NULL) cur = cur->next;
2183 }
2184
2185 xmlUnlinkNode(elem);
2186
2187 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002188 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002189 xmlFreeNode(elem);
2190 return(cur);
2191 }
2192
2193 if (elem->doc != cur->doc) {
2194 xmlSetTreeDoc(elem, cur->doc);
2195 }
2196 parent = cur->parent;
2197 elem->prev = cur;
2198 elem->next = NULL;
2199 elem->parent = parent;
2200 cur->next = elem;
2201 if (parent != NULL)
2202 parent->last = elem;
2203
2204 return(elem);
2205}
2206
2207/**
2208 * xmlAddChildList:
2209 * @parent: the parent node
2210 * @cur: the first node in the list
2211 *
2212 * Add a list of node at the end of the child list of the parent
2213 * merging adjacent TEXT nodes (@cur may be freed)
2214 *
2215 * Returns the last child or NULL in case of error.
2216 */
2217xmlNodePtr
2218xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2219 xmlNodePtr prev;
2220
2221 if (parent == NULL) {
2222#ifdef DEBUG_TREE
2223 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002224 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002225#endif
2226 return(NULL);
2227 }
2228
2229 if (cur == NULL) {
2230#ifdef DEBUG_TREE
2231 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002232 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002233#endif
2234 return(NULL);
2235 }
2236
2237 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2238 (cur->doc != parent->doc)) {
2239#ifdef DEBUG_TREE
2240 xmlGenericError(xmlGenericErrorContext,
2241 "Elements moved to a different document\n");
2242#endif
2243 }
2244
2245 /*
2246 * add the first element at the end of the children list.
2247 */
2248 if (parent->children == NULL) {
2249 parent->children = cur;
2250 } else {
2251 /*
2252 * If cur and parent->last both are TEXT nodes, then merge them.
2253 */
2254 if ((cur->type == XML_TEXT_NODE) &&
2255 (parent->last->type == XML_TEXT_NODE) &&
2256 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002257 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002258 /*
2259 * if it's the only child, nothing more to be done.
2260 */
2261 if (cur->next == NULL) {
2262 xmlFreeNode(cur);
2263 return(parent->last);
2264 }
2265 prev = cur;
2266 cur = cur->next;
2267 xmlFreeNode(prev);
2268 }
2269 prev = parent->last;
2270 prev->next = cur;
2271 cur->prev = prev;
2272 }
2273 while (cur->next != NULL) {
2274 cur->parent = parent;
2275 if (cur->doc != parent->doc) {
2276 xmlSetTreeDoc(cur, parent->doc);
2277 }
2278 cur = cur->next;
2279 }
2280 cur->parent = parent;
2281 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2282 parent->last = cur;
2283
2284 return(cur);
2285}
2286
2287/**
2288 * xmlAddChild:
2289 * @parent: the parent node
2290 * @cur: the child node
2291 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002292 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002293 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002294 * If the new node was already inserted in a document it is
2295 * first unlinked from its existing context.
2296 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2297 * If there is an attribute with equal name, it is first destroyed.
2298 *
Owen Taylor3473f882001-02-23 17:55:21 +00002299 * Returns the child or NULL in case of error.
2300 */
2301xmlNodePtr
2302xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2303 xmlNodePtr prev;
2304
2305 if (parent == NULL) {
2306#ifdef DEBUG_TREE
2307 xmlGenericError(xmlGenericErrorContext,
2308 "xmlAddChild : parent == NULL\n");
2309#endif
2310 return(NULL);
2311 }
2312
2313 if (cur == NULL) {
2314#ifdef DEBUG_TREE
2315 xmlGenericError(xmlGenericErrorContext,
2316 "xmlAddChild : child == NULL\n");
2317#endif
2318 return(NULL);
2319 }
2320
Owen Taylor3473f882001-02-23 17:55:21 +00002321 /*
2322 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002323 * cur is then freed.
2324 */
2325 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002326 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002327 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002328 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002329 xmlFreeNode(cur);
2330 return(parent);
2331 }
2332 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2333 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002334 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002335 xmlFreeNode(cur);
2336 return(parent->last);
2337 }
2338 }
2339
2340 /*
2341 * add the new element at the end of the children list.
2342 */
2343 cur->parent = parent;
2344 if (cur->doc != parent->doc) {
2345 xmlSetTreeDoc(cur, parent->doc);
2346 }
2347
2348 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002349 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002350 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002351 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002352 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002353 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002354 xmlFreeNode(cur);
2355 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002356 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002357 if (cur->type == XML_ATTRIBUTE_NODE) {
2358 if (parent->properties == NULL) {
2359 parent->properties = (xmlAttrPtr) cur;
2360 } else {
2361 /* check if an attribute with the same name exists */
2362 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002363
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002364 if (cur->ns == NULL)
2365 lastattr = xmlHasProp(parent, cur->name);
2366 else
2367 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2368 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2369 /* different instance, destroy it (attributes must be unique) */
2370 xmlFreeProp(lastattr);
2371 }
2372 /* find the end */
2373 lastattr = parent->properties;
2374 while (lastattr->next != NULL) {
2375 lastattr = lastattr->next;
2376 }
2377 lastattr->next = (xmlAttrPtr) cur;
2378 ((xmlAttrPtr) cur)->prev = lastattr;
2379 }
2380 } else {
2381 if (parent->children == NULL) {
2382 parent->children = cur;
2383 parent->last = cur;
2384 } else {
2385 prev = parent->last;
2386 prev->next = cur;
2387 cur->prev = prev;
2388 parent->last = cur;
2389 }
2390 }
Owen Taylor3473f882001-02-23 17:55:21 +00002391 return(cur);
2392}
2393
2394/**
2395 * xmlGetLastChild:
2396 * @parent: the parent node
2397 *
2398 * Search the last child of a node.
2399 * Returns the last child or NULL if none.
2400 */
2401xmlNodePtr
2402xmlGetLastChild(xmlNodePtr parent) {
2403 if (parent == NULL) {
2404#ifdef DEBUG_TREE
2405 xmlGenericError(xmlGenericErrorContext,
2406 "xmlGetLastChild : parent == NULL\n");
2407#endif
2408 return(NULL);
2409 }
2410 return(parent->last);
2411}
2412
2413/**
2414 * xmlFreeNodeList:
2415 * @cur: the first node in the list
2416 *
2417 * Free a node and all its siblings, this is a recursive behaviour, all
2418 * the children are freed too.
2419 */
2420void
2421xmlFreeNodeList(xmlNodePtr cur) {
2422 xmlNodePtr next;
2423 if (cur == NULL) {
2424#ifdef DEBUG_TREE
2425 xmlGenericError(xmlGenericErrorContext,
2426 "xmlFreeNodeList : node == NULL\n");
2427#endif
2428 return;
2429 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002430 if (cur->type == XML_NAMESPACE_DECL) {
2431 xmlFreeNsList((xmlNsPtr) cur);
2432 return;
2433 }
Owen Taylor3473f882001-02-23 17:55:21 +00002434 while (cur != NULL) {
2435 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002436 /* unroll to speed up freeing the document */
2437 if (cur->type != XML_DTD_NODE) {
2438 if ((cur->children != NULL) &&
2439 (cur->type != XML_ENTITY_REF_NODE))
2440 xmlFreeNodeList(cur->children);
2441 if (cur->properties != NULL)
2442 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002443 if ((cur->type != XML_ELEMENT_NODE) &&
2444 (cur->type != XML_XINCLUDE_START) &&
2445 (cur->type != XML_XINCLUDE_END) &&
2446 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002447 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002448 }
2449 if (((cur->type == XML_ELEMENT_NODE) ||
2450 (cur->type == XML_XINCLUDE_START) ||
2451 (cur->type == XML_XINCLUDE_END)) &&
2452 (cur->nsDef != NULL))
2453 xmlFreeNsList(cur->nsDef);
2454
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002455 /*
2456 * When a node is a text node or a comment, it uses a global static
2457 * variable for the name of the node.
2458 *
2459 * The xmlStrEqual comparisons need to be done when (happened with
2460 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002461 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002462 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002463 * the string addresses compare are not sufficient.
2464 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002465 if ((cur->name != NULL) &&
2466 (cur->name != xmlStringText) &&
2467 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002468 (cur->name != xmlStringComment)) {
2469 if (cur->type == XML_TEXT_NODE) {
2470 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2471 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2472 xmlFree((char *) cur->name);
2473 } else if (cur->type == XML_COMMENT_NODE) {
2474 if (!xmlStrEqual(cur->name, xmlStringComment))
2475 xmlFree((char *) cur->name);
2476 } else
2477 xmlFree((char *) cur->name);
2478 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002479 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002480 xmlFree(cur);
2481 }
Owen Taylor3473f882001-02-23 17:55:21 +00002482 cur = next;
2483 }
2484}
2485
2486/**
2487 * xmlFreeNode:
2488 * @cur: the node
2489 *
2490 * Free a node, this is a recursive behaviour, all the children are freed too.
2491 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2492 */
2493void
2494xmlFreeNode(xmlNodePtr cur) {
2495 if (cur == NULL) {
2496#ifdef DEBUG_TREE
2497 xmlGenericError(xmlGenericErrorContext,
2498 "xmlFreeNode : node == NULL\n");
2499#endif
2500 return;
2501 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002502 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002503 if (cur->type == XML_DTD_NODE) {
2504 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002505 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002506 }
2507 if (cur->type == XML_NAMESPACE_DECL) {
2508 xmlFreeNs((xmlNsPtr) cur);
2509 return;
2510 }
Owen Taylor3473f882001-02-23 17:55:21 +00002511 if ((cur->children != NULL) &&
2512 (cur->type != XML_ENTITY_REF_NODE))
2513 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002514 if (cur->properties != NULL)
2515 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002516 if ((cur->type != XML_ELEMENT_NODE) &&
2517 (cur->content != NULL) &&
2518 (cur->type != XML_ENTITY_REF_NODE) &&
2519 (cur->type != XML_XINCLUDE_END) &&
2520 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002521 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002522 }
2523
Daniel Veillardacd370f2001-06-09 17:17:51 +00002524 /*
2525 * When a node is a text node or a comment, it uses a global static
2526 * variable for the name of the node.
2527 *
2528 * The xmlStrEqual comparisons need to be done when (happened with
2529 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002530 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002531 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002532 * are not sufficient.
2533 */
Owen Taylor3473f882001-02-23 17:55:21 +00002534 if ((cur->name != NULL) &&
2535 (cur->name != xmlStringText) &&
2536 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002537 (cur->name != xmlStringComment)) {
2538 if (cur->type == XML_TEXT_NODE) {
2539 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2540 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2541 xmlFree((char *) cur->name);
2542 } else if (cur->type == XML_COMMENT_NODE) {
2543 if (!xmlStrEqual(cur->name, xmlStringComment))
2544 xmlFree((char *) cur->name);
2545 } else
2546 xmlFree((char *) cur->name);
2547 }
2548
Owen Taylor3473f882001-02-23 17:55:21 +00002549 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002550 xmlFree(cur);
2551}
2552
2553/**
2554 * xmlUnlinkNode:
2555 * @cur: the node
2556 *
2557 * Unlink a node from it's current context, the node is not freed
2558 */
2559void
2560xmlUnlinkNode(xmlNodePtr cur) {
2561 if (cur == NULL) {
2562#ifdef DEBUG_TREE
2563 xmlGenericError(xmlGenericErrorContext,
2564 "xmlUnlinkNode : node == NULL\n");
2565#endif
2566 return;
2567 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002568 if (cur->type == XML_DTD_NODE) {
2569 xmlDocPtr doc;
2570 doc = cur->doc;
2571 if (doc->intSubset == (xmlDtdPtr) cur)
2572 doc->intSubset = NULL;
2573 if (doc->extSubset == (xmlDtdPtr) cur)
2574 doc->extSubset = NULL;
2575 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002576 if (cur->parent != NULL) {
2577 xmlNodePtr parent;
2578 parent = cur->parent;
2579 if (cur->type == XML_ATTRIBUTE_NODE) {
2580 if (parent->properties == (xmlAttrPtr) cur)
2581 parent->properties = ((xmlAttrPtr) cur)->next;
2582 } else {
2583 if (parent->children == cur)
2584 parent->children = cur->next;
2585 if (parent->last == cur)
2586 parent->last = cur->prev;
2587 }
2588 cur->parent = NULL;
2589 }
Owen Taylor3473f882001-02-23 17:55:21 +00002590 if (cur->next != NULL)
2591 cur->next->prev = cur->prev;
2592 if (cur->prev != NULL)
2593 cur->prev->next = cur->next;
2594 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002595}
2596
2597/**
2598 * xmlReplaceNode:
2599 * @old: the old node
2600 * @cur: the node
2601 *
2602 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002603 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002604 * first unlinked from its existing context.
2605 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002606 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002607 */
2608xmlNodePtr
2609xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2610 if (old == NULL) {
2611#ifdef DEBUG_TREE
2612 xmlGenericError(xmlGenericErrorContext,
2613 "xmlReplaceNode : old == NULL\n");
2614#endif
2615 return(NULL);
2616 }
2617 if (cur == NULL) {
2618 xmlUnlinkNode(old);
2619 return(old);
2620 }
2621 if (cur == old) {
2622 return(old);
2623 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002624 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2625#ifdef DEBUG_TREE
2626 xmlGenericError(xmlGenericErrorContext,
2627 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2628#endif
2629 return(old);
2630 }
2631 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2632#ifdef DEBUG_TREE
2633 xmlGenericError(xmlGenericErrorContext,
2634 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2635#endif
2636 return(old);
2637 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002638 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2639#ifdef DEBUG_TREE
2640 xmlGenericError(xmlGenericErrorContext,
2641 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2642#endif
2643 return(old);
2644 }
2645 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2646#ifdef DEBUG_TREE
2647 xmlGenericError(xmlGenericErrorContext,
2648 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2649#endif
2650 return(old);
2651 }
Owen Taylor3473f882001-02-23 17:55:21 +00002652 xmlUnlinkNode(cur);
2653 cur->doc = old->doc;
2654 cur->parent = old->parent;
2655 cur->next = old->next;
2656 if (cur->next != NULL)
2657 cur->next->prev = cur;
2658 cur->prev = old->prev;
2659 if (cur->prev != NULL)
2660 cur->prev->next = cur;
2661 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002662 if (cur->type == XML_ATTRIBUTE_NODE) {
2663 if (cur->parent->properties == (xmlAttrPtr)old)
2664 cur->parent->properties = ((xmlAttrPtr) cur);
2665 } else {
2666 if (cur->parent->children == old)
2667 cur->parent->children = cur;
2668 if (cur->parent->last == old)
2669 cur->parent->last = cur;
2670 }
Owen Taylor3473f882001-02-23 17:55:21 +00002671 }
2672 old->next = old->prev = NULL;
2673 old->parent = NULL;
2674 return(old);
2675}
2676
2677/************************************************************************
2678 * *
2679 * Copy operations *
2680 * *
2681 ************************************************************************/
2682
2683/**
2684 * xmlCopyNamespace:
2685 * @cur: the namespace
2686 *
2687 * Do a copy of the namespace.
2688 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002689 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002690 */
2691xmlNsPtr
2692xmlCopyNamespace(xmlNsPtr cur) {
2693 xmlNsPtr ret;
2694
2695 if (cur == NULL) return(NULL);
2696 switch (cur->type) {
2697 case XML_LOCAL_NAMESPACE:
2698 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2699 break;
2700 default:
2701#ifdef DEBUG_TREE
2702 xmlGenericError(xmlGenericErrorContext,
2703 "xmlCopyNamespace: invalid type %d\n", cur->type);
2704#endif
2705 return(NULL);
2706 }
2707 return(ret);
2708}
2709
2710/**
2711 * xmlCopyNamespaceList:
2712 * @cur: the first namespace
2713 *
2714 * Do a copy of an namespace list.
2715 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002716 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002717 */
2718xmlNsPtr
2719xmlCopyNamespaceList(xmlNsPtr cur) {
2720 xmlNsPtr ret = NULL;
2721 xmlNsPtr p = NULL,q;
2722
2723 while (cur != NULL) {
2724 q = xmlCopyNamespace(cur);
2725 if (p == NULL) {
2726 ret = p = q;
2727 } else {
2728 p->next = q;
2729 p = q;
2730 }
2731 cur = cur->next;
2732 }
2733 return(ret);
2734}
2735
2736static xmlNodePtr
2737xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2738/**
2739 * xmlCopyProp:
2740 * @target: the element where the attribute will be grafted
2741 * @cur: the attribute
2742 *
2743 * Do a copy of the attribute.
2744 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002745 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002746 */
2747xmlAttrPtr
2748xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2749 xmlAttrPtr ret;
2750
2751 if (cur == NULL) return(NULL);
2752 if (target != NULL)
2753 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2754 else if (cur->parent != NULL)
2755 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2756 else if (cur->children != NULL)
2757 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2758 else
2759 ret = xmlNewDocProp(NULL, cur->name, NULL);
2760 if (ret == NULL) return(NULL);
2761 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002762
Owen Taylor3473f882001-02-23 17:55:21 +00002763 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002764 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002765/*
2766 * if (target->doc)
2767 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2768 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2769 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2770 * else
2771 * ns = NULL;
2772 * ret->ns = ns;
2773 */
2774 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2775 if (ns == NULL) {
2776 /*
2777 * Humm, we are copying an element whose namespace is defined
2778 * out of the new tree scope. Search it in the original tree
2779 * and add it at the top of the new tree
2780 */
2781 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2782 if (ns != NULL) {
2783 xmlNodePtr root = target;
2784 xmlNodePtr pred = NULL;
2785
2786 while (root->parent != NULL) {
2787 pred = root;
2788 root = root->parent;
2789 }
2790 if (root == (xmlNodePtr) target->doc) {
2791 /* correct possibly cycling above the document elt */
2792 root = pred;
2793 }
2794 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2795 }
2796 } else {
2797 /*
2798 * we have to find something appropriate here since
2799 * we cant be sure, that the namespce we found is identified
2800 * by the prefix
2801 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002802 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002803 /* this is the nice case */
2804 ret->ns = ns;
2805 } else {
2806 /*
2807 * we are in trouble: we need a new reconcilied namespace.
2808 * This is expensive
2809 */
2810 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2811 }
2812 }
2813
Owen Taylor3473f882001-02-23 17:55:21 +00002814 } else
2815 ret->ns = NULL;
2816
2817 if (cur->children != NULL) {
2818 xmlNodePtr tmp;
2819
2820 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2821 ret->last = NULL;
2822 tmp = ret->children;
2823 while (tmp != NULL) {
2824 /* tmp->parent = (xmlNodePtr)ret; */
2825 if (tmp->next == NULL)
2826 ret->last = tmp;
2827 tmp = tmp->next;
2828 }
2829 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002830 /*
2831 * Try to handle IDs
2832 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002833 if ((target!= NULL) && (cur!= NULL) &&
2834 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002835 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2836 if (xmlIsID(cur->doc, cur->parent, cur)) {
2837 xmlChar *id;
2838
2839 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2840 if (id != NULL) {
2841 xmlAddID(NULL, target->doc, id, ret);
2842 xmlFree(id);
2843 }
2844 }
2845 }
Owen Taylor3473f882001-02-23 17:55:21 +00002846 return(ret);
2847}
2848
2849/**
2850 * xmlCopyPropList:
2851 * @target: the element where the attributes will be grafted
2852 * @cur: the first attribute
2853 *
2854 * Do a copy of an attribute list.
2855 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002856 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002857 */
2858xmlAttrPtr
2859xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2860 xmlAttrPtr ret = NULL;
2861 xmlAttrPtr p = NULL,q;
2862
2863 while (cur != NULL) {
2864 q = xmlCopyProp(target, cur);
2865 if (p == NULL) {
2866 ret = p = q;
2867 } else {
2868 p->next = q;
2869 q->prev = p;
2870 p = q;
2871 }
2872 cur = cur->next;
2873 }
2874 return(ret);
2875}
2876
2877/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002878 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002879 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002880 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002881 * tricky reason: namespaces. Doing a direct copy of a node
2882 * say RPM:Copyright without changing the namespace pointer to
2883 * something else can produce stale links. One way to do it is
2884 * to keep a reference counter but this doesn't work as soon
2885 * as one move the element or the subtree out of the scope of
2886 * the existing namespace. The actual solution seems to add
2887 * a copy of the namespace at the top of the copied tree if
2888 * not available in the subtree.
2889 * Hence two functions, the public front-end call the inner ones
2890 */
2891
2892static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002893xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002894 int recursive) {
2895 xmlNodePtr ret;
2896
2897 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002898 switch (node->type) {
2899 case XML_TEXT_NODE:
2900 case XML_CDATA_SECTION_NODE:
2901 case XML_ELEMENT_NODE:
2902 case XML_ENTITY_REF_NODE:
2903 case XML_ENTITY_NODE:
2904 case XML_PI_NODE:
2905 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002906 case XML_XINCLUDE_START:
2907 case XML_XINCLUDE_END:
2908 break;
2909 case XML_ATTRIBUTE_NODE:
2910 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2911 case XML_NAMESPACE_DECL:
2912 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2913
Daniel Veillard39196eb2001-06-19 18:09:42 +00002914 case XML_DOCUMENT_NODE:
2915 case XML_HTML_DOCUMENT_NODE:
2916#ifdef LIBXML_DOCB_ENABLED
2917 case XML_DOCB_DOCUMENT_NODE:
2918#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002919 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002920 case XML_DOCUMENT_TYPE_NODE:
2921 case XML_DOCUMENT_FRAG_NODE:
2922 case XML_NOTATION_NODE:
2923 case XML_DTD_NODE:
2924 case XML_ELEMENT_DECL:
2925 case XML_ATTRIBUTE_DECL:
2926 case XML_ENTITY_DECL:
2927 return(NULL);
2928 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002929
Owen Taylor3473f882001-02-23 17:55:21 +00002930 /*
2931 * Allocate a new node and fill the fields.
2932 */
2933 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2934 if (ret == NULL) {
2935 xmlGenericError(xmlGenericErrorContext,
2936 "xmlStaticCopyNode : malloc failed\n");
2937 return(NULL);
2938 }
2939 memset(ret, 0, sizeof(xmlNode));
2940 ret->type = node->type;
2941
2942 ret->doc = doc;
2943 ret->parent = parent;
2944 if (node->name == xmlStringText)
2945 ret->name = xmlStringText;
2946 else if (node->name == xmlStringTextNoenc)
2947 ret->name = xmlStringTextNoenc;
2948 else if (node->name == xmlStringComment)
2949 ret->name = xmlStringComment;
2950 else if (node->name != NULL)
2951 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002952 if ((node->type != XML_ELEMENT_NODE) &&
2953 (node->content != NULL) &&
2954 (node->type != XML_ENTITY_REF_NODE) &&
2955 (node->type != XML_XINCLUDE_END) &&
2956 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002957 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00002958 }else{
2959 if (node->type == XML_ELEMENT_NODE)
2960 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002961 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002962 if (parent != NULL) {
2963 xmlNodePtr tmp;
2964
2965 tmp = xmlAddChild(parent, ret);
2966 /* node could have coalesced */
2967 if (tmp != ret)
2968 return(tmp);
2969 }
Owen Taylor3473f882001-02-23 17:55:21 +00002970
2971 if (!recursive) return(ret);
2972 if (node->nsDef != NULL)
2973 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2974
2975 if (node->ns != NULL) {
2976 xmlNsPtr ns;
2977
2978 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2979 if (ns == NULL) {
2980 /*
2981 * Humm, we are copying an element whose namespace is defined
2982 * out of the new tree scope. Search it in the original tree
2983 * and add it at the top of the new tree
2984 */
2985 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2986 if (ns != NULL) {
2987 xmlNodePtr root = ret;
2988
2989 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002990 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002991 }
2992 } else {
2993 /*
2994 * reference the existing namespace definition in our own tree.
2995 */
2996 ret->ns = ns;
2997 }
2998 }
2999 if (node->properties != NULL)
3000 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003001 if (node->type == XML_ENTITY_REF_NODE) {
3002 if ((doc == NULL) || (node->doc != doc)) {
3003 /*
3004 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003005 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003006 * we cannot keep the reference. Try to find it in the
3007 * target document.
3008 */
3009 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3010 } else {
3011 ret->children = node->children;
3012 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003013 ret->last = ret->children;
3014 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003015 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003016 UPDATE_LAST_CHILD_AND_PARENT(ret)
3017 }
Owen Taylor3473f882001-02-23 17:55:21 +00003018 return(ret);
3019}
3020
3021static xmlNodePtr
3022xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3023 xmlNodePtr ret = NULL;
3024 xmlNodePtr p = NULL,q;
3025
3026 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003027 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003028 if (doc == NULL) {
3029 node = node->next;
3030 continue;
3031 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003032 if (doc->intSubset == NULL) {
3033 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3034 q->doc = doc;
3035 q->parent = parent;
3036 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003037 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003038 } else {
3039 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003040 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003041 }
3042 } else
3043 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003044 if (ret == NULL) {
3045 q->prev = NULL;
3046 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003047 } else if (p != q) {
3048 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003049 p->next = q;
3050 q->prev = p;
3051 p = q;
3052 }
3053 node = node->next;
3054 }
3055 return(ret);
3056}
3057
3058/**
3059 * xmlCopyNode:
3060 * @node: the node
3061 * @recursive: if 1 do a recursive copy.
3062 *
3063 * Do a copy of the node.
3064 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003065 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003066 */
3067xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003068xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003069 xmlNodePtr ret;
3070
3071 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3072 return(ret);
3073}
3074
3075/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003076 * xmlDocCopyNode:
3077 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003078 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003079 * @recursive: if 1 do a recursive copy.
3080 *
3081 * Do a copy of the node to a given document.
3082 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003083 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003084 */
3085xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003086xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003087 xmlNodePtr ret;
3088
3089 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3090 return(ret);
3091}
3092
3093/**
Owen Taylor3473f882001-02-23 17:55:21 +00003094 * xmlCopyNodeList:
3095 * @node: the first node in the list.
3096 *
3097 * Do a recursive copy of the node list.
3098 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003099 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003100 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003101xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003102 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3103 return(ret);
3104}
3105
3106/**
Owen Taylor3473f882001-02-23 17:55:21 +00003107 * xmlCopyDtd:
3108 * @dtd: the dtd
3109 *
3110 * Do a copy of the dtd.
3111 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003112 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003113 */
3114xmlDtdPtr
3115xmlCopyDtd(xmlDtdPtr dtd) {
3116 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003117 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003118
3119 if (dtd == NULL) return(NULL);
3120 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3121 if (ret == NULL) return(NULL);
3122 if (dtd->entities != NULL)
3123 ret->entities = (void *) xmlCopyEntitiesTable(
3124 (xmlEntitiesTablePtr) dtd->entities);
3125 if (dtd->notations != NULL)
3126 ret->notations = (void *) xmlCopyNotationTable(
3127 (xmlNotationTablePtr) dtd->notations);
3128 if (dtd->elements != NULL)
3129 ret->elements = (void *) xmlCopyElementTable(
3130 (xmlElementTablePtr) dtd->elements);
3131 if (dtd->attributes != NULL)
3132 ret->attributes = (void *) xmlCopyAttributeTable(
3133 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003134 if (dtd->pentities != NULL)
3135 ret->pentities = (void *) xmlCopyEntitiesTable(
3136 (xmlEntitiesTablePtr) dtd->pentities);
3137
3138 cur = dtd->children;
3139 while (cur != NULL) {
3140 q = NULL;
3141
3142 if (cur->type == XML_ENTITY_DECL) {
3143 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3144 switch (tmp->etype) {
3145 case XML_INTERNAL_GENERAL_ENTITY:
3146 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3147 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3148 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3149 break;
3150 case XML_INTERNAL_PARAMETER_ENTITY:
3151 case XML_EXTERNAL_PARAMETER_ENTITY:
3152 q = (xmlNodePtr)
3153 xmlGetParameterEntityFromDtd(ret, tmp->name);
3154 break;
3155 case XML_INTERNAL_PREDEFINED_ENTITY:
3156 break;
3157 }
3158 } else if (cur->type == XML_ELEMENT_DECL) {
3159 xmlElementPtr tmp = (xmlElementPtr) cur;
3160 q = (xmlNodePtr)
3161 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3162 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3163 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3164 q = (xmlNodePtr)
3165 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3166 } else if (cur->type == XML_COMMENT_NODE) {
3167 q = xmlCopyNode(cur, 0);
3168 }
3169
3170 if (q == NULL) {
3171 cur = cur->next;
3172 continue;
3173 }
3174
3175 if (p == NULL)
3176 ret->children = q;
3177 else
3178 p->next = q;
3179
3180 q->prev = p;
3181 q->parent = (xmlNodePtr) ret;
3182 q->next = NULL;
3183 ret->last = q;
3184 p = q;
3185 cur = cur->next;
3186 }
3187
Owen Taylor3473f882001-02-23 17:55:21 +00003188 return(ret);
3189}
3190
3191/**
3192 * xmlCopyDoc:
3193 * @doc: the document
3194 * @recursive: if 1 do a recursive copy.
3195 *
3196 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003197 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003198 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003199 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003200 */
3201xmlDocPtr
3202xmlCopyDoc(xmlDocPtr doc, int recursive) {
3203 xmlDocPtr ret;
3204
3205 if (doc == NULL) return(NULL);
3206 ret = xmlNewDoc(doc->version);
3207 if (ret == NULL) return(NULL);
3208 if (doc->name != NULL)
3209 ret->name = xmlMemStrdup(doc->name);
3210 if (doc->encoding != NULL)
3211 ret->encoding = xmlStrdup(doc->encoding);
3212 ret->charset = doc->charset;
3213 ret->compression = doc->compression;
3214 ret->standalone = doc->standalone;
3215 if (!recursive) return(ret);
3216
Daniel Veillardb33c2012001-04-25 12:59:04 +00003217 ret->last = NULL;
3218 ret->children = NULL;
3219 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003220 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003221 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003222 ret->intSubset->parent = ret;
3223 }
Owen Taylor3473f882001-02-23 17:55:21 +00003224 if (doc->oldNs != NULL)
3225 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3226 if (doc->children != NULL) {
3227 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003228
3229 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3230 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003231 ret->last = NULL;
3232 tmp = ret->children;
3233 while (tmp != NULL) {
3234 if (tmp->next == NULL)
3235 ret->last = tmp;
3236 tmp = tmp->next;
3237 }
3238 }
3239 return(ret);
3240}
3241
3242/************************************************************************
3243 * *
3244 * Content access functions *
3245 * *
3246 ************************************************************************/
3247
3248/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003249 * xmlGetLineNo:
3250 * @node : valid node
3251 *
3252 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003253 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003254 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003255 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003256 */
3257long
3258xmlGetLineNo(xmlNodePtr node)
3259{
3260 long result = -1;
3261
3262 if (!node)
3263 return result;
3264 if (node->type == XML_ELEMENT_NODE)
3265 result = (long) node->content;
3266 else if ((node->prev != NULL) &&
3267 ((node->prev->type == XML_ELEMENT_NODE) ||
3268 (node->prev->type == XML_TEXT_NODE)))
3269 result = xmlGetLineNo(node->prev);
3270 else if ((node->parent != NULL) &&
3271 ((node->parent->type == XML_ELEMENT_NODE) ||
3272 (node->parent->type == XML_TEXT_NODE)))
3273 result = xmlGetLineNo(node->parent);
3274
3275 return result;
3276}
3277
3278/**
3279 * xmlGetNodePath:
3280 * @node: a node
3281 *
3282 * Build a structure based Path for the given node
3283 *
3284 * Returns the new path or NULL in case of error. The caller must free
3285 * the returned string
3286 */
3287xmlChar *
3288xmlGetNodePath(xmlNodePtr node)
3289{
3290 xmlNodePtr cur, tmp, next;
3291 xmlChar *buffer = NULL, *temp;
3292 size_t buf_len;
3293 xmlChar *buf;
3294 char sep;
3295 const char *name;
3296 char nametemp[100];
3297 int occur = 0;
3298
3299 if (node == NULL)
3300 return (NULL);
3301
3302 buf_len = 500;
3303 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3304 if (buffer == NULL)
3305 return (NULL);
3306 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3307 if (buf == NULL) {
3308 xmlFree(buffer);
3309 return (NULL);
3310 }
3311
3312 buffer[0] = 0;
3313 cur = node;
3314 do {
3315 name = "";
3316 sep = '?';
3317 occur = 0;
3318 if ((cur->type == XML_DOCUMENT_NODE) ||
3319 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3320 if (buffer[0] == '/')
3321 break;
3322 sep = '/';
3323 next = NULL;
3324 } else if (cur->type == XML_ELEMENT_NODE) {
3325 sep = '/';
3326 name = (const char *) cur->name;
3327 if (cur->ns) {
3328 snprintf(nametemp, sizeof(nametemp) - 1,
3329 "%s:%s", cur->ns->prefix, cur->name);
3330 nametemp[sizeof(nametemp) - 1] = 0;
3331 name = nametemp;
3332 }
3333 next = cur->parent;
3334
3335 /*
3336 * Thumbler index computation
3337 */
3338 tmp = cur->prev;
3339 while (tmp != NULL) {
3340 if (xmlStrEqual(cur->name, tmp->name))
3341 occur++;
3342 tmp = tmp->prev;
3343 }
3344 if (occur == 0) {
3345 tmp = cur->next;
3346 while (tmp != NULL) {
3347 if (xmlStrEqual(cur->name, tmp->name))
3348 occur++;
3349 tmp = tmp->next;
3350 }
3351 if (occur != 0)
3352 occur = 1;
3353 } else
3354 occur++;
3355 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3356 sep = '@';
3357 name = (const char *) (((xmlAttrPtr) cur)->name);
3358 next = ((xmlAttrPtr) cur)->parent;
3359 } else {
3360 next = cur->parent;
3361 }
3362
3363 /*
3364 * Make sure there is enough room
3365 */
3366 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3367 buf_len =
3368 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3369 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3370 if (temp == NULL) {
3371 xmlFree(buf);
3372 xmlFree(buffer);
3373 return (NULL);
3374 }
3375 buffer = temp;
3376 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3377 if (temp == NULL) {
3378 xmlFree(buf);
3379 xmlFree(buffer);
3380 return (NULL);
3381 }
3382 buf = temp;
3383 }
3384 if (occur == 0)
3385 snprintf((char *) buf, buf_len, "%c%s%s",
3386 sep, name, (char *) buffer);
3387 else
3388 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3389 sep, name, occur, (char *) buffer);
3390 snprintf((char *) buffer, buf_len, "%s", buf);
3391 cur = next;
3392 } while (cur != NULL);
3393 xmlFree(buf);
3394 return (buffer);
3395}
3396
3397/**
Owen Taylor3473f882001-02-23 17:55:21 +00003398 * xmlDocGetRootElement:
3399 * @doc: the document
3400 *
3401 * Get the root element of the document (doc->children is a list
3402 * containing possibly comments, PIs, etc ...).
3403 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003404 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003405 */
3406xmlNodePtr
3407xmlDocGetRootElement(xmlDocPtr doc) {
3408 xmlNodePtr ret;
3409
3410 if (doc == NULL) return(NULL);
3411 ret = doc->children;
3412 while (ret != NULL) {
3413 if (ret->type == XML_ELEMENT_NODE)
3414 return(ret);
3415 ret = ret->next;
3416 }
3417 return(ret);
3418}
3419
3420/**
3421 * xmlDocSetRootElement:
3422 * @doc: the document
3423 * @root: the new document root element
3424 *
3425 * Set the root element of the document (doc->children is a list
3426 * containing possibly comments, PIs, etc ...).
3427 *
3428 * Returns the old root element if any was found
3429 */
3430xmlNodePtr
3431xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3432 xmlNodePtr old = NULL;
3433
3434 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003435 if (root == NULL)
3436 return(NULL);
3437 xmlUnlinkNode(root);
3438 root->doc = doc;
3439 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003440 old = doc->children;
3441 while (old != NULL) {
3442 if (old->type == XML_ELEMENT_NODE)
3443 break;
3444 old = old->next;
3445 }
3446 if (old == NULL) {
3447 if (doc->children == NULL) {
3448 doc->children = root;
3449 doc->last = root;
3450 } else {
3451 xmlAddSibling(doc->children, root);
3452 }
3453 } else {
3454 xmlReplaceNode(old, root);
3455 }
3456 return(old);
3457}
3458
3459/**
3460 * xmlNodeSetLang:
3461 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003462 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003463 *
3464 * Set the language of a node, i.e. the values of the xml:lang
3465 * attribute.
3466 */
3467void
3468xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003469 xmlNsPtr ns;
3470
Owen Taylor3473f882001-02-23 17:55:21 +00003471 if (cur == NULL) return;
3472 switch(cur->type) {
3473 case XML_TEXT_NODE:
3474 case XML_CDATA_SECTION_NODE:
3475 case XML_COMMENT_NODE:
3476 case XML_DOCUMENT_NODE:
3477 case XML_DOCUMENT_TYPE_NODE:
3478 case XML_DOCUMENT_FRAG_NODE:
3479 case XML_NOTATION_NODE:
3480 case XML_HTML_DOCUMENT_NODE:
3481 case XML_DTD_NODE:
3482 case XML_ELEMENT_DECL:
3483 case XML_ATTRIBUTE_DECL:
3484 case XML_ENTITY_DECL:
3485 case XML_PI_NODE:
3486 case XML_ENTITY_REF_NODE:
3487 case XML_ENTITY_NODE:
3488 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003489#ifdef LIBXML_DOCB_ENABLED
3490 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003491#endif
3492 case XML_XINCLUDE_START:
3493 case XML_XINCLUDE_END:
3494 return;
3495 case XML_ELEMENT_NODE:
3496 case XML_ATTRIBUTE_NODE:
3497 break;
3498 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003499 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3500 if (ns == NULL)
3501 return;
3502 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003503}
3504
3505/**
3506 * xmlNodeGetLang:
3507 * @cur: the node being checked
3508 *
3509 * Searches the language of a node, i.e. the values of the xml:lang
3510 * attribute or the one carried by the nearest ancestor.
3511 *
3512 * Returns a pointer to the lang value, or NULL if not found
3513 * It's up to the caller to free the memory.
3514 */
3515xmlChar *
3516xmlNodeGetLang(xmlNodePtr cur) {
3517 xmlChar *lang;
3518
3519 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003520 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003521 if (lang != NULL)
3522 return(lang);
3523 cur = cur->parent;
3524 }
3525 return(NULL);
3526}
3527
3528
3529/**
3530 * xmlNodeSetSpacePreserve:
3531 * @cur: the node being changed
3532 * @val: the xml:space value ("0": default, 1: "preserve")
3533 *
3534 * Set (or reset) the space preserving behaviour of a node, i.e. the
3535 * value of the xml:space attribute.
3536 */
3537void
3538xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003539 xmlNsPtr ns;
3540
Owen Taylor3473f882001-02-23 17:55:21 +00003541 if (cur == NULL) return;
3542 switch(cur->type) {
3543 case XML_TEXT_NODE:
3544 case XML_CDATA_SECTION_NODE:
3545 case XML_COMMENT_NODE:
3546 case XML_DOCUMENT_NODE:
3547 case XML_DOCUMENT_TYPE_NODE:
3548 case XML_DOCUMENT_FRAG_NODE:
3549 case XML_NOTATION_NODE:
3550 case XML_HTML_DOCUMENT_NODE:
3551 case XML_DTD_NODE:
3552 case XML_ELEMENT_DECL:
3553 case XML_ATTRIBUTE_DECL:
3554 case XML_ENTITY_DECL:
3555 case XML_PI_NODE:
3556 case XML_ENTITY_REF_NODE:
3557 case XML_ENTITY_NODE:
3558 case XML_NAMESPACE_DECL:
3559 case XML_XINCLUDE_START:
3560 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003561#ifdef LIBXML_DOCB_ENABLED
3562 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003563#endif
3564 return;
3565 case XML_ELEMENT_NODE:
3566 case XML_ATTRIBUTE_NODE:
3567 break;
3568 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003569 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3570 if (ns == NULL)
3571 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003572 switch (val) {
3573 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003574 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003575 break;
3576 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003577 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003578 break;
3579 }
3580}
3581
3582/**
3583 * xmlNodeGetSpacePreserve:
3584 * @cur: the node being checked
3585 *
3586 * Searches the space preserving behaviour of a node, i.e. the values
3587 * of the xml:space attribute or the one carried by the nearest
3588 * ancestor.
3589 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003590 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003591 */
3592int
3593xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3594 xmlChar *space;
3595
3596 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003597 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003598 if (space != NULL) {
3599 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3600 xmlFree(space);
3601 return(1);
3602 }
3603 if (xmlStrEqual(space, BAD_CAST "default")) {
3604 xmlFree(space);
3605 return(0);
3606 }
3607 xmlFree(space);
3608 }
3609 cur = cur->parent;
3610 }
3611 return(-1);
3612}
3613
3614/**
3615 * xmlNodeSetName:
3616 * @cur: the node being changed
3617 * @name: the new tag name
3618 *
3619 * Set (or reset) the name of a node.
3620 */
3621void
3622xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3623 if (cur == NULL) return;
3624 if (name == NULL) return;
3625 switch(cur->type) {
3626 case XML_TEXT_NODE:
3627 case XML_CDATA_SECTION_NODE:
3628 case XML_COMMENT_NODE:
3629 case XML_DOCUMENT_TYPE_NODE:
3630 case XML_DOCUMENT_FRAG_NODE:
3631 case XML_NOTATION_NODE:
3632 case XML_HTML_DOCUMENT_NODE:
3633 case XML_NAMESPACE_DECL:
3634 case XML_XINCLUDE_START:
3635 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003636#ifdef LIBXML_DOCB_ENABLED
3637 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003638#endif
3639 return;
3640 case XML_ELEMENT_NODE:
3641 case XML_ATTRIBUTE_NODE:
3642 case XML_PI_NODE:
3643 case XML_ENTITY_REF_NODE:
3644 case XML_ENTITY_NODE:
3645 case XML_DTD_NODE:
3646 case XML_DOCUMENT_NODE:
3647 case XML_ELEMENT_DECL:
3648 case XML_ATTRIBUTE_DECL:
3649 case XML_ENTITY_DECL:
3650 break;
3651 }
3652 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3653 cur->name = xmlStrdup(name);
3654}
3655
3656/**
3657 * xmlNodeSetBase:
3658 * @cur: the node being changed
3659 * @uri: the new base URI
3660 *
3661 * Set (or reset) the base URI of a node, i.e. the value of the
3662 * xml:base attribute.
3663 */
3664void
3665xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003666 xmlNsPtr ns;
3667
Owen Taylor3473f882001-02-23 17:55:21 +00003668 if (cur == NULL) return;
3669 switch(cur->type) {
3670 case XML_TEXT_NODE:
3671 case XML_CDATA_SECTION_NODE:
3672 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003673 case XML_DOCUMENT_TYPE_NODE:
3674 case XML_DOCUMENT_FRAG_NODE:
3675 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003676 case XML_DTD_NODE:
3677 case XML_ELEMENT_DECL:
3678 case XML_ATTRIBUTE_DECL:
3679 case XML_ENTITY_DECL:
3680 case XML_PI_NODE:
3681 case XML_ENTITY_REF_NODE:
3682 case XML_ENTITY_NODE:
3683 case XML_NAMESPACE_DECL:
3684 case XML_XINCLUDE_START:
3685 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003686 return;
3687 case XML_ELEMENT_NODE:
3688 case XML_ATTRIBUTE_NODE:
3689 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003690 case XML_DOCUMENT_NODE:
3691#ifdef LIBXML_DOCB_ENABLED
3692 case XML_DOCB_DOCUMENT_NODE:
3693#endif
3694 case XML_HTML_DOCUMENT_NODE: {
3695 xmlDocPtr doc = (xmlDocPtr) cur;
3696
3697 if (doc->URL != NULL)
3698 xmlFree((xmlChar *) doc->URL);
3699 if (uri == NULL)
3700 doc->URL = NULL;
3701 else
3702 doc->URL = xmlStrdup(uri);
3703 return;
3704 }
Owen Taylor3473f882001-02-23 17:55:21 +00003705 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003706
3707 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3708 if (ns == NULL)
3709 return;
3710 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003711}
3712
3713/**
Owen Taylor3473f882001-02-23 17:55:21 +00003714 * xmlNodeGetBase:
3715 * @doc: the document the node pertains to
3716 * @cur: the node being checked
3717 *
3718 * Searches for the BASE URL. The code should work on both XML
3719 * and HTML document even if base mechanisms are completely different.
3720 * It returns the base as defined in RFC 2396 sections
3721 * 5.1.1. Base URI within Document Content
3722 * and
3723 * 5.1.2. Base URI from the Encapsulating Entity
3724 * However it does not return the document base (5.1.3), use
3725 * xmlDocumentGetBase() for this
3726 *
3727 * Returns a pointer to the base URL, or NULL if not found
3728 * It's up to the caller to free the memory.
3729 */
3730xmlChar *
3731xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003732 xmlChar *oldbase = NULL;
3733 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003734
3735 if ((cur == NULL) && (doc == NULL))
3736 return(NULL);
3737 if (doc == NULL) doc = cur->doc;
3738 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3739 cur = doc->children;
3740 while ((cur != NULL) && (cur->name != NULL)) {
3741 if (cur->type != XML_ELEMENT_NODE) {
3742 cur = cur->next;
3743 continue;
3744 }
3745 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3746 cur = cur->children;
3747 continue;
3748 }
3749 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3750 cur = cur->children;
3751 continue;
3752 }
3753 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3754 return(xmlGetProp(cur, BAD_CAST "href"));
3755 }
3756 cur = cur->next;
3757 }
3758 return(NULL);
3759 }
3760 while (cur != NULL) {
3761 if (cur->type == XML_ENTITY_DECL) {
3762 xmlEntityPtr ent = (xmlEntityPtr) cur;
3763 return(xmlStrdup(ent->URI));
3764 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003765 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003766 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003767 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003768 if (oldbase != NULL) {
3769 newbase = xmlBuildURI(oldbase, base);
3770 if (newbase != NULL) {
3771 xmlFree(oldbase);
3772 xmlFree(base);
3773 oldbase = newbase;
3774 } else {
3775 xmlFree(oldbase);
3776 xmlFree(base);
3777 return(NULL);
3778 }
3779 } else {
3780 oldbase = base;
3781 }
3782 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3783 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3784 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3785 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003786 }
3787 }
Owen Taylor3473f882001-02-23 17:55:21 +00003788 cur = cur->parent;
3789 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003790 if ((doc != NULL) && (doc->URL != NULL)) {
3791 if (oldbase == NULL)
3792 return(xmlStrdup(doc->URL));
3793 newbase = xmlBuildURI(oldbase, doc->URL);
3794 xmlFree(oldbase);
3795 return(newbase);
3796 }
3797 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003798}
3799
3800/**
3801 * xmlNodeGetContent:
3802 * @cur: the node being read
3803 *
3804 * Read the value of a node, this can be either the text carried
3805 * directly by this node if it's a TEXT node or the aggregate string
3806 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003807 * Entity references are substituted.
3808 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003809 * It's up to the caller to free the memory.
3810 */
3811xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00003812xmlNodeGetContent(xmlNodePtr cur)
3813{
3814 if (cur == NULL)
3815 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003816 switch (cur->type) {
3817 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003818 case XML_ELEMENT_NODE:{
3819 xmlNodePtr tmp = cur;
3820 xmlBufferPtr buffer;
3821 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003822
Daniel Veillard7646b182002-04-20 06:41:40 +00003823 buffer = xmlBufferCreate();
3824 if (buffer == NULL)
3825 return (NULL);
3826 while (tmp != NULL) {
3827 switch (tmp->type) {
3828 case XML_CDATA_SECTION_NODE:
3829 case XML_TEXT_NODE:
3830 if (tmp->content != NULL)
3831 xmlBufferCat(buffer, tmp->content);
3832 break;
3833 case XML_ENTITY_REF_NODE:{
3834 /* recursive substitution of entity references */
3835 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003836
Daniel Veillard7646b182002-04-20 06:41:40 +00003837 if (cont) {
3838 xmlBufferCat(buffer,
3839 (const xmlChar *) cont);
3840 xmlFree(cont);
3841 }
3842 break;
3843 }
3844 default:
3845 break;
3846 }
3847 /*
3848 * Skip to next node
3849 */
3850 if (tmp->children != NULL) {
3851 if (tmp->children->type != XML_ENTITY_DECL) {
3852 tmp = tmp->children;
3853 continue;
3854 }
3855 }
3856 if (tmp == cur)
3857 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003858
Daniel Veillard7646b182002-04-20 06:41:40 +00003859 if (tmp->next != NULL) {
3860 tmp = tmp->next;
3861 continue;
3862 }
3863
3864 do {
3865 tmp = tmp->parent;
3866 if (tmp == NULL)
3867 break;
3868 if (tmp == cur) {
3869 tmp = NULL;
3870 break;
3871 }
3872 if (tmp->next != NULL) {
3873 tmp = tmp->next;
3874 break;
3875 }
3876 } while (tmp != NULL);
3877 }
3878 ret = buffer->content;
3879 buffer->content = NULL;
3880 xmlBufferFree(buffer);
3881 return (ret);
3882 }
3883 case XML_ATTRIBUTE_NODE:{
3884 xmlAttrPtr attr = (xmlAttrPtr) cur;
3885
3886 if (attr->parent != NULL)
3887 return (xmlNodeListGetString
3888 (attr->parent->doc, attr->children, 1));
3889 else
3890 return (xmlNodeListGetString(NULL, attr->children, 1));
3891 break;
3892 }
Owen Taylor3473f882001-02-23 17:55:21 +00003893 case XML_COMMENT_NODE:
3894 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003895 if (cur->content != NULL)
3896 return (xmlStrdup(cur->content));
3897 return (NULL);
3898 case XML_ENTITY_REF_NODE:{
3899 xmlEntityPtr ent;
3900 xmlNodePtr tmp;
3901 xmlBufferPtr buffer;
3902 xmlChar *ret;
3903
3904 /* lookup entity declaration */
3905 ent = xmlGetDocEntity(cur->doc, cur->name);
3906 if (ent == NULL)
3907 return (NULL);
3908
3909 buffer = xmlBufferCreate();
3910 if (buffer == NULL)
3911 return (NULL);
3912
3913 /* an entity content can be any "well balanced chunk",
3914 * i.e. the result of the content [43] production:
3915 * http://www.w3.org/TR/REC-xml#NT-content
3916 * -> we iterate through child nodes and recursive call
3917 * xmlNodeGetContent() which handles all possible node types */
3918 tmp = ent->children;
3919 while (tmp) {
3920 xmlChar *cont = xmlNodeGetContent(tmp);
3921
3922 if (cont) {
3923 xmlBufferCat(buffer, (const xmlChar *) cont);
3924 xmlFree(cont);
3925 }
3926 tmp = tmp->next;
3927 }
3928
3929 ret = buffer->content;
3930 buffer->content = NULL;
3931 xmlBufferFree(buffer);
3932 return (ret);
3933 }
Owen Taylor3473f882001-02-23 17:55:21 +00003934 case XML_ENTITY_NODE:
3935 case XML_DOCUMENT_NODE:
3936 case XML_HTML_DOCUMENT_NODE:
3937 case XML_DOCUMENT_TYPE_NODE:
3938 case XML_NOTATION_NODE:
3939 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003940 case XML_XINCLUDE_START:
3941 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003942#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00003943 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003944#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00003945 return (NULL);
3946 case XML_NAMESPACE_DECL:
3947 return (xmlStrdup(((xmlNsPtr) cur)->href));
Owen Taylor3473f882001-02-23 17:55:21 +00003948 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00003949 /* TODO !!! */
3950 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003951 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00003952 /* TODO !!! */
3953 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003954 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00003955 /* TODO !!! */
3956 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003957 case XML_CDATA_SECTION_NODE:
3958 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003959 if (cur->content != NULL)
3960 return (xmlStrdup(cur->content));
3961 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003962 }
Daniel Veillard7646b182002-04-20 06:41:40 +00003963 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003964}
Owen Taylor3473f882001-02-23 17:55:21 +00003965/**
3966 * xmlNodeSetContent:
3967 * @cur: the node being modified
3968 * @content: the new value of the content
3969 *
3970 * Replace the content of a node.
3971 */
3972void
3973xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3974 if (cur == NULL) {
3975#ifdef DEBUG_TREE
3976 xmlGenericError(xmlGenericErrorContext,
3977 "xmlNodeSetContent : node == NULL\n");
3978#endif
3979 return;
3980 }
3981 switch (cur->type) {
3982 case XML_DOCUMENT_FRAG_NODE:
3983 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003984 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003985 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3986 cur->children = xmlStringGetNodeList(cur->doc, content);
3987 UPDATE_LAST_CHILD_AND_PARENT(cur)
3988 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003989 case XML_TEXT_NODE:
3990 case XML_CDATA_SECTION_NODE:
3991 case XML_ENTITY_REF_NODE:
3992 case XML_ENTITY_NODE:
3993 case XML_PI_NODE:
3994 case XML_COMMENT_NODE:
3995 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003996 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003997 }
3998 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3999 cur->last = cur->children = NULL;
4000 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004001 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004002 } else
4003 cur->content = NULL;
4004 break;
4005 case XML_DOCUMENT_NODE:
4006 case XML_HTML_DOCUMENT_NODE:
4007 case XML_DOCUMENT_TYPE_NODE:
4008 case XML_XINCLUDE_START:
4009 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004010#ifdef LIBXML_DOCB_ENABLED
4011 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004012#endif
4013 break;
4014 case XML_NOTATION_NODE:
4015 break;
4016 case XML_DTD_NODE:
4017 break;
4018 case XML_NAMESPACE_DECL:
4019 break;
4020 case XML_ELEMENT_DECL:
4021 /* TODO !!! */
4022 break;
4023 case XML_ATTRIBUTE_DECL:
4024 /* TODO !!! */
4025 break;
4026 case XML_ENTITY_DECL:
4027 /* TODO !!! */
4028 break;
4029 }
4030}
4031
4032/**
4033 * xmlNodeSetContentLen:
4034 * @cur: the node being modified
4035 * @content: the new value of the content
4036 * @len: the size of @content
4037 *
4038 * Replace the content of a node.
4039 */
4040void
4041xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4042 if (cur == NULL) {
4043#ifdef DEBUG_TREE
4044 xmlGenericError(xmlGenericErrorContext,
4045 "xmlNodeSetContentLen : node == NULL\n");
4046#endif
4047 return;
4048 }
4049 switch (cur->type) {
4050 case XML_DOCUMENT_FRAG_NODE:
4051 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004052 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004053 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4054 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4055 UPDATE_LAST_CHILD_AND_PARENT(cur)
4056 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004057 case XML_TEXT_NODE:
4058 case XML_CDATA_SECTION_NODE:
4059 case XML_ENTITY_REF_NODE:
4060 case XML_ENTITY_NODE:
4061 case XML_PI_NODE:
4062 case XML_COMMENT_NODE:
4063 case XML_NOTATION_NODE:
4064 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004065 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004066 }
4067 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4068 cur->children = cur->last = NULL;
4069 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004070 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004071 } else
4072 cur->content = NULL;
4073 break;
4074 case XML_DOCUMENT_NODE:
4075 case XML_DTD_NODE:
4076 case XML_HTML_DOCUMENT_NODE:
4077 case XML_DOCUMENT_TYPE_NODE:
4078 case XML_NAMESPACE_DECL:
4079 case XML_XINCLUDE_START:
4080 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004081#ifdef LIBXML_DOCB_ENABLED
4082 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004083#endif
4084 break;
4085 case XML_ELEMENT_DECL:
4086 /* TODO !!! */
4087 break;
4088 case XML_ATTRIBUTE_DECL:
4089 /* TODO !!! */
4090 break;
4091 case XML_ENTITY_DECL:
4092 /* TODO !!! */
4093 break;
4094 }
4095}
4096
4097/**
4098 * xmlNodeAddContentLen:
4099 * @cur: the node being modified
4100 * @content: extra content
4101 * @len: the size of @content
4102 *
4103 * Append the extra substring to the node content.
4104 */
4105void
4106xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4107 if (cur == NULL) {
4108#ifdef DEBUG_TREE
4109 xmlGenericError(xmlGenericErrorContext,
4110 "xmlNodeAddContentLen : node == NULL\n");
4111#endif
4112 return;
4113 }
4114 if (len <= 0) return;
4115 switch (cur->type) {
4116 case XML_DOCUMENT_FRAG_NODE:
4117 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004118 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004119
Daniel Veillard7db37732001-07-12 01:20:08 +00004120 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004121 newNode = xmlNewTextLen(content, len);
4122 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004123 tmp = xmlAddChild(cur, newNode);
4124 if (tmp != newNode)
4125 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004126 if ((last != NULL) && (last->next == newNode)) {
4127 xmlTextMerge(last, newNode);
4128 }
4129 }
4130 break;
4131 }
4132 case XML_ATTRIBUTE_NODE:
4133 break;
4134 case XML_TEXT_NODE:
4135 case XML_CDATA_SECTION_NODE:
4136 case XML_ENTITY_REF_NODE:
4137 case XML_ENTITY_NODE:
4138 case XML_PI_NODE:
4139 case XML_COMMENT_NODE:
4140 case XML_NOTATION_NODE:
4141 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004142 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004143 }
4144 case XML_DOCUMENT_NODE:
4145 case XML_DTD_NODE:
4146 case XML_HTML_DOCUMENT_NODE:
4147 case XML_DOCUMENT_TYPE_NODE:
4148 case XML_NAMESPACE_DECL:
4149 case XML_XINCLUDE_START:
4150 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004151#ifdef LIBXML_DOCB_ENABLED
4152 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004153#endif
4154 break;
4155 case XML_ELEMENT_DECL:
4156 case XML_ATTRIBUTE_DECL:
4157 case XML_ENTITY_DECL:
4158 break;
4159 }
4160}
4161
4162/**
4163 * xmlNodeAddContent:
4164 * @cur: the node being modified
4165 * @content: extra content
4166 *
4167 * Append the extra substring to the node content.
4168 */
4169void
4170xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4171 int len;
4172
4173 if (cur == NULL) {
4174#ifdef DEBUG_TREE
4175 xmlGenericError(xmlGenericErrorContext,
4176 "xmlNodeAddContent : node == NULL\n");
4177#endif
4178 return;
4179 }
4180 if (content == NULL) return;
4181 len = xmlStrlen(content);
4182 xmlNodeAddContentLen(cur, content, len);
4183}
4184
4185/**
4186 * xmlTextMerge:
4187 * @first: the first text node
4188 * @second: the second text node being merged
4189 *
4190 * Merge two text nodes into one
4191 * Returns the first text node augmented
4192 */
4193xmlNodePtr
4194xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4195 if (first == NULL) return(second);
4196 if (second == NULL) return(first);
4197 if (first->type != XML_TEXT_NODE) return(first);
4198 if (second->type != XML_TEXT_NODE) return(first);
4199 if (second->name != first->name)
4200 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004201 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004202 xmlUnlinkNode(second);
4203 xmlFreeNode(second);
4204 return(first);
4205}
4206
4207/**
4208 * xmlGetNsList:
4209 * @doc: the document
4210 * @node: the current node
4211 *
4212 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004213 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004214 * that need to be freed by the caller or NULL if no
4215 * namespace if defined
4216 */
4217xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004218xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4219{
Owen Taylor3473f882001-02-23 17:55:21 +00004220 xmlNsPtr cur;
4221 xmlNsPtr *ret = NULL;
4222 int nbns = 0;
4223 int maxns = 10;
4224 int i;
4225
4226 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004227 if (node->type == XML_ELEMENT_NODE) {
4228 cur = node->nsDef;
4229 while (cur != NULL) {
4230 if (ret == NULL) {
4231 ret =
4232 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4233 sizeof(xmlNsPtr));
4234 if (ret == NULL) {
4235 xmlGenericError(xmlGenericErrorContext,
4236 "xmlGetNsList : out of memory!\n");
4237 return (NULL);
4238 }
4239 ret[nbns] = NULL;
4240 }
4241 for (i = 0; i < nbns; i++) {
4242 if ((cur->prefix == ret[i]->prefix) ||
4243 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4244 break;
4245 }
4246 if (i >= nbns) {
4247 if (nbns >= maxns) {
4248 maxns *= 2;
4249 ret = (xmlNsPtr *) xmlRealloc(ret,
4250 (maxns +
4251 1) *
4252 sizeof(xmlNsPtr));
4253 if (ret == NULL) {
4254 xmlGenericError(xmlGenericErrorContext,
4255 "xmlGetNsList : realloc failed!\n");
4256 return (NULL);
4257 }
4258 }
4259 ret[nbns++] = cur;
4260 ret[nbns] = NULL;
4261 }
Owen Taylor3473f882001-02-23 17:55:21 +00004262
Daniel Veillard77044732001-06-29 21:31:07 +00004263 cur = cur->next;
4264 }
4265 }
4266 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004267 }
Daniel Veillard77044732001-06-29 21:31:07 +00004268 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004269}
4270
4271/**
4272 * xmlSearchNs:
4273 * @doc: the document
4274 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004275 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004276 *
4277 * Search a Ns registered under a given name space for a document.
4278 * recurse on the parents until it finds the defined namespace
4279 * or return NULL otherwise.
4280 * @nameSpace can be NULL, this is a search for the default namespace.
4281 * We don't allow to cross entities boundaries. If you don't declare
4282 * the namespace within those you will be in troubles !!! A warning
4283 * is generated to cover this case.
4284 *
4285 * Returns the namespace pointer or NULL.
4286 */
4287xmlNsPtr
4288xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4289 xmlNsPtr cur;
4290
4291 if (node == NULL) return(NULL);
4292 if ((nameSpace != NULL) &&
4293 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004294 if (doc == NULL)
4295 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004296 if (doc->oldNs == NULL) {
4297 /*
4298 * Allocate a new Namespace and fill the fields.
4299 */
4300 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4301 if (doc->oldNs == NULL) {
4302 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004303 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004304 return(NULL);
4305 }
4306 memset(doc->oldNs, 0, sizeof(xmlNs));
4307 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4308
4309 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4310 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4311 }
4312 return(doc->oldNs);
4313 }
4314 while (node != NULL) {
4315 if ((node->type == XML_ENTITY_REF_NODE) ||
4316 (node->type == XML_ENTITY_NODE) ||
4317 (node->type == XML_ENTITY_DECL))
4318 return(NULL);
4319 if (node->type == XML_ELEMENT_NODE) {
4320 cur = node->nsDef;
4321 while (cur != NULL) {
4322 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4323 (cur->href != NULL))
4324 return(cur);
4325 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4326 (cur->href != NULL) &&
4327 (xmlStrEqual(cur->prefix, nameSpace)))
4328 return(cur);
4329 cur = cur->next;
4330 }
4331 }
4332 node = node->parent;
4333 }
4334 return(NULL);
4335}
4336
4337/**
4338 * xmlSearchNsByHref:
4339 * @doc: the document
4340 * @node: the current node
4341 * @href: the namespace value
4342 *
4343 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4344 * the defined namespace or return NULL otherwise.
4345 * Returns the namespace pointer or NULL.
4346 */
4347xmlNsPtr
4348xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4349 xmlNsPtr cur;
4350 xmlNodePtr orig = node;
4351
4352 if ((node == NULL) || (href == NULL)) return(NULL);
4353 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004354 /*
4355 * Only the document can hold the XML spec namespace.
4356 */
4357 if (doc == NULL)
4358 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004359 if (doc->oldNs == NULL) {
4360 /*
4361 * Allocate a new Namespace and fill the fields.
4362 */
4363 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4364 if (doc->oldNs == NULL) {
4365 xmlGenericError(xmlGenericErrorContext,
4366 "xmlSearchNsByHref : malloc failed\n");
4367 return(NULL);
4368 }
4369 memset(doc->oldNs, 0, sizeof(xmlNs));
4370 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4371
4372 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4373 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4374 }
4375 return(doc->oldNs);
4376 }
4377 while (node != NULL) {
4378 cur = node->nsDef;
4379 while (cur != NULL) {
4380 if ((cur->href != NULL) && (href != NULL) &&
4381 (xmlStrEqual(cur->href, href))) {
4382 /*
4383 * Check that the prefix is not shadowed between orig and node
4384 */
4385 xmlNodePtr check = orig;
4386 xmlNsPtr tst;
4387
4388 while (check != node) {
4389 tst = check->nsDef;
4390 while (tst != NULL) {
4391 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4392 goto shadowed;
4393 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4394 (xmlStrEqual(tst->prefix, cur->prefix)))
4395 goto shadowed;
4396 tst = tst->next;
4397 }
4398 check = check->parent;
4399 }
4400 return(cur);
4401 }
4402shadowed:
4403 cur = cur->next;
4404 }
4405 node = node->parent;
4406 }
4407 return(NULL);
4408}
4409
4410/**
4411 * xmlNewReconciliedNs
4412 * @doc: the document
4413 * @tree: a node expected to hold the new namespace
4414 * @ns: the original namespace
4415 *
4416 * This function tries to locate a namespace definition in a tree
4417 * ancestors, or create a new namespace definition node similar to
4418 * @ns trying to reuse the same prefix. However if the given prefix is
4419 * null (default namespace) or reused within the subtree defined by
4420 * @tree or on one of its ancestors then a new prefix is generated.
4421 * Returns the (new) namespace definition or NULL in case of error
4422 */
4423xmlNsPtr
4424xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4425 xmlNsPtr def;
4426 xmlChar prefix[50];
4427 int counter = 1;
4428
4429 if (tree == NULL) {
4430#ifdef DEBUG_TREE
4431 xmlGenericError(xmlGenericErrorContext,
4432 "xmlNewReconciliedNs : tree == NULL\n");
4433#endif
4434 return(NULL);
4435 }
4436 if (ns == NULL) {
4437#ifdef DEBUG_TREE
4438 xmlGenericError(xmlGenericErrorContext,
4439 "xmlNewReconciliedNs : ns == NULL\n");
4440#endif
4441 return(NULL);
4442 }
4443 /*
4444 * Search an existing namespace definition inherited.
4445 */
4446 def = xmlSearchNsByHref(doc, tree, ns->href);
4447 if (def != NULL)
4448 return(def);
4449
4450 /*
4451 * Find a close prefix which is not already in use.
4452 * Let's strip namespace prefixes longer than 20 chars !
4453 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004454 if (ns->prefix == NULL)
4455 sprintf((char *) prefix, "default");
4456 else
4457 sprintf((char *) prefix, "%.20s", ns->prefix);
4458
Owen Taylor3473f882001-02-23 17:55:21 +00004459 def = xmlSearchNs(doc, tree, prefix);
4460 while (def != NULL) {
4461 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004462 if (ns->prefix == NULL)
4463 sprintf((char *) prefix, "default%d", counter++);
4464 else
4465 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004466 def = xmlSearchNs(doc, tree, prefix);
4467 }
4468
4469 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004470 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004471 */
4472 def = xmlNewNs(tree, ns->href, prefix);
4473 return(def);
4474}
4475
4476/**
4477 * xmlReconciliateNs
4478 * @doc: the document
4479 * @tree: a node defining the subtree to reconciliate
4480 *
4481 * This function checks that all the namespaces declared within the given
4482 * tree are properly declared. This is needed for example after Copy or Cut
4483 * and then paste operations. The subtree may still hold pointers to
4484 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004485 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004486 * the new environment. If not possible the new namespaces are redeclared
4487 * on @tree at the top of the given subtree.
4488 * Returns the number of namespace declarations created or -1 in case of error.
4489 */
4490int
4491xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4492 xmlNsPtr *oldNs = NULL;
4493 xmlNsPtr *newNs = NULL;
4494 int sizeCache = 0;
4495 int nbCache = 0;
4496
4497 xmlNsPtr n;
4498 xmlNodePtr node = tree;
4499 xmlAttrPtr attr;
4500 int ret = 0, i;
4501
4502 while (node != NULL) {
4503 /*
4504 * Reconciliate the node namespace
4505 */
4506 if (node->ns != NULL) {
4507 /*
4508 * initialize the cache if needed
4509 */
4510 if (sizeCache == 0) {
4511 sizeCache = 10;
4512 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4513 sizeof(xmlNsPtr));
4514 if (oldNs == NULL) {
4515 xmlGenericError(xmlGenericErrorContext,
4516 "xmlReconciliateNs : memory pbm\n");
4517 return(-1);
4518 }
4519 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4520 sizeof(xmlNsPtr));
4521 if (newNs == NULL) {
4522 xmlGenericError(xmlGenericErrorContext,
4523 "xmlReconciliateNs : memory pbm\n");
4524 xmlFree(oldNs);
4525 return(-1);
4526 }
4527 }
4528 for (i = 0;i < nbCache;i++) {
4529 if (oldNs[i] == node->ns) {
4530 node->ns = newNs[i];
4531 break;
4532 }
4533 }
4534 if (i == nbCache) {
4535 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004536 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004537 */
4538 n = xmlNewReconciliedNs(doc, tree, node->ns);
4539 if (n != NULL) { /* :-( what if else ??? */
4540 /*
4541 * check if we need to grow the cache buffers.
4542 */
4543 if (sizeCache <= nbCache) {
4544 sizeCache *= 2;
4545 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4546 sizeof(xmlNsPtr));
4547 if (oldNs == NULL) {
4548 xmlGenericError(xmlGenericErrorContext,
4549 "xmlReconciliateNs : memory pbm\n");
4550 xmlFree(newNs);
4551 return(-1);
4552 }
4553 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4554 sizeof(xmlNsPtr));
4555 if (newNs == NULL) {
4556 xmlGenericError(xmlGenericErrorContext,
4557 "xmlReconciliateNs : memory pbm\n");
4558 xmlFree(oldNs);
4559 return(-1);
4560 }
4561 }
4562 newNs[nbCache] = n;
4563 oldNs[nbCache++] = node->ns;
4564 node->ns = n;
4565 }
4566 }
4567 }
4568 /*
4569 * now check for namespace hold by attributes on the node.
4570 */
4571 attr = node->properties;
4572 while (attr != NULL) {
4573 if (attr->ns != NULL) {
4574 /*
4575 * initialize the cache if needed
4576 */
4577 if (sizeCache == 0) {
4578 sizeCache = 10;
4579 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4580 sizeof(xmlNsPtr));
4581 if (oldNs == NULL) {
4582 xmlGenericError(xmlGenericErrorContext,
4583 "xmlReconciliateNs : memory pbm\n");
4584 return(-1);
4585 }
4586 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4587 sizeof(xmlNsPtr));
4588 if (newNs == NULL) {
4589 xmlGenericError(xmlGenericErrorContext,
4590 "xmlReconciliateNs : memory pbm\n");
4591 xmlFree(oldNs);
4592 return(-1);
4593 }
4594 }
4595 for (i = 0;i < nbCache;i++) {
4596 if (oldNs[i] == attr->ns) {
4597 node->ns = newNs[i];
4598 break;
4599 }
4600 }
4601 if (i == nbCache) {
4602 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004603 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004604 */
4605 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4606 if (n != NULL) { /* :-( what if else ??? */
4607 /*
4608 * check if we need to grow the cache buffers.
4609 */
4610 if (sizeCache <= nbCache) {
4611 sizeCache *= 2;
4612 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4613 sizeof(xmlNsPtr));
4614 if (oldNs == NULL) {
4615 xmlGenericError(xmlGenericErrorContext,
4616 "xmlReconciliateNs : memory pbm\n");
4617 xmlFree(newNs);
4618 return(-1);
4619 }
4620 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4621 sizeof(xmlNsPtr));
4622 if (newNs == NULL) {
4623 xmlGenericError(xmlGenericErrorContext,
4624 "xmlReconciliateNs : memory pbm\n");
4625 xmlFree(oldNs);
4626 return(-1);
4627 }
4628 }
4629 newNs[nbCache] = n;
4630 oldNs[nbCache++] = attr->ns;
4631 attr->ns = n;
4632 }
4633 }
4634 }
4635 attr = attr->next;
4636 }
4637
4638 /*
4639 * Browse the full subtree, deep first
4640 */
4641 if (node->children != NULL) {
4642 /* deep first */
4643 node = node->children;
4644 } else if ((node != tree) && (node->next != NULL)) {
4645 /* then siblings */
4646 node = node->next;
4647 } else if (node != tree) {
4648 /* go up to parents->next if needed */
4649 while (node != tree) {
4650 if (node->parent != NULL)
4651 node = node->parent;
4652 if ((node != tree) && (node->next != NULL)) {
4653 node = node->next;
4654 break;
4655 }
4656 if (node->parent == NULL) {
4657 node = NULL;
4658 break;
4659 }
4660 }
4661 /* exit condition */
4662 if (node == tree)
4663 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004664 } else
4665 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004666 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004667 if (oldNs != NULL)
4668 xmlFree(oldNs);
4669 if (newNs != NULL)
4670 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004671 return(ret);
4672}
4673
4674/**
4675 * xmlHasProp:
4676 * @node: the node
4677 * @name: the attribute name
4678 *
4679 * Search an attribute associated to a node
4680 * This function also looks in DTD attribute declaration for #FIXED or
4681 * default declaration values unless DTD use has been turned off.
4682 *
4683 * Returns the attribute or the attribute declaration or NULL if
4684 * neither was found.
4685 */
4686xmlAttrPtr
4687xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4688 xmlAttrPtr prop;
4689 xmlDocPtr doc;
4690
4691 if ((node == NULL) || (name == NULL)) return(NULL);
4692 /*
4693 * Check on the properties attached to the node
4694 */
4695 prop = node->properties;
4696 while (prop != NULL) {
4697 if (xmlStrEqual(prop->name, name)) {
4698 return(prop);
4699 }
4700 prop = prop->next;
4701 }
4702 if (!xmlCheckDTD) return(NULL);
4703
4704 /*
4705 * Check if there is a default declaration in the internal
4706 * or external subsets
4707 */
4708 doc = node->doc;
4709 if (doc != NULL) {
4710 xmlAttributePtr attrDecl;
4711 if (doc->intSubset != NULL) {
4712 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4713 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4714 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4715 if (attrDecl != NULL)
4716 return((xmlAttrPtr) attrDecl);
4717 }
4718 }
4719 return(NULL);
4720}
4721
4722/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004723 * xmlHasNsProp:
4724 * @node: the node
4725 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004726 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004727 *
4728 * Search for an attribute associated to a node
4729 * This attribute has to be anchored in the namespace specified.
4730 * This does the entity substitution.
4731 * This function looks in DTD attribute declaration for #FIXED or
4732 * default declaration values unless DTD use has been turned off.
4733 *
4734 * Returns the attribute or the attribute declaration or NULL
4735 * if neither was found.
4736 */
4737xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004738xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004739 xmlAttrPtr prop;
4740 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004741
4742 if (node == NULL)
4743 return(NULL);
4744
4745 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004746 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004747 return(xmlHasProp(node, name));
4748 while (prop != NULL) {
4749 /*
4750 * One need to have
4751 * - same attribute names
4752 * - and the attribute carrying that namespace
4753 * or
4754 * no namespace on the attribute and the element carrying it
4755 */
4756 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004757 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4758 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004759 }
4760 prop = prop->next;
4761 }
4762 if (!xmlCheckDTD) return(NULL);
4763
4764 /*
4765 * Check if there is a default declaration in the internal
4766 * or external subsets
4767 */
4768 doc = node->doc;
4769 if (doc != NULL) {
4770 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004771 xmlAttributePtr attrDecl = NULL;
4772 xmlNsPtr *nsList, *cur;
4773 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004774
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004775 nsList = xmlGetNsList(node->doc, node);
4776 if (nsList == NULL)
4777 return(NULL);
4778 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4779 ename = xmlStrdup(node->ns->prefix);
4780 ename = xmlStrcat(ename, BAD_CAST ":");
4781 ename = xmlStrcat(ename, node->name);
4782 } else {
4783 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004784 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004785 if (ename == NULL) {
4786 xmlFree(nsList);
4787 return(NULL);
4788 }
4789
4790 cur = nsList;
4791 while (*cur != NULL) {
4792 if (xmlStrEqual((*cur)->href, nameSpace)) {
4793 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4794 name, (*cur)->prefix);
4795 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4796 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4797 name, (*cur)->prefix);
4798 }
4799 cur++;
4800 }
4801 xmlFree(nsList);
4802 xmlFree(ename);
4803 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004804 }
4805 }
4806 return(NULL);
4807}
4808
4809/**
Owen Taylor3473f882001-02-23 17:55:21 +00004810 * xmlGetProp:
4811 * @node: the node
4812 * @name: the attribute name
4813 *
4814 * Search and get the value of an attribute associated to a node
4815 * This does the entity substitution.
4816 * This function looks in DTD attribute declaration for #FIXED or
4817 * default declaration values unless DTD use has been turned off.
4818 *
4819 * Returns the attribute value or NULL if not found.
4820 * It's up to the caller to free the memory.
4821 */
4822xmlChar *
4823xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4824 xmlAttrPtr prop;
4825 xmlDocPtr doc;
4826
4827 if ((node == NULL) || (name == NULL)) return(NULL);
4828 /*
4829 * Check on the properties attached to the node
4830 */
4831 prop = node->properties;
4832 while (prop != NULL) {
4833 if (xmlStrEqual(prop->name, name)) {
4834 xmlChar *ret;
4835
4836 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4837 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4838 return(ret);
4839 }
4840 prop = prop->next;
4841 }
4842 if (!xmlCheckDTD) return(NULL);
4843
4844 /*
4845 * Check if there is a default declaration in the internal
4846 * or external subsets
4847 */
4848 doc = node->doc;
4849 if (doc != NULL) {
4850 xmlAttributePtr attrDecl;
4851 if (doc->intSubset != NULL) {
4852 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4853 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4854 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4855 if (attrDecl != NULL)
4856 return(xmlStrdup(attrDecl->defaultValue));
4857 }
4858 }
4859 return(NULL);
4860}
4861
4862/**
4863 * xmlGetNsProp:
4864 * @node: the node
4865 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004866 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004867 *
4868 * Search and get the value of an attribute associated to a node
4869 * This attribute has to be anchored in the namespace specified.
4870 * This does the entity substitution.
4871 * This function looks in DTD attribute declaration for #FIXED or
4872 * default declaration values unless DTD use has been turned off.
4873 *
4874 * Returns the attribute value or NULL if not found.
4875 * It's up to the caller to free the memory.
4876 */
4877xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004878xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004879 xmlAttrPtr prop;
4880 xmlDocPtr doc;
4881 xmlNsPtr ns;
4882
4883 if (node == NULL)
4884 return(NULL);
4885
4886 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004887 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004888 return(xmlGetProp(node, name));
4889 while (prop != NULL) {
4890 /*
4891 * One need to have
4892 * - same attribute names
4893 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004894 */
4895 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004896 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004897 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004898 xmlChar *ret;
4899
4900 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4901 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4902 return(ret);
4903 }
4904 prop = prop->next;
4905 }
4906 if (!xmlCheckDTD) return(NULL);
4907
4908 /*
4909 * Check if there is a default declaration in the internal
4910 * or external subsets
4911 */
4912 doc = node->doc;
4913 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004914 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004915 xmlAttributePtr attrDecl;
4916
Owen Taylor3473f882001-02-23 17:55:21 +00004917 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4918 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4919 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4920
4921 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4922 /*
4923 * The DTD declaration only allows a prefix search
4924 */
4925 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004926 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004927 return(xmlStrdup(attrDecl->defaultValue));
4928 }
4929 }
4930 }
4931 return(NULL);
4932}
4933
4934/**
4935 * xmlSetProp:
4936 * @node: the node
4937 * @name: the attribute name
4938 * @value: the attribute value
4939 *
4940 * Set (or reset) an attribute carried by a node.
4941 * Returns the attribute pointer.
4942 */
4943xmlAttrPtr
4944xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004945 xmlAttrPtr prop;
4946 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004947
4948 if ((node == NULL) || (name == NULL))
4949 return(NULL);
4950 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004951 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004952 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004953 if ((xmlStrEqual(prop->name, name)) &&
4954 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004955 xmlNodePtr oldprop = prop->children;
4956
Owen Taylor3473f882001-02-23 17:55:21 +00004957 prop->children = NULL;
4958 prop->last = NULL;
4959 if (value != NULL) {
4960 xmlChar *buffer;
4961 xmlNodePtr tmp;
4962
4963 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4964 prop->children = xmlStringGetNodeList(node->doc, buffer);
4965 prop->last = NULL;
4966 prop->doc = doc;
4967 tmp = prop->children;
4968 while (tmp != NULL) {
4969 tmp->parent = (xmlNodePtr) prop;
4970 tmp->doc = doc;
4971 if (tmp->next == NULL)
4972 prop->last = tmp;
4973 tmp = tmp->next;
4974 }
4975 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004976 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004977 if (oldprop != NULL)
4978 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004979 return(prop);
4980 }
4981 prop = prop->next;
4982 }
4983 prop = xmlNewProp(node, name, value);
4984 return(prop);
4985}
4986
4987/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004988 * xmlUnsetProp:
4989 * @node: the node
4990 * @name: the attribute name
4991 *
4992 * Remove an attribute carried by a node.
4993 * Returns 0 if successful, -1 if not found
4994 */
4995int
4996xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4997 xmlAttrPtr prop = node->properties, prev = NULL;;
4998
4999 if ((node == NULL) || (name == NULL))
5000 return(-1);
5001 while (prop != NULL) {
5002 if ((xmlStrEqual(prop->name, name)) &&
5003 (prop->ns == NULL)) {
5004 if (prev == NULL)
5005 node->properties = prop->next;
5006 else
5007 prev->next = prop->next;
5008 xmlFreeProp(prop);
5009 return(0);
5010 }
5011 prev = prop;
5012 prop = prop->next;
5013 }
5014 return(-1);
5015}
5016
5017/**
Owen Taylor3473f882001-02-23 17:55:21 +00005018 * xmlSetNsProp:
5019 * @node: the node
5020 * @ns: the namespace definition
5021 * @name: the attribute name
5022 * @value: the attribute value
5023 *
5024 * Set (or reset) an attribute carried by a node.
5025 * The ns structure must be in scope, this is not checked.
5026 *
5027 * Returns the attribute pointer.
5028 */
5029xmlAttrPtr
5030xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5031 const xmlChar *value) {
5032 xmlAttrPtr prop;
5033
5034 if ((node == NULL) || (name == NULL))
5035 return(NULL);
5036
5037 if (ns == NULL)
5038 return(xmlSetProp(node, name, value));
5039 if (ns->href == NULL)
5040 return(NULL);
5041 prop = node->properties;
5042
5043 while (prop != NULL) {
5044 /*
5045 * One need to have
5046 * - same attribute names
5047 * - and the attribute carrying that namespace
5048 * or
5049 * no namespace on the attribute and the element carrying it
5050 */
5051 if ((xmlStrEqual(prop->name, name)) &&
5052 (((prop->ns == NULL) && (node->ns != NULL) &&
5053 (xmlStrEqual(node->ns->href, ns->href))) ||
5054 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5055 if (prop->children != NULL)
5056 xmlFreeNodeList(prop->children);
5057 prop->children = NULL;
5058 prop->last = NULL;
5059 prop->ns = ns;
5060 if (value != NULL) {
5061 xmlChar *buffer;
5062 xmlNodePtr tmp;
5063
5064 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5065 prop->children = xmlStringGetNodeList(node->doc, buffer);
5066 prop->last = NULL;
5067 tmp = prop->children;
5068 while (tmp != NULL) {
5069 tmp->parent = (xmlNodePtr) prop;
5070 if (tmp->next == NULL)
5071 prop->last = tmp;
5072 tmp = tmp->next;
5073 }
5074 xmlFree(buffer);
5075 }
5076 return(prop);
5077 }
5078 prop = prop->next;
5079 }
5080 prop = xmlNewNsProp(node, ns, name, value);
5081 return(prop);
5082}
5083
5084/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005085 * xmlUnsetNsProp:
5086 * @node: the node
5087 * @ns: the namespace definition
5088 * @name: the attribute name
5089 *
5090 * Remove an attribute carried by a node.
5091 * Returns 0 if successful, -1 if not found
5092 */
5093int
5094xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5095 xmlAttrPtr prop = node->properties, prev = NULL;;
5096
5097 if ((node == NULL) || (name == NULL))
5098 return(-1);
5099 if (ns == NULL)
5100 return(xmlUnsetProp(node, name));
5101 if (ns->href == NULL)
5102 return(-1);
5103 while (prop != NULL) {
5104 if ((xmlStrEqual(prop->name, name)) &&
5105 (((prop->ns == NULL) && (node->ns != NULL) &&
5106 (xmlStrEqual(node->ns->href, ns->href))) ||
5107 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5108 if (prev == NULL)
5109 node->properties = prop->next;
5110 else
5111 prev->next = prop->next;
5112 xmlFreeProp(prop);
5113 return(0);
5114 }
5115 prev = prop;
5116 prop = prop->next;
5117 }
5118 return(-1);
5119}
5120
5121/**
Owen Taylor3473f882001-02-23 17:55:21 +00005122 * xmlNodeIsText:
5123 * @node: the node
5124 *
5125 * Is this node a Text node ?
5126 * Returns 1 yes, 0 no
5127 */
5128int
5129xmlNodeIsText(xmlNodePtr node) {
5130 if (node == NULL) return(0);
5131
5132 if (node->type == XML_TEXT_NODE) return(1);
5133 return(0);
5134}
5135
5136/**
5137 * xmlIsBlankNode:
5138 * @node: the node
5139 *
5140 * Checks whether this node is an empty or whitespace only
5141 * (and possibly ignorable) text-node.
5142 *
5143 * Returns 1 yes, 0 no
5144 */
5145int
5146xmlIsBlankNode(xmlNodePtr node) {
5147 const xmlChar *cur;
5148 if (node == NULL) return(0);
5149
Daniel Veillard7db37732001-07-12 01:20:08 +00005150 if ((node->type != XML_TEXT_NODE) &&
5151 (node->type != XML_CDATA_SECTION_NODE))
5152 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005153 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005154 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005155 while (*cur != 0) {
5156 if (!IS_BLANK(*cur)) return(0);
5157 cur++;
5158 }
5159
5160 return(1);
5161}
5162
5163/**
5164 * xmlTextConcat:
5165 * @node: the node
5166 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005167 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005168 *
5169 * Concat the given string at the end of the existing node content
5170 */
5171
5172void
5173xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5174 if (node == NULL) return;
5175
5176 if ((node->type != XML_TEXT_NODE) &&
5177 (node->type != XML_CDATA_SECTION_NODE)) {
5178#ifdef DEBUG_TREE
5179 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005180 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005181#endif
5182 return;
5183 }
Owen Taylor3473f882001-02-23 17:55:21 +00005184 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005185}
5186
5187/************************************************************************
5188 * *
5189 * Output : to a FILE or in memory *
5190 * *
5191 ************************************************************************/
5192
Owen Taylor3473f882001-02-23 17:55:21 +00005193/**
5194 * xmlBufferCreate:
5195 *
5196 * routine to create an XML buffer.
5197 * returns the new structure.
5198 */
5199xmlBufferPtr
5200xmlBufferCreate(void) {
5201 xmlBufferPtr ret;
5202
5203 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5204 if (ret == NULL) {
5205 xmlGenericError(xmlGenericErrorContext,
5206 "xmlBufferCreate : out of memory!\n");
5207 return(NULL);
5208 }
5209 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005210 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005211 ret->alloc = xmlBufferAllocScheme;
5212 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5213 if (ret->content == NULL) {
5214 xmlGenericError(xmlGenericErrorContext,
5215 "xmlBufferCreate : out of memory!\n");
5216 xmlFree(ret);
5217 return(NULL);
5218 }
5219 ret->content[0] = 0;
5220 return(ret);
5221}
5222
5223/**
5224 * xmlBufferCreateSize:
5225 * @size: initial size of buffer
5226 *
5227 * routine to create an XML buffer.
5228 * returns the new structure.
5229 */
5230xmlBufferPtr
5231xmlBufferCreateSize(size_t size) {
5232 xmlBufferPtr ret;
5233
5234 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5235 if (ret == NULL) {
5236 xmlGenericError(xmlGenericErrorContext,
5237 "xmlBufferCreate : out of memory!\n");
5238 return(NULL);
5239 }
5240 ret->use = 0;
5241 ret->alloc = xmlBufferAllocScheme;
5242 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5243 if (ret->size){
5244 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5245 if (ret->content == NULL) {
5246 xmlGenericError(xmlGenericErrorContext,
5247 "xmlBufferCreate : out of memory!\n");
5248 xmlFree(ret);
5249 return(NULL);
5250 }
5251 ret->content[0] = 0;
5252 } else
5253 ret->content = NULL;
5254 return(ret);
5255}
5256
5257/**
5258 * xmlBufferSetAllocationScheme:
5259 * @buf: the buffer to free
5260 * @scheme: allocation scheme to use
5261 *
5262 * Sets the allocation scheme for this buffer
5263 */
5264void
5265xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5266 xmlBufferAllocationScheme scheme) {
5267 if (buf == NULL) {
5268#ifdef DEBUG_BUFFER
5269 xmlGenericError(xmlGenericErrorContext,
5270 "xmlBufferSetAllocationScheme: buf == NULL\n");
5271#endif
5272 return;
5273 }
5274
5275 buf->alloc = scheme;
5276}
5277
5278/**
5279 * xmlBufferFree:
5280 * @buf: the buffer to free
5281 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005282 * Frees an XML buffer. It frees both the content and the structure which
5283 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005284 */
5285void
5286xmlBufferFree(xmlBufferPtr buf) {
5287 if (buf == NULL) {
5288#ifdef DEBUG_BUFFER
5289 xmlGenericError(xmlGenericErrorContext,
5290 "xmlBufferFree: buf == NULL\n");
5291#endif
5292 return;
5293 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005294 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005295 xmlFree(buf->content);
5296 }
Owen Taylor3473f882001-02-23 17:55:21 +00005297 xmlFree(buf);
5298}
5299
5300/**
5301 * xmlBufferEmpty:
5302 * @buf: the buffer
5303 *
5304 * empty a buffer.
5305 */
5306void
5307xmlBufferEmpty(xmlBufferPtr buf) {
5308 if (buf->content == NULL) return;
5309 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005310 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005311}
5312
5313/**
5314 * xmlBufferShrink:
5315 * @buf: the buffer to dump
5316 * @len: the number of xmlChar to remove
5317 *
5318 * Remove the beginning of an XML buffer.
5319 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005320 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005321 */
5322int
5323xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5324 if (len == 0) return(0);
5325 if (len > buf->use) return(-1);
5326
5327 buf->use -= len;
5328 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5329
5330 buf->content[buf->use] = 0;
5331 return(len);
5332}
5333
5334/**
5335 * xmlBufferGrow:
5336 * @buf: the buffer
5337 * @len: the minimum free size to allocate
5338 *
5339 * Grow the available space of an XML buffer.
5340 *
5341 * Returns the new available space or -1 in case of error
5342 */
5343int
5344xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5345 int size;
5346 xmlChar *newbuf;
5347
5348 if (len + buf->use < buf->size) return(0);
5349
5350 size = buf->use + len + 100;
5351
5352 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5353 if (newbuf == NULL) return(-1);
5354 buf->content = newbuf;
5355 buf->size = size;
5356 return(buf->size - buf->use);
5357}
5358
5359/**
5360 * xmlBufferDump:
5361 * @file: the file output
5362 * @buf: the buffer to dump
5363 *
5364 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005365 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005366 */
5367int
5368xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5369 int ret;
5370
5371 if (buf == NULL) {
5372#ifdef DEBUG_BUFFER
5373 xmlGenericError(xmlGenericErrorContext,
5374 "xmlBufferDump: buf == NULL\n");
5375#endif
5376 return(0);
5377 }
5378 if (buf->content == NULL) {
5379#ifdef DEBUG_BUFFER
5380 xmlGenericError(xmlGenericErrorContext,
5381 "xmlBufferDump: buf->content == NULL\n");
5382#endif
5383 return(0);
5384 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005385 if (file == NULL)
5386 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005387 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5388 return(ret);
5389}
5390
5391/**
5392 * xmlBufferContent:
5393 * @buf: the buffer
5394 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005395 * Function to extract the content of a buffer
5396 *
Owen Taylor3473f882001-02-23 17:55:21 +00005397 * Returns the internal content
5398 */
5399
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005400const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005401xmlBufferContent(const xmlBufferPtr buf)
5402{
5403 if(!buf)
5404 return NULL;
5405
5406 return buf->content;
5407}
5408
5409/**
5410 * xmlBufferLength:
5411 * @buf: the buffer
5412 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005413 * Function to get the length of a buffer
5414 *
Owen Taylor3473f882001-02-23 17:55:21 +00005415 * Returns the length of data in the internal content
5416 */
5417
5418int
5419xmlBufferLength(const xmlBufferPtr buf)
5420{
5421 if(!buf)
5422 return 0;
5423
5424 return buf->use;
5425}
5426
5427/**
5428 * xmlBufferResize:
5429 * @buf: the buffer to resize
5430 * @size: the desired size
5431 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005432 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005433 *
5434 * Returns 0 in case of problems, 1 otherwise
5435 */
5436int
5437xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5438{
5439 unsigned int newSize;
5440 xmlChar* rebuf = NULL;
5441
5442 /*take care of empty case*/
5443 newSize = (buf->size ? buf->size*2 : size);
5444
5445 /* Don't resize if we don't have to */
5446 if (size < buf->size)
5447 return 1;
5448
5449 /* figure out new size */
5450 switch (buf->alloc){
5451 case XML_BUFFER_ALLOC_DOUBLEIT:
5452 while (size > newSize) newSize *= 2;
5453 break;
5454 case XML_BUFFER_ALLOC_EXACT:
5455 newSize = size+10;
5456 break;
5457 default:
5458 newSize = size+10;
5459 break;
5460 }
5461
5462 if (buf->content == NULL)
5463 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5464 else
5465 rebuf = (xmlChar *) xmlRealloc(buf->content,
5466 newSize * sizeof(xmlChar));
5467 if (rebuf == NULL) {
5468 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005469 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005470 return 0;
5471 }
5472 buf->content = rebuf;
5473 buf->size = newSize;
5474
5475 return 1;
5476}
5477
5478/**
5479 * xmlBufferAdd:
5480 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005481 * @str: the #xmlChar string
5482 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005483 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005484 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005485 * str is recomputed.
5486 */
5487void
5488xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5489 unsigned int needSize;
5490
5491 if (str == NULL) {
5492#ifdef DEBUG_BUFFER
5493 xmlGenericError(xmlGenericErrorContext,
5494 "xmlBufferAdd: str == NULL\n");
5495#endif
5496 return;
5497 }
5498 if (len < -1) {
5499#ifdef DEBUG_BUFFER
5500 xmlGenericError(xmlGenericErrorContext,
5501 "xmlBufferAdd: len < 0\n");
5502#endif
5503 return;
5504 }
5505 if (len == 0) return;
5506
5507 if (len < 0)
5508 len = xmlStrlen(str);
5509
5510 if (len <= 0) return;
5511
5512 needSize = buf->use + len + 2;
5513 if (needSize > buf->size){
5514 if (!xmlBufferResize(buf, needSize)){
5515 xmlGenericError(xmlGenericErrorContext,
5516 "xmlBufferAdd : out of memory!\n");
5517 return;
5518 }
5519 }
5520
5521 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5522 buf->use += len;
5523 buf->content[buf->use] = 0;
5524}
5525
5526/**
5527 * xmlBufferAddHead:
5528 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005529 * @str: the #xmlChar string
5530 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005531 *
5532 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005533 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005534 */
5535void
5536xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5537 unsigned int needSize;
5538
5539 if (str == NULL) {
5540#ifdef DEBUG_BUFFER
5541 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005542 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005543#endif
5544 return;
5545 }
5546 if (len < -1) {
5547#ifdef DEBUG_BUFFER
5548 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005549 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005550#endif
5551 return;
5552 }
5553 if (len == 0) return;
5554
5555 if (len < 0)
5556 len = xmlStrlen(str);
5557
5558 if (len <= 0) return;
5559
5560 needSize = buf->use + len + 2;
5561 if (needSize > buf->size){
5562 if (!xmlBufferResize(buf, needSize)){
5563 xmlGenericError(xmlGenericErrorContext,
5564 "xmlBufferAddHead : out of memory!\n");
5565 return;
5566 }
5567 }
5568
5569 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5570 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5571 buf->use += len;
5572 buf->content[buf->use] = 0;
5573}
5574
5575/**
5576 * xmlBufferCat:
5577 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005578 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005579 *
5580 * Append a zero terminated string to an XML buffer.
5581 */
5582void
5583xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5584 if (str != NULL)
5585 xmlBufferAdd(buf, str, -1);
5586}
5587
5588/**
5589 * xmlBufferCCat:
5590 * @buf: the buffer to dump
5591 * @str: the C char string
5592 *
5593 * Append a zero terminated C string to an XML buffer.
5594 */
5595void
5596xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5597 const char *cur;
5598
5599 if (str == NULL) {
5600#ifdef DEBUG_BUFFER
5601 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005602 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005603#endif
5604 return;
5605 }
5606 for (cur = str;*cur != 0;cur++) {
5607 if (buf->use + 10 >= buf->size) {
5608 if (!xmlBufferResize(buf, buf->use+10)){
5609 xmlGenericError(xmlGenericErrorContext,
5610 "xmlBufferCCat : out of memory!\n");
5611 return;
5612 }
5613 }
5614 buf->content[buf->use++] = *cur;
5615 }
5616 buf->content[buf->use] = 0;
5617}
5618
5619/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005620 * xmlBufferWriteXmlCHAR:
5621 * @buf: the XML buffer
5622 * @string: the string to add
5623 *
5624 * For VMS only.
5625 * routine which manages and grows an output buffer. This one adds
5626 * xmlChars at the end of the buffer.
5627 */
5628/**
Owen Taylor3473f882001-02-23 17:55:21 +00005629 * xmlBufferWriteCHAR:
5630 * @buf: the XML buffer
5631 * @string: the string to add
5632 *
5633 * routine which manages and grows an output buffer. This one adds
5634 * xmlChars at the end of the buffer.
5635 */
5636void
5637#ifdef VMS
5638xmlBufferWriteXmlCHAR
5639#else
5640xmlBufferWriteCHAR
5641#endif
5642(xmlBufferPtr buf, const xmlChar *string) {
5643 xmlBufferCat(buf, string);
5644}
5645
5646/**
5647 * xmlBufferWriteChar:
5648 * @buf: the XML buffer output
5649 * @string: the string to add
5650 *
5651 * routine which manage and grows an output buffer. This one add
5652 * C chars at the end of the array.
5653 */
5654void
5655xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5656 xmlBufferCCat(buf, string);
5657}
5658
5659
5660/**
5661 * xmlBufferWriteQuotedString:
5662 * @buf: the XML buffer output
5663 * @string: the string to add
5664 *
5665 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005666 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005667 * quote or double-quotes internally
5668 */
5669void
5670xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5671 if (xmlStrchr(string, '"')) {
5672 if (xmlStrchr(string, '\'')) {
5673#ifdef DEBUG_BUFFER
5674 xmlGenericError(xmlGenericErrorContext,
5675 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5676#endif
5677 }
5678 xmlBufferCCat(buf, "'");
5679 xmlBufferCat(buf, string);
5680 xmlBufferCCat(buf, "'");
5681 } else {
5682 xmlBufferCCat(buf, "\"");
5683 xmlBufferCat(buf, string);
5684 xmlBufferCCat(buf, "\"");
5685 }
5686}
5687
5688
5689/************************************************************************
5690 * *
5691 * Dumping XML tree content to a simple buffer *
5692 * *
5693 ************************************************************************/
5694
Owen Taylor3473f882001-02-23 17:55:21 +00005695static void
5696xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5697 int format);
5698void
5699htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5700
5701/**
5702 * xmlNsDump:
5703 * @buf: the XML buffer output
5704 * @cur: a namespace
5705 *
5706 * Dump a local Namespace definition.
5707 * Should be called in the context of attributes dumps.
5708 */
5709static void
5710xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5711 if (cur == NULL) {
5712#ifdef DEBUG_TREE
5713 xmlGenericError(xmlGenericErrorContext,
5714 "xmlNsDump : Ns == NULL\n");
5715#endif
5716 return;
5717 }
5718 if (cur->type == XML_LOCAL_NAMESPACE) {
5719 /* Within the context of an element attributes */
5720 if (cur->prefix != NULL) {
5721 xmlBufferWriteChar(buf, " xmlns:");
5722 xmlBufferWriteCHAR(buf, cur->prefix);
5723 } else
5724 xmlBufferWriteChar(buf, " xmlns");
5725 xmlBufferWriteChar(buf, "=");
5726 xmlBufferWriteQuotedString(buf, cur->href);
5727 }
5728}
5729
5730/**
5731 * xmlNsListDump:
5732 * @buf: the XML buffer output
5733 * @cur: the first namespace
5734 *
5735 * Dump a list of local Namespace definitions.
5736 * Should be called in the context of attributes dumps.
5737 */
5738static void
5739xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5740 while (cur != NULL) {
5741 xmlNsDump(buf, cur);
5742 cur = cur->next;
5743 }
5744}
5745
5746/**
5747 * xmlDtdDump:
5748 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005749 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005750 *
5751 * Dump the XML document DTD, if any.
5752 */
5753static void
5754xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5755 if (dtd == NULL) {
5756#ifdef DEBUG_TREE
5757 xmlGenericError(xmlGenericErrorContext,
5758 "xmlDtdDump : no internal subset\n");
5759#endif
5760 return;
5761 }
5762 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5763 xmlBufferWriteCHAR(buf, dtd->name);
5764 if (dtd->ExternalID != NULL) {
5765 xmlBufferWriteChar(buf, " PUBLIC ");
5766 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5767 xmlBufferWriteChar(buf, " ");
5768 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5769 } else if (dtd->SystemID != NULL) {
5770 xmlBufferWriteChar(buf, " SYSTEM ");
5771 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5772 }
5773 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5774 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5775 xmlBufferWriteChar(buf, ">");
5776 return;
5777 }
5778 xmlBufferWriteChar(buf, " [\n");
5779 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5780#if 0
5781 if (dtd->entities != NULL)
5782 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5783 if (dtd->notations != NULL)
5784 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5785 if (dtd->elements != NULL)
5786 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5787 if (dtd->attributes != NULL)
5788 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5789#endif
5790 xmlBufferWriteChar(buf, "]>");
5791}
5792
5793/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005794 * xmlAttrSerializeContent:
5795 * @buf: the XML buffer output
5796 * @doc: the document
5797 * @attr: the attribute pointer
5798 *
5799 * Serialize the attribute in the buffer
5800 */
5801static void
5802xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5803 const xmlChar *cur, *base;
5804 xmlNodePtr children;
5805
5806 children = attr->children;
5807 while (children != NULL) {
5808 switch (children->type) {
5809 case XML_TEXT_NODE:
5810 base = cur = children->content;
5811 while (*cur != 0) {
5812 if (*cur == '\n') {
5813 if (base != cur)
5814 xmlBufferAdd(buf, base, cur - base);
5815 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5816 cur++;
5817 base = cur;
5818#if 0
5819 } else if (*cur == '\'') {
5820 if (base != cur)
5821 xmlBufferAdd(buf, base, cur - base);
5822 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5823 cur++;
5824 base = cur;
5825#endif
5826 } else if (*cur == '"') {
5827 if (base != cur)
5828 xmlBufferAdd(buf, base, cur - base);
5829 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5830 cur++;
5831 base = cur;
5832 } else if (*cur == '<') {
5833 if (base != cur)
5834 xmlBufferAdd(buf, base, cur - base);
5835 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
5836 cur++;
5837 base = cur;
5838 } else if (*cur == '>') {
5839 if (base != cur)
5840 xmlBufferAdd(buf, base, cur - base);
5841 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
5842 cur++;
5843 base = cur;
5844 } else if (*cur == '&') {
5845 if (base != cur)
5846 xmlBufferAdd(buf, base, cur - base);
5847 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
5848 cur++;
5849 base = cur;
5850 } else if ((*cur >= 0x80) && ((doc == NULL) ||
5851 (doc->encoding == NULL))) {
5852 /*
5853 * We assume we have UTF-8 content.
5854 */
5855 char tmp[10];
5856 int val = 0, l = 1;
5857
5858 if (base != cur)
5859 xmlBufferAdd(buf, base, cur - base);
5860 if (*cur < 0xC0) {
5861 xmlGenericError(xmlGenericErrorContext,
5862 "xmlAttrSerializeContent : input not UTF-8\n");
5863 if (doc != NULL)
5864 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5865 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5866 tmp[sizeof(tmp) - 1] = 0;
5867 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5868 cur++;
5869 base = cur;
5870 continue;
5871 } else if (*cur < 0xE0) {
5872 val = (cur[0]) & 0x1F;
5873 val <<= 6;
5874 val |= (cur[1]) & 0x3F;
5875 l = 2;
5876 } else if (*cur < 0xF0) {
5877 val = (cur[0]) & 0x0F;
5878 val <<= 6;
5879 val |= (cur[1]) & 0x3F;
5880 val <<= 6;
5881 val |= (cur[2]) & 0x3F;
5882 l = 3;
5883 } else if (*cur < 0xF8) {
5884 val = (cur[0]) & 0x07;
5885 val <<= 6;
5886 val |= (cur[1]) & 0x3F;
5887 val <<= 6;
5888 val |= (cur[2]) & 0x3F;
5889 val <<= 6;
5890 val |= (cur[3]) & 0x3F;
5891 l = 4;
5892 }
5893 if ((l == 1) || (!IS_CHAR(val))) {
5894 xmlGenericError(xmlGenericErrorContext,
5895 "xmlAttrSerializeContent : char out of range\n");
5896 if (doc != NULL)
5897 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5898 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5899 tmp[sizeof(tmp) - 1] = 0;
5900 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5901 cur++;
5902 base = cur;
5903 continue;
5904 }
5905 /*
5906 * We could do multiple things here. Just save
5907 * as a char ref
5908 */
5909 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
5910 tmp[sizeof(tmp) - 1] = 0;
5911 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5912 cur += l;
5913 base = cur;
5914 } else {
5915 cur++;
5916 }
5917 }
5918 if (base != cur)
5919 xmlBufferAdd(buf, base, cur - base);
5920 break;
5921 case XML_ENTITY_REF_NODE:
5922 xmlBufferAdd(buf, BAD_CAST "&", 1);
5923 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
5924 xmlBufferAdd(buf, BAD_CAST ";", 1);
5925 break;
5926 default:
5927 /* should not happen unless we have a badly built tree */
5928 break;
5929 }
5930 children = children->next;
5931 }
5932}
5933
5934/**
Owen Taylor3473f882001-02-23 17:55:21 +00005935 * xmlAttrDump:
5936 * @buf: the XML buffer output
5937 * @doc: the document
5938 * @cur: the attribute pointer
5939 *
5940 * Dump an XML attribute
5941 */
5942static void
5943xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00005944 if (cur == NULL) {
5945#ifdef DEBUG_TREE
5946 xmlGenericError(xmlGenericErrorContext,
5947 "xmlAttrDump : property == NULL\n");
5948#endif
5949 return;
5950 }
5951 xmlBufferWriteChar(buf, " ");
5952 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5953 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5954 xmlBufferWriteChar(buf, ":");
5955 }
5956 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00005957 xmlBufferWriteChar(buf, "=\"");
5958 xmlAttrSerializeContent(buf, doc, cur);
5959 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00005960}
5961
5962/**
5963 * xmlAttrListDump:
5964 * @buf: the XML buffer output
5965 * @doc: the document
5966 * @cur: the first attribute pointer
5967 *
5968 * Dump a list of XML attributes
5969 */
5970static void
5971xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5972 if (cur == NULL) {
5973#ifdef DEBUG_TREE
5974 xmlGenericError(xmlGenericErrorContext,
5975 "xmlAttrListDump : property == NULL\n");
5976#endif
5977 return;
5978 }
5979 while (cur != NULL) {
5980 xmlAttrDump(buf, doc, cur);
5981 cur = cur->next;
5982 }
5983}
5984
5985
5986
5987/**
5988 * xmlNodeListDump:
5989 * @buf: the XML buffer output
5990 * @doc: the document
5991 * @cur: the first node
5992 * @level: the imbrication level for indenting
5993 * @format: is formatting allowed
5994 *
5995 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005996 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
5997 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00005998 */
5999static void
6000xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6001 int format) {
6002 int i;
6003
6004 if (cur == NULL) {
6005#ifdef DEBUG_TREE
6006 xmlGenericError(xmlGenericErrorContext,
6007 "xmlNodeListDump : node == NULL\n");
6008#endif
6009 return;
6010 }
6011 while (cur != NULL) {
6012 if ((format) && (xmlIndentTreeOutput) &&
6013 (cur->type == XML_ELEMENT_NODE))
6014 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006015 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006016 xmlNodeDump(buf, doc, cur, level, format);
6017 if (format) {
6018 xmlBufferWriteChar(buf, "\n");
6019 }
6020 cur = cur->next;
6021 }
6022}
6023
6024/**
6025 * xmlNodeDump:
6026 * @buf: the XML buffer output
6027 * @doc: the document
6028 * @cur: the current node
6029 * @level: the imbrication level for indenting
6030 * @format: is formatting allowed
6031 *
6032 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006033 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6034 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006035 */
6036void
6037xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6038 int format) {
6039 int i;
6040 xmlNodePtr tmp;
6041
6042 if (cur == NULL) {
6043#ifdef DEBUG_TREE
6044 xmlGenericError(xmlGenericErrorContext,
6045 "xmlNodeDump : node == NULL\n");
6046#endif
6047 return;
6048 }
6049 if (cur->type == XML_XINCLUDE_START)
6050 return;
6051 if (cur->type == XML_XINCLUDE_END)
6052 return;
6053 if (cur->type == XML_DTD_NODE) {
6054 xmlDtdDump(buf, (xmlDtdPtr) cur);
6055 return;
6056 }
6057 if (cur->type == XML_ELEMENT_DECL) {
6058 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6059 return;
6060 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006061 if (cur->type == XML_ATTRIBUTE_NODE){
6062 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6063 return;
6064 }
Owen Taylor3473f882001-02-23 17:55:21 +00006065 if (cur->type == XML_ATTRIBUTE_DECL) {
6066 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6067 return;
6068 }
6069 if (cur->type == XML_ENTITY_DECL) {
6070 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6071 return;
6072 }
6073 if (cur->type == XML_TEXT_NODE) {
6074 if (cur->content != NULL) {
6075 if ((cur->name == xmlStringText) ||
6076 (cur->name != xmlStringTextNoenc)) {
6077 xmlChar *buffer;
6078
Owen Taylor3473f882001-02-23 17:55:21 +00006079 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006080 if (buffer != NULL) {
6081 xmlBufferWriteCHAR(buf, buffer);
6082 xmlFree(buffer);
6083 }
6084 } else {
6085 /*
6086 * Disable escaping, needed for XSLT
6087 */
Owen Taylor3473f882001-02-23 17:55:21 +00006088 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006089 }
6090 }
6091 return;
6092 }
6093 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006094 xmlBufferWriteChar(buf, "<?");
6095 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006096 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006097 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006098 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006099 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006100 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006101 return;
6102 }
6103 if (cur->type == XML_COMMENT_NODE) {
6104 if (cur->content != NULL) {
6105 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006106 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006107 xmlBufferWriteChar(buf, "-->");
6108 }
6109 return;
6110 }
6111 if (cur->type == XML_ENTITY_REF_NODE) {
6112 xmlBufferWriteChar(buf, "&");
6113 xmlBufferWriteCHAR(buf, cur->name);
6114 xmlBufferWriteChar(buf, ";");
6115 return;
6116 }
6117 if (cur->type == XML_CDATA_SECTION_NODE) {
6118 xmlBufferWriteChar(buf, "<![CDATA[");
6119 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006120 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006121 xmlBufferWriteChar(buf, "]]>");
6122 return;
6123 }
6124
6125 if (format == 1) {
6126 tmp = cur->children;
6127 while (tmp != NULL) {
6128 if ((tmp->type == XML_TEXT_NODE) ||
6129 (tmp->type == XML_ENTITY_REF_NODE)) {
6130 format = 0;
6131 break;
6132 }
6133 tmp = tmp->next;
6134 }
6135 }
6136 xmlBufferWriteChar(buf, "<");
6137 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6138 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6139 xmlBufferWriteChar(buf, ":");
6140 }
6141
6142 xmlBufferWriteCHAR(buf, cur->name);
6143 if (cur->nsDef)
6144 xmlNsListDump(buf, cur->nsDef);
6145 if (cur->properties != NULL)
6146 xmlAttrListDump(buf, doc, cur->properties);
6147
Daniel Veillard7db37732001-07-12 01:20:08 +00006148 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6149 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006150 (!xmlSaveNoEmptyTags)) {
6151 xmlBufferWriteChar(buf, "/>");
6152 return;
6153 }
6154 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006155 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006156 xmlChar *buffer;
6157
Owen Taylor3473f882001-02-23 17:55:21 +00006158 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006159 if (buffer != NULL) {
6160 xmlBufferWriteCHAR(buf, buffer);
6161 xmlFree(buffer);
6162 }
6163 }
6164 if (cur->children != NULL) {
6165 if (format) xmlBufferWriteChar(buf, "\n");
6166 xmlNodeListDump(buf, doc, cur->children,
6167 (level >= 0?level+1:-1), format);
6168 if ((xmlIndentTreeOutput) && (format))
6169 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006170 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006171 }
6172 xmlBufferWriteChar(buf, "</");
6173 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6174 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6175 xmlBufferWriteChar(buf, ":");
6176 }
6177
6178 xmlBufferWriteCHAR(buf, cur->name);
6179 xmlBufferWriteChar(buf, ">");
6180}
6181
6182/**
6183 * xmlElemDump:
6184 * @f: the FILE * for the output
6185 * @doc: the document
6186 * @cur: the current node
6187 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006188 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006189 */
6190void
6191xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6192 xmlBufferPtr buf;
6193
6194 if (cur == NULL) {
6195#ifdef DEBUG_TREE
6196 xmlGenericError(xmlGenericErrorContext,
6197 "xmlElemDump : cur == NULL\n");
6198#endif
6199 return;
6200 }
Owen Taylor3473f882001-02-23 17:55:21 +00006201#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006202 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006203 xmlGenericError(xmlGenericErrorContext,
6204 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006205 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006206#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006207
Owen Taylor3473f882001-02-23 17:55:21 +00006208 buf = xmlBufferCreate();
6209 if (buf == NULL) return;
6210 if ((doc != NULL) &&
6211 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6212#ifdef LIBXML_HTML_ENABLED
6213 htmlNodeDump(buf, doc, cur);
6214#else
6215 xmlGenericError(xmlGenericErrorContext,
6216 "HTML support not compiled in\n");
6217#endif /* LIBXML_HTML_ENABLED */
6218 } else
6219 xmlNodeDump(buf, doc, cur, 0, 1);
6220 xmlBufferDump(f, buf);
6221 xmlBufferFree(buf);
6222}
6223
6224/************************************************************************
6225 * *
6226 * Dumping XML tree content to an I/O output buffer *
6227 * *
6228 ************************************************************************/
6229
Owen Taylor3473f882001-02-23 17:55:21 +00006230static void
6231xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6232 int level, int format, const char *encoding);
6233/**
6234 * xmlNsDumpOutput:
6235 * @buf: the XML buffer output
6236 * @cur: a namespace
6237 *
6238 * Dump a local Namespace definition.
6239 * Should be called in the context of attributes dumps.
6240 */
6241static void
6242xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6243 if (cur == NULL) {
6244#ifdef DEBUG_TREE
6245 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006246 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006247#endif
6248 return;
6249 }
6250 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6251 /* Within the context of an element attributes */
6252 if (cur->prefix != NULL) {
6253 xmlOutputBufferWriteString(buf, " xmlns:");
6254 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6255 } else
6256 xmlOutputBufferWriteString(buf, " xmlns");
6257 xmlOutputBufferWriteString(buf, "=");
6258 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6259 }
6260}
6261
6262/**
6263 * xmlNsListDumpOutput:
6264 * @buf: the XML buffer output
6265 * @cur: the first namespace
6266 *
6267 * Dump a list of local Namespace definitions.
6268 * Should be called in the context of attributes dumps.
6269 */
6270static void
6271xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6272 while (cur != NULL) {
6273 xmlNsDumpOutput(buf, cur);
6274 cur = cur->next;
6275 }
6276}
6277
6278/**
6279 * xmlDtdDumpOutput:
6280 * @buf: the XML buffer output
6281 * @doc: the document
6282 * @encoding: an optional encoding string
6283 *
6284 * Dump the XML document DTD, if any.
6285 */
6286static void
6287xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6288 if (dtd == NULL) {
6289#ifdef DEBUG_TREE
6290 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006291 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006292#endif
6293 return;
6294 }
6295 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6296 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6297 if (dtd->ExternalID != NULL) {
6298 xmlOutputBufferWriteString(buf, " PUBLIC ");
6299 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6300 xmlOutputBufferWriteString(buf, " ");
6301 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6302 } else if (dtd->SystemID != NULL) {
6303 xmlOutputBufferWriteString(buf, " SYSTEM ");
6304 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6305 }
6306 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6307 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6308 xmlOutputBufferWriteString(buf, ">");
6309 return;
6310 }
6311 xmlOutputBufferWriteString(buf, " [\n");
6312 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6313 xmlOutputBufferWriteString(buf, "]>");
6314}
6315
6316/**
6317 * xmlAttrDumpOutput:
6318 * @buf: the XML buffer output
6319 * @doc: the document
6320 * @cur: the attribute pointer
6321 * @encoding: an optional encoding string
6322 *
6323 * Dump an XML attribute
6324 */
6325static void
6326xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006327 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006328 if (cur == NULL) {
6329#ifdef DEBUG_TREE
6330 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006331 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006332#endif
6333 return;
6334 }
6335 xmlOutputBufferWriteString(buf, " ");
6336 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6337 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6338 xmlOutputBufferWriteString(buf, ":");
6339 }
6340 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006341 xmlOutputBufferWriteString(buf, "=\"");
6342 xmlAttrSerializeContent(buf->buffer, doc, cur);
6343 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006344}
6345
6346/**
6347 * xmlAttrListDumpOutput:
6348 * @buf: the XML buffer output
6349 * @doc: the document
6350 * @cur: the first attribute pointer
6351 * @encoding: an optional encoding string
6352 *
6353 * Dump a list of XML attributes
6354 */
6355static void
6356xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6357 xmlAttrPtr cur, const char *encoding) {
6358 if (cur == NULL) {
6359#ifdef DEBUG_TREE
6360 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006361 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006362#endif
6363 return;
6364 }
6365 while (cur != NULL) {
6366 xmlAttrDumpOutput(buf, doc, cur, encoding);
6367 cur = cur->next;
6368 }
6369}
6370
6371
6372
6373/**
6374 * xmlNodeListDumpOutput:
6375 * @buf: the XML buffer output
6376 * @doc: the document
6377 * @cur: the first node
6378 * @level: the imbrication level for indenting
6379 * @format: is formatting allowed
6380 * @encoding: an optional encoding string
6381 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006382 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006383 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6384 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006385 */
6386static void
6387xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6388 xmlNodePtr cur, int level, int format, const char *encoding) {
6389 int i;
6390
6391 if (cur == NULL) {
6392#ifdef DEBUG_TREE
6393 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006394 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006395#endif
6396 return;
6397 }
6398 while (cur != NULL) {
6399 if ((format) && (xmlIndentTreeOutput) &&
6400 (cur->type == XML_ELEMENT_NODE))
6401 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006402 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006403 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6404 if (format) {
6405 xmlOutputBufferWriteString(buf, "\n");
6406 }
6407 cur = cur->next;
6408 }
6409}
6410
6411/**
6412 * xmlNodeDumpOutput:
6413 * @buf: the XML buffer output
6414 * @doc: the document
6415 * @cur: the current node
6416 * @level: the imbrication level for indenting
6417 * @format: is formatting allowed
6418 * @encoding: an optional encoding string
6419 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006420 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006421 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6422 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006423 */
6424void
6425xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6426 int level, int format, const char *encoding) {
6427 int i;
6428 xmlNodePtr tmp;
6429
6430 if (cur == NULL) {
6431#ifdef DEBUG_TREE
6432 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006433 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006434#endif
6435 return;
6436 }
6437 if (cur->type == XML_XINCLUDE_START)
6438 return;
6439 if (cur->type == XML_XINCLUDE_END)
6440 return;
6441 if (cur->type == XML_DTD_NODE) {
6442 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6443 return;
6444 }
6445 if (cur->type == XML_ELEMENT_DECL) {
6446 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6447 return;
6448 }
6449 if (cur->type == XML_ATTRIBUTE_DECL) {
6450 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6451 return;
6452 }
6453 if (cur->type == XML_ENTITY_DECL) {
6454 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6455 return;
6456 }
6457 if (cur->type == XML_TEXT_NODE) {
6458 if (cur->content != NULL) {
6459 if ((cur->name == xmlStringText) ||
6460 (cur->name != xmlStringTextNoenc)) {
6461 xmlChar *buffer;
6462
Owen Taylor3473f882001-02-23 17:55:21 +00006463 if (encoding == NULL)
6464 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6465 else
6466 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006467 if (buffer != NULL) {
6468 xmlOutputBufferWriteString(buf, (const char *)buffer);
6469 xmlFree(buffer);
6470 }
6471 } else {
6472 /*
6473 * Disable escaping, needed for XSLT
6474 */
Owen Taylor3473f882001-02-23 17:55:21 +00006475 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006476 }
6477 }
6478
6479 return;
6480 }
6481 if (cur->type == XML_PI_NODE) {
6482 if (cur->content != NULL) {
6483 xmlOutputBufferWriteString(buf, "<?");
6484 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6485 if (cur->content != NULL) {
6486 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006487 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006488 }
6489 xmlOutputBufferWriteString(buf, "?>");
6490 } else {
6491 xmlOutputBufferWriteString(buf, "<?");
6492 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6493 xmlOutputBufferWriteString(buf, "?>");
6494 }
6495 return;
6496 }
6497 if (cur->type == XML_COMMENT_NODE) {
6498 if (cur->content != NULL) {
6499 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006500 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006501 xmlOutputBufferWriteString(buf, "-->");
6502 }
6503 return;
6504 }
6505 if (cur->type == XML_ENTITY_REF_NODE) {
6506 xmlOutputBufferWriteString(buf, "&");
6507 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6508 xmlOutputBufferWriteString(buf, ";");
6509 return;
6510 }
6511 if (cur->type == XML_CDATA_SECTION_NODE) {
6512 xmlOutputBufferWriteString(buf, "<![CDATA[");
6513 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006514 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006515 xmlOutputBufferWriteString(buf, "]]>");
6516 return;
6517 }
6518
6519 if (format == 1) {
6520 tmp = cur->children;
6521 while (tmp != NULL) {
6522 if ((tmp->type == XML_TEXT_NODE) ||
6523 (tmp->type == XML_ENTITY_REF_NODE)) {
6524 format = 0;
6525 break;
6526 }
6527 tmp = tmp->next;
6528 }
6529 }
6530 xmlOutputBufferWriteString(buf, "<");
6531 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6532 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6533 xmlOutputBufferWriteString(buf, ":");
6534 }
6535
6536 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6537 if (cur->nsDef)
6538 xmlNsListDumpOutput(buf, cur->nsDef);
6539 if (cur->properties != NULL)
6540 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6541
Daniel Veillard7db37732001-07-12 01:20:08 +00006542 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6543 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006544 xmlOutputBufferWriteString(buf, "/>");
6545 return;
6546 }
6547 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006548 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006549 xmlChar *buffer;
6550
Owen Taylor3473f882001-02-23 17:55:21 +00006551 if (encoding == NULL)
6552 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6553 else
6554 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006555 if (buffer != NULL) {
6556 xmlOutputBufferWriteString(buf, (const char *)buffer);
6557 xmlFree(buffer);
6558 }
6559 }
6560 if (cur->children != NULL) {
6561 if (format) xmlOutputBufferWriteString(buf, "\n");
6562 xmlNodeListDumpOutput(buf, doc, cur->children,
6563 (level >= 0?level+1:-1), format, encoding);
6564 if ((xmlIndentTreeOutput) && (format))
6565 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006566 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006567 }
6568 xmlOutputBufferWriteString(buf, "</");
6569 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6570 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6571 xmlOutputBufferWriteString(buf, ":");
6572 }
6573
6574 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6575 xmlOutputBufferWriteString(buf, ">");
6576}
6577
6578/**
6579 * xmlDocContentDumpOutput:
6580 * @buf: the XML buffer output
6581 * @cur: the document
6582 * @encoding: an optional encoding string
6583 * @format: should formatting spaces been added
6584 *
6585 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006586 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6587 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006588 */
6589static void
6590xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6591 const char *encoding, int format) {
6592 xmlOutputBufferWriteString(buf, "<?xml version=");
6593 if (cur->version != NULL)
6594 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6595 else
6596 xmlOutputBufferWriteString(buf, "\"1.0\"");
6597 if (encoding == NULL) {
6598 if (cur->encoding != NULL)
6599 encoding = (const char *) cur->encoding;
6600 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6601 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6602 }
6603 if (encoding != NULL) {
6604 xmlOutputBufferWriteString(buf, " encoding=");
6605 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6606 }
6607 switch (cur->standalone) {
6608 case 0:
6609 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6610 break;
6611 case 1:
6612 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6613 break;
6614 }
6615 xmlOutputBufferWriteString(buf, "?>\n");
6616 if (cur->children != NULL) {
6617 xmlNodePtr child = cur->children;
6618
6619 while (child != NULL) {
6620 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6621 xmlOutputBufferWriteString(buf, "\n");
6622 child = child->next;
6623 }
6624 }
6625}
6626
6627/************************************************************************
6628 * *
6629 * Saving functions front-ends *
6630 * *
6631 ************************************************************************/
6632
6633/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006634 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006635 * @out_doc: Document to generate XML text from
6636 * @doc_txt_ptr: Memory pointer for allocated XML text
6637 * @doc_txt_len: Length of the generated XML text
6638 * @txt_encoding: Character encoding to use when generating XML text
6639 * @format: should formatting spaces been added
6640 *
6641 * Dump the current DOM tree into memory using the character encoding specified
6642 * by the caller. Note it is up to the caller of this function to free the
6643 * allocated memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006644 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6645 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006646 */
6647
6648void
6649xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006650 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006651 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006652 int dummy = 0;
6653
6654 xmlCharEncoding doc_charset;
6655 xmlOutputBufferPtr out_buff = NULL;
6656 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6657
6658 if (doc_txt_len == NULL) {
6659 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6660 }
6661
6662 if (doc_txt_ptr == NULL) {
6663 *doc_txt_len = 0;
6664 xmlGenericError(xmlGenericErrorContext,
6665 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6666 return;
6667 }
6668
6669 *doc_txt_ptr = NULL;
6670 *doc_txt_len = 0;
6671
6672 if (out_doc == NULL) {
6673 /* No document, no output */
6674 xmlGenericError(xmlGenericErrorContext,
6675 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6676 return;
6677 }
6678
6679 /*
6680 * Validate the encoding value, if provided.
6681 * This logic is copied from xmlSaveFileEnc.
6682 */
6683
6684 if (txt_encoding == NULL)
6685 txt_encoding = (const char *) out_doc->encoding;
6686 if (txt_encoding != NULL) {
6687 doc_charset = xmlParseCharEncoding(txt_encoding);
6688
6689 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6690 xmlGenericError(xmlGenericErrorContext,
6691 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6692 return;
6693
6694 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6695 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6696 if ( conv_hdlr == NULL ) {
6697 xmlGenericError(xmlGenericErrorContext,
6698 "%s: %s %s '%s'\n",
6699 "xmlDocDumpFormatMemoryEnc",
6700 "Failed to identify encoding handler for",
6701 "character set",
6702 txt_encoding);
6703 return;
6704 }
6705 }
6706 }
6707
6708 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6709 xmlGenericError(xmlGenericErrorContext,
6710 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6711 return;
6712 }
6713
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006714 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006715 xmlOutputBufferFlush(out_buff);
6716 if (out_buff->conv != NULL) {
6717 *doc_txt_len = out_buff->conv->use;
6718 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6719 } else {
6720 *doc_txt_len = out_buff->buffer->use;
6721 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6722 }
6723 (void)xmlOutputBufferClose(out_buff);
6724
6725 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6726 *doc_txt_len = 0;
6727 xmlGenericError(xmlGenericErrorContext,
6728 "xmlDocDumpFormatMemoryEnc: %s\n",
6729 "Failed to allocate memory for document text representation.");
6730 }
6731
6732 return;
6733}
6734
6735/**
6736 * xmlDocDumpMemory:
6737 * @cur: the document
6738 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006739 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006740 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006741 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006742 * It's up to the caller to free the memory.
6743 */
6744void
6745xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6746 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6747}
6748
6749/**
6750 * xmlDocDumpFormatMemory:
6751 * @cur: the document
6752 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006753 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006754 * @format: should formatting spaces been added
6755 *
6756 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006757 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006758 * It's up to the caller to free the memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006759 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6760 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006761 */
6762void
6763xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6764 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6765}
6766
6767/**
6768 * xmlDocDumpMemoryEnc:
6769 * @out_doc: Document to generate XML text from
6770 * @doc_txt_ptr: Memory pointer for allocated XML text
6771 * @doc_txt_len: Length of the generated XML text
6772 * @txt_encoding: Character encoding to use when generating XML text
6773 *
6774 * Dump the current DOM tree into memory using the character encoding specified
6775 * by the caller. Note it is up to the caller of this function to free the
6776 * allocated memory.
6777 */
6778
6779void
6780xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6781 int * doc_txt_len, const char * txt_encoding) {
6782 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006783 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006784}
6785
6786/**
6787 * xmlGetDocCompressMode:
6788 * @doc: the document
6789 *
6790 * get the compression ratio for a document, ZLIB based
6791 * Returns 0 (uncompressed) to 9 (max compression)
6792 */
6793int
6794xmlGetDocCompressMode (xmlDocPtr doc) {
6795 if (doc == NULL) return(-1);
6796 return(doc->compression);
6797}
6798
6799/**
6800 * xmlSetDocCompressMode:
6801 * @doc: the document
6802 * @mode: the compression ratio
6803 *
6804 * set the compression ratio for a document, ZLIB based
6805 * Correct values: 0 (uncompressed) to 9 (max compression)
6806 */
6807void
6808xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6809 if (doc == NULL) return;
6810 if (mode < 0) doc->compression = 0;
6811 else if (mode > 9) doc->compression = 9;
6812 else doc->compression = mode;
6813}
6814
6815/**
6816 * xmlGetCompressMode:
6817 *
6818 * get the default compression mode used, ZLIB based.
6819 * Returns 0 (uncompressed) to 9 (max compression)
6820 */
6821int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006822xmlGetCompressMode(void)
6823{
6824 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006825}
6826
6827/**
6828 * xmlSetCompressMode:
6829 * @mode: the compression ratio
6830 *
6831 * set the default compression mode used, ZLIB based
6832 * Correct values: 0 (uncompressed) to 9 (max compression)
6833 */
6834void
6835xmlSetCompressMode(int mode) {
6836 if (mode < 0) xmlCompressMode = 0;
6837 else if (mode > 9) xmlCompressMode = 9;
6838 else xmlCompressMode = mode;
6839}
6840
6841/**
6842 * xmlDocDump:
6843 * @f: the FILE*
6844 * @cur: the document
6845 *
6846 * Dump an XML document to an open FILE.
6847 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006848 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006849 */
6850int
6851xmlDocDump(FILE *f, xmlDocPtr cur) {
6852 xmlOutputBufferPtr buf;
6853 const char * encoding;
6854 xmlCharEncodingHandlerPtr handler = NULL;
6855 int ret;
6856
6857 if (cur == NULL) {
6858#ifdef DEBUG_TREE
6859 xmlGenericError(xmlGenericErrorContext,
6860 "xmlDocDump : document == NULL\n");
6861#endif
6862 return(-1);
6863 }
6864 encoding = (const char *) cur->encoding;
6865
6866 if (encoding != NULL) {
6867 xmlCharEncoding enc;
6868
6869 enc = xmlParseCharEncoding(encoding);
6870
6871 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6872 xmlGenericError(xmlGenericErrorContext,
6873 "xmlDocDump: document not in UTF8\n");
6874 return(-1);
6875 }
6876 if (enc != XML_CHAR_ENCODING_UTF8) {
6877 handler = xmlFindCharEncodingHandler(encoding);
6878 if (handler == NULL) {
6879 xmlFree((char *) cur->encoding);
6880 cur->encoding = NULL;
6881 }
6882 }
6883 }
6884 buf = xmlOutputBufferCreateFile(f, handler);
6885 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006886 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006887
6888 ret = xmlOutputBufferClose(buf);
6889 return(ret);
6890}
6891
6892/**
6893 * xmlSaveFileTo:
6894 * @buf: an output I/O buffer
6895 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006896 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006897 *
6898 * Dump an XML document to an I/O buffer.
6899 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006900 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006901 */
6902int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006903xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006904 int ret;
6905
6906 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006907 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006908 ret = xmlOutputBufferClose(buf);
6909 return(ret);
6910}
6911
6912/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006913 * xmlSaveFormatFileTo:
6914 * @buf: an output I/O buffer
6915 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006916 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006917 * @format: should formatting spaces been added
6918 *
6919 * Dump an XML document to an I/O buffer.
6920 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006921 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006922 */
6923int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006924xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006925 int ret;
6926
6927 if (buf == NULL) return(0);
6928 xmlDocContentDumpOutput(buf, cur, encoding, format);
6929 ret = xmlOutputBufferClose(buf);
6930 return(ret);
6931}
6932
6933/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006934 * xmlSaveFormatFileEnc
6935 * @filename: the filename or URL to output
6936 * @cur: the document being saved
6937 * @encoding: the name of the encoding to use or NULL.
6938 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006939 *
6940 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006941 */
6942int
Daniel Veillardf012a642001-07-23 19:10:52 +00006943xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6944 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006945 xmlOutputBufferPtr buf;
6946 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006947 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006948 int ret;
6949
Daniel Veillardfb25a512002-01-13 20:32:08 +00006950 if (encoding == NULL)
6951 encoding = (const char *) cur->encoding;
6952
Owen Taylor3473f882001-02-23 17:55:21 +00006953 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006954
6955 enc = xmlParseCharEncoding(encoding);
6956 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6957 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006958 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006959 return(-1);
6960 }
6961 if (enc != XML_CHAR_ENCODING_UTF8) {
6962 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006963 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006964 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006965 }
6966 }
6967
Daniel Veillardf012a642001-07-23 19:10:52 +00006968#ifdef HAVE_ZLIB_H
6969 if (cur->compression < 0) cur->compression = xmlCompressMode;
6970#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006971 /*
6972 * save the content to a temp buffer.
6973 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006974 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006975 if (buf == NULL) return(-1);
6976
Daniel Veillardf012a642001-07-23 19:10:52 +00006977 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006978
6979 ret = xmlOutputBufferClose(buf);
6980 return(ret);
6981}
6982
Daniel Veillardf012a642001-07-23 19:10:52 +00006983
6984/**
6985 * xmlSaveFileEnc:
6986 * @filename: the filename (or URL)
6987 * @cur: the document
6988 * @encoding: the name of an encoding (or NULL)
6989 *
6990 * Dump an XML document, converting it to the given encoding
6991 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006992 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006993 */
6994int
6995xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6996 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6997}
6998
Owen Taylor3473f882001-02-23 17:55:21 +00006999/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007000 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007001 * @filename: the filename (or URL)
7002 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007003 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007004 *
7005 * Dump an XML document to a file. Will use compression if
7006 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007007 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007008 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007009 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007010 */
7011int
Daniel Veillard67fee942001-04-26 18:59:03 +00007012xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007013 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007014}
7015
Daniel Veillard67fee942001-04-26 18:59:03 +00007016/**
7017 * xmlSaveFile:
7018 * @filename: the filename (or URL)
7019 * @cur: the document
7020 *
7021 * Dump an XML document to a file. Will use compression if
7022 * compiled in and enabled. If @filename is "-" the stdout file is
7023 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007024 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007025 */
7026int
7027xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007028 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007029}
7030