blob: b4b143b8c910d4f0e8802b8ddf09e9966b9184e9 [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/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001207 * xmlNewNsPropEatName:
1208 * @node: the holding node
1209 * @ns: the namespace
1210 * @name: the name of the attribute
1211 * @value: the value of the attribute
1212 *
1213 * Create a new property tagged with a namespace and carried by a node.
1214 * Returns a pointer to the attribute
1215 */
1216xmlAttrPtr
1217xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1218 const xmlChar *value) {
1219 xmlAttrPtr cur;
1220 xmlDocPtr doc = NULL;
1221
1222 if (name == NULL) {
1223#ifdef DEBUG_TREE
1224 xmlGenericError(xmlGenericErrorContext,
1225 "xmlNewNsPropEatName : name == NULL\n");
1226#endif
1227 return(NULL);
1228 }
1229
1230 /*
1231 * Allocate a new property and fill the fields.
1232 */
1233 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1234 if (cur == NULL) {
1235 xmlGenericError(xmlGenericErrorContext,
1236 "xmlNewNsPropEatName : malloc failed\n");
1237 return(NULL);
1238 }
1239 memset(cur, 0, sizeof(xmlAttr));
1240 cur->type = XML_ATTRIBUTE_NODE;
1241
1242 cur->parent = node;
1243 if (node != NULL) {
1244 doc = node->doc;
1245 cur->doc = doc;
1246 }
1247 cur->ns = ns;
1248 cur->name = name;
1249 if (value != NULL) {
1250 xmlChar *buffer;
1251 xmlNodePtr tmp;
1252
1253 buffer = xmlEncodeEntitiesReentrant(doc, value);
1254 cur->children = xmlStringGetNodeList(doc, buffer);
1255 cur->last = NULL;
1256 tmp = cur->children;
1257 while (tmp != NULL) {
1258 tmp->parent = (xmlNodePtr) cur;
1259 if (tmp->next == NULL)
1260 cur->last = tmp;
1261 tmp = tmp->next;
1262 }
1263 xmlFree(buffer);
1264 }
1265
1266 /*
1267 * Add it at the end to preserve parsing order ...
1268 */
1269 if (node != NULL) {
1270 if (node->properties == NULL) {
1271 node->properties = cur;
1272 } else {
1273 xmlAttrPtr prev = node->properties;
1274
1275 while (prev->next != NULL) prev = prev->next;
1276 prev->next = cur;
1277 cur->prev = prev;
1278 }
1279 }
1280 return(cur);
1281}
1282
1283/**
Owen Taylor3473f882001-02-23 17:55:21 +00001284 * xmlNewDocProp:
1285 * @doc: the document
1286 * @name: the name of the attribute
1287 * @value: the value of the attribute
1288 *
1289 * Create a new property carried by a document.
1290 * Returns a pointer to the attribute
1291 */
1292xmlAttrPtr
1293xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1294 xmlAttrPtr cur;
1295
1296 if (name == NULL) {
1297#ifdef DEBUG_TREE
1298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001299 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001300#endif
1301 return(NULL);
1302 }
1303
1304 /*
1305 * Allocate a new property and fill the fields.
1306 */
1307 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1308 if (cur == NULL) {
1309 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001310 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001311 return(NULL);
1312 }
1313 memset(cur, 0, sizeof(xmlAttr));
1314 cur->type = XML_ATTRIBUTE_NODE;
1315
1316 cur->name = xmlStrdup(name);
1317 cur->doc = doc;
1318 if (value != NULL) {
1319 xmlNodePtr tmp;
1320
1321 cur->children = xmlStringGetNodeList(doc, value);
1322 cur->last = NULL;
1323
1324 tmp = cur->children;
1325 while (tmp != NULL) {
1326 tmp->parent = (xmlNodePtr) cur;
1327 if (tmp->next == NULL)
1328 cur->last = tmp;
1329 tmp = tmp->next;
1330 }
1331 }
1332 return(cur);
1333}
1334
1335/**
1336 * xmlFreePropList:
1337 * @cur: the first property in the list
1338 *
1339 * Free a property and all its siblings, all the children are freed too.
1340 */
1341void
1342xmlFreePropList(xmlAttrPtr cur) {
1343 xmlAttrPtr next;
1344 if (cur == NULL) {
1345#ifdef DEBUG_TREE
1346 xmlGenericError(xmlGenericErrorContext,
1347 "xmlFreePropList : property == NULL\n");
1348#endif
1349 return;
1350 }
1351 while (cur != NULL) {
1352 next = cur->next;
1353 xmlFreeProp(cur);
1354 cur = next;
1355 }
1356}
1357
1358/**
1359 * xmlFreeProp:
1360 * @cur: an attribute
1361 *
1362 * Free one attribute, all the content is freed too
1363 */
1364void
1365xmlFreeProp(xmlAttrPtr cur) {
1366 if (cur == NULL) {
1367#ifdef DEBUG_TREE
1368 xmlGenericError(xmlGenericErrorContext,
1369 "xmlFreeProp : property == NULL\n");
1370#endif
1371 return;
1372 }
1373 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001374 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1375 ((cur->parent->doc->intSubset != NULL) ||
1376 (cur->parent->doc->extSubset != NULL))) {
1377 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1378 xmlRemoveID(cur->parent->doc, cur);
1379 }
Owen Taylor3473f882001-02-23 17:55:21 +00001380 if (cur->name != NULL) xmlFree((char *) cur->name);
1381 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001382 xmlFree(cur);
1383}
1384
1385/**
1386 * xmlRemoveProp:
1387 * @cur: an attribute
1388 *
1389 * Unlink and free one attribute, all the content is freed too
1390 * Note this doesn't work for namespace definition attributes
1391 *
1392 * Returns 0 if success and -1 in case of error.
1393 */
1394int
1395xmlRemoveProp(xmlAttrPtr cur) {
1396 xmlAttrPtr tmp;
1397 if (cur == NULL) {
1398#ifdef DEBUG_TREE
1399 xmlGenericError(xmlGenericErrorContext,
1400 "xmlRemoveProp : cur == NULL\n");
1401#endif
1402 return(-1);
1403 }
1404 if (cur->parent == NULL) {
1405#ifdef DEBUG_TREE
1406 xmlGenericError(xmlGenericErrorContext,
1407 "xmlRemoveProp : cur->parent == NULL\n");
1408#endif
1409 return(-1);
1410 }
1411 tmp = cur->parent->properties;
1412 if (tmp == cur) {
1413 cur->parent->properties = cur->next;
1414 xmlFreeProp(cur);
1415 return(0);
1416 }
1417 while (tmp != NULL) {
1418 if (tmp->next == cur) {
1419 tmp->next = cur->next;
1420 if (tmp->next != NULL)
1421 tmp->next->prev = tmp;
1422 xmlFreeProp(cur);
1423 return(0);
1424 }
1425 tmp = tmp->next;
1426 }
1427#ifdef DEBUG_TREE
1428 xmlGenericError(xmlGenericErrorContext,
1429 "xmlRemoveProp : attribute not owned by its node\n");
1430#endif
1431 return(-1);
1432}
1433
1434/**
1435 * xmlNewPI:
1436 * @name: the processing instruction name
1437 * @content: the PI content
1438 *
1439 * Creation of a processing instruction element.
1440 * Returns a pointer to the new node object.
1441 */
1442xmlNodePtr
1443xmlNewPI(const xmlChar *name, const xmlChar *content) {
1444 xmlNodePtr cur;
1445
1446 if (name == NULL) {
1447#ifdef DEBUG_TREE
1448 xmlGenericError(xmlGenericErrorContext,
1449 "xmlNewPI : name == NULL\n");
1450#endif
1451 return(NULL);
1452 }
1453
1454 /*
1455 * Allocate a new node and fill the fields.
1456 */
1457 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1458 if (cur == NULL) {
1459 xmlGenericError(xmlGenericErrorContext,
1460 "xmlNewPI : malloc failed\n");
1461 return(NULL);
1462 }
1463 memset(cur, 0, sizeof(xmlNode));
1464 cur->type = XML_PI_NODE;
1465
1466 cur->name = xmlStrdup(name);
1467 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001468 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001469 }
1470 return(cur);
1471}
1472
1473/**
1474 * xmlNewNode:
1475 * @ns: namespace if any
1476 * @name: the node name
1477 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001478 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001479 *
1480 * Returns a pointer to the new node object.
1481 */
1482xmlNodePtr
1483xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1484 xmlNodePtr cur;
1485
1486 if (name == NULL) {
1487#ifdef DEBUG_TREE
1488 xmlGenericError(xmlGenericErrorContext,
1489 "xmlNewNode : name == NULL\n");
1490#endif
1491 return(NULL);
1492 }
1493
1494 /*
1495 * Allocate a new node and fill the fields.
1496 */
1497 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1498 if (cur == NULL) {
1499 xmlGenericError(xmlGenericErrorContext,
1500 "xmlNewNode : malloc failed\n");
1501 return(NULL);
1502 }
1503 memset(cur, 0, sizeof(xmlNode));
1504 cur->type = XML_ELEMENT_NODE;
1505
1506 cur->name = xmlStrdup(name);
1507 cur->ns = ns;
1508 return(cur);
1509}
1510
1511/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001512 * xmlNewNodeEatName:
1513 * @ns: namespace if any
1514 * @name: the node name
1515 *
1516 * Creation of a new node element. @ns is optional (NULL).
1517 *
1518 * Returns a pointer to the new node object.
1519 */
1520xmlNodePtr
1521xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1522 xmlNodePtr cur;
1523
1524 if (name == NULL) {
1525#ifdef DEBUG_TREE
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlNewNode : name == NULL\n");
1528#endif
1529 return(NULL);
1530 }
1531
1532 /*
1533 * Allocate a new node and fill the fields.
1534 */
1535 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1536 if (cur == NULL) {
1537 xmlGenericError(xmlGenericErrorContext,
1538 "xmlNewNode : malloc failed\n");
1539 return(NULL);
1540 }
1541 memset(cur, 0, sizeof(xmlNode));
1542 cur->type = XML_ELEMENT_NODE;
1543
1544 cur->name = name;
1545 cur->ns = ns;
1546 return(cur);
1547}
1548
1549/**
Owen Taylor3473f882001-02-23 17:55:21 +00001550 * xmlNewDocNode:
1551 * @doc: the document
1552 * @ns: namespace if any
1553 * @name: the node name
1554 * @content: the XML text content if any
1555 *
1556 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001557 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001558 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1559 * references, but XML special chars need to be escaped first by using
1560 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1561 * need entities support.
1562 *
1563 * Returns a pointer to the new node object.
1564 */
1565xmlNodePtr
1566xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1567 const xmlChar *name, const xmlChar *content) {
1568 xmlNodePtr cur;
1569
1570 cur = xmlNewNode(ns, name);
1571 if (cur != NULL) {
1572 cur->doc = doc;
1573 if (content != NULL) {
1574 cur->children = xmlStringGetNodeList(doc, content);
1575 UPDATE_LAST_CHILD_AND_PARENT(cur)
1576 }
1577 }
1578 return(cur);
1579}
1580
Daniel Veillard46de64e2002-05-29 08:21:33 +00001581/**
1582 * xmlNewDocNodeEatName:
1583 * @doc: the document
1584 * @ns: namespace if any
1585 * @name: the node name
1586 * @content: the XML text content if any
1587 *
1588 * Creation of a new node element within a document. @ns and @content
1589 * are optional (NULL).
1590 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1591 * references, but XML special chars need to be escaped first by using
1592 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1593 * need entities support.
1594 *
1595 * Returns a pointer to the new node object.
1596 */
1597xmlNodePtr
1598xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1599 xmlChar *name, const xmlChar *content) {
1600 xmlNodePtr cur;
1601
1602 cur = xmlNewNodeEatName(ns, name);
1603 if (cur != NULL) {
1604 cur->doc = doc;
1605 if (content != NULL) {
1606 cur->children = xmlStringGetNodeList(doc, content);
1607 UPDATE_LAST_CHILD_AND_PARENT(cur)
1608 }
1609 }
1610 return(cur);
1611}
1612
Owen Taylor3473f882001-02-23 17:55:21 +00001613
1614/**
1615 * xmlNewDocRawNode:
1616 * @doc: the document
1617 * @ns: namespace if any
1618 * @name: the node name
1619 * @content: the text content if any
1620 *
1621 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001622 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001623 *
1624 * Returns a pointer to the new node object.
1625 */
1626xmlNodePtr
1627xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1628 const xmlChar *name, const xmlChar *content) {
1629 xmlNodePtr cur;
1630
1631 cur = xmlNewNode(ns, name);
1632 if (cur != NULL) {
1633 cur->doc = doc;
1634 if (content != NULL) {
1635 cur->children = xmlNewDocText(doc, content);
1636 UPDATE_LAST_CHILD_AND_PARENT(cur)
1637 }
1638 }
1639 return(cur);
1640}
1641
1642/**
1643 * xmlNewDocFragment:
1644 * @doc: the document owning the fragment
1645 *
1646 * Creation of a new Fragment node.
1647 * Returns a pointer to the new node object.
1648 */
1649xmlNodePtr
1650xmlNewDocFragment(xmlDocPtr doc) {
1651 xmlNodePtr cur;
1652
1653 /*
1654 * Allocate a new DocumentFragment node and fill the fields.
1655 */
1656 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1657 if (cur == NULL) {
1658 xmlGenericError(xmlGenericErrorContext,
1659 "xmlNewDocFragment : malloc failed\n");
1660 return(NULL);
1661 }
1662 memset(cur, 0, sizeof(xmlNode));
1663 cur->type = XML_DOCUMENT_FRAG_NODE;
1664
1665 cur->doc = doc;
1666 return(cur);
1667}
1668
1669/**
1670 * xmlNewText:
1671 * @content: the text content
1672 *
1673 * Creation of a new text node.
1674 * Returns a pointer to the new node object.
1675 */
1676xmlNodePtr
1677xmlNewText(const xmlChar *content) {
1678 xmlNodePtr cur;
1679
1680 /*
1681 * Allocate a new node and fill the fields.
1682 */
1683 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1684 if (cur == NULL) {
1685 xmlGenericError(xmlGenericErrorContext,
1686 "xmlNewText : malloc failed\n");
1687 return(NULL);
1688 }
1689 memset(cur, 0, sizeof(xmlNode));
1690 cur->type = XML_TEXT_NODE;
1691
1692 cur->name = xmlStringText;
1693 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001694 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001695 }
1696 return(cur);
1697}
1698
1699/**
1700 * xmlNewTextChild:
1701 * @parent: the parent node
1702 * @ns: a namespace if any
1703 * @name: the name of the child
1704 * @content: the text content of the child if any.
1705 *
1706 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001707 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001708 * a child TEXT node will be created containing the string content.
1709 *
1710 * Returns a pointer to the new node object.
1711 */
1712xmlNodePtr
1713xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1714 const xmlChar *name, const xmlChar *content) {
1715 xmlNodePtr cur, prev;
1716
1717 if (parent == NULL) {
1718#ifdef DEBUG_TREE
1719 xmlGenericError(xmlGenericErrorContext,
1720 "xmlNewTextChild : parent == NULL\n");
1721#endif
1722 return(NULL);
1723 }
1724
1725 if (name == NULL) {
1726#ifdef DEBUG_TREE
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlNewTextChild : name == NULL\n");
1729#endif
1730 return(NULL);
1731 }
1732
1733 /*
1734 * Allocate a new node
1735 */
1736 if (ns == NULL)
1737 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1738 else
1739 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1740 if (cur == NULL) return(NULL);
1741
1742 /*
1743 * add the new element at the end of the children list.
1744 */
1745 cur->type = XML_ELEMENT_NODE;
1746 cur->parent = parent;
1747 cur->doc = parent->doc;
1748 if (parent->children == NULL) {
1749 parent->children = cur;
1750 parent->last = cur;
1751 } else {
1752 prev = parent->last;
1753 prev->next = cur;
1754 cur->prev = prev;
1755 parent->last = cur;
1756 }
1757
1758 return(cur);
1759}
1760
1761/**
1762 * xmlNewCharRef:
1763 * @doc: the document
1764 * @name: the char ref string, starting with # or "&# ... ;"
1765 *
1766 * Creation of a new character reference node.
1767 * Returns a pointer to the new node object.
1768 */
1769xmlNodePtr
1770xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1771 xmlNodePtr cur;
1772
1773 /*
1774 * Allocate a new node and fill the fields.
1775 */
1776 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1777 if (cur == NULL) {
1778 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001779 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001780 return(NULL);
1781 }
1782 memset(cur, 0, sizeof(xmlNode));
1783 cur->type = XML_ENTITY_REF_NODE;
1784
1785 cur->doc = doc;
1786 if (name[0] == '&') {
1787 int len;
1788 name++;
1789 len = xmlStrlen(name);
1790 if (name[len - 1] == ';')
1791 cur->name = xmlStrndup(name, len - 1);
1792 else
1793 cur->name = xmlStrndup(name, len);
1794 } else
1795 cur->name = xmlStrdup(name);
1796 return(cur);
1797}
1798
1799/**
1800 * xmlNewReference:
1801 * @doc: the document
1802 * @name: the reference name, or the reference string with & and ;
1803 *
1804 * Creation of a new reference node.
1805 * Returns a pointer to the new node object.
1806 */
1807xmlNodePtr
1808xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1809 xmlNodePtr cur;
1810 xmlEntityPtr ent;
1811
1812 /*
1813 * Allocate a new node and fill the fields.
1814 */
1815 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1816 if (cur == NULL) {
1817 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001818 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001819 return(NULL);
1820 }
1821 memset(cur, 0, sizeof(xmlNode));
1822 cur->type = XML_ENTITY_REF_NODE;
1823
1824 cur->doc = doc;
1825 if (name[0] == '&') {
1826 int len;
1827 name++;
1828 len = xmlStrlen(name);
1829 if (name[len - 1] == ';')
1830 cur->name = xmlStrndup(name, len - 1);
1831 else
1832 cur->name = xmlStrndup(name, len);
1833 } else
1834 cur->name = xmlStrdup(name);
1835
1836 ent = xmlGetDocEntity(doc, cur->name);
1837 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001838 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001839 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001840 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001841 * updated. Not sure if this is 100% correct.
1842 * -George
1843 */
1844 cur->children = (xmlNodePtr) ent;
1845 cur->last = (xmlNodePtr) ent;
1846 }
1847 return(cur);
1848}
1849
1850/**
1851 * xmlNewDocText:
1852 * @doc: the document
1853 * @content: the text content
1854 *
1855 * Creation of a new text node within a document.
1856 * Returns a pointer to the new node object.
1857 */
1858xmlNodePtr
1859xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1860 xmlNodePtr cur;
1861
1862 cur = xmlNewText(content);
1863 if (cur != NULL) cur->doc = doc;
1864 return(cur);
1865}
1866
1867/**
1868 * xmlNewTextLen:
1869 * @content: the text content
1870 * @len: the text len.
1871 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001872 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001873 * Returns a pointer to the new node object.
1874 */
1875xmlNodePtr
1876xmlNewTextLen(const xmlChar *content, int len) {
1877 xmlNodePtr cur;
1878
1879 /*
1880 * Allocate a new node and fill the fields.
1881 */
1882 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1883 if (cur == NULL) {
1884 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001885 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001886 return(NULL);
1887 }
1888 memset(cur, 0, sizeof(xmlNode));
1889 cur->type = XML_TEXT_NODE;
1890
1891 cur->name = xmlStringText;
1892 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001893 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001894 }
1895 return(cur);
1896}
1897
1898/**
1899 * xmlNewDocTextLen:
1900 * @doc: the document
1901 * @content: the text content
1902 * @len: the text len.
1903 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001904 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001905 * text node pertain to a given document.
1906 * Returns a pointer to the new node object.
1907 */
1908xmlNodePtr
1909xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1910 xmlNodePtr cur;
1911
1912 cur = xmlNewTextLen(content, len);
1913 if (cur != NULL) cur->doc = doc;
1914 return(cur);
1915}
1916
1917/**
1918 * xmlNewComment:
1919 * @content: the comment content
1920 *
1921 * Creation of a new node containing a comment.
1922 * Returns a pointer to the new node object.
1923 */
1924xmlNodePtr
1925xmlNewComment(const xmlChar *content) {
1926 xmlNodePtr cur;
1927
1928 /*
1929 * Allocate a new node and fill the fields.
1930 */
1931 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1932 if (cur == NULL) {
1933 xmlGenericError(xmlGenericErrorContext,
1934 "xmlNewComment : malloc failed\n");
1935 return(NULL);
1936 }
1937 memset(cur, 0, sizeof(xmlNode));
1938 cur->type = XML_COMMENT_NODE;
1939
1940 cur->name = xmlStringComment;
1941 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001942 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 }
1944 return(cur);
1945}
1946
1947/**
1948 * xmlNewCDataBlock:
1949 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001950 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001951 * @len: the length of the block
1952 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001953 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001954 * Returns a pointer to the new node object.
1955 */
1956xmlNodePtr
1957xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1958 xmlNodePtr cur;
1959
1960 /*
1961 * Allocate a new node and fill the fields.
1962 */
1963 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1964 if (cur == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlNewCDataBlock : malloc failed\n");
1967 return(NULL);
1968 }
1969 memset(cur, 0, sizeof(xmlNode));
1970 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001971 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001972
1973 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001974 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001975 }
1976 return(cur);
1977}
1978
1979/**
1980 * xmlNewDocComment:
1981 * @doc: the document
1982 * @content: the comment content
1983 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001984 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001985 * Returns a pointer to the new node object.
1986 */
1987xmlNodePtr
1988xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1989 xmlNodePtr cur;
1990
1991 cur = xmlNewComment(content);
1992 if (cur != NULL) cur->doc = doc;
1993 return(cur);
1994}
1995
1996/**
1997 * xmlSetTreeDoc:
1998 * @tree: the top element
1999 * @doc: the document
2000 *
2001 * update all nodes under the tree to point to the right document
2002 */
2003void
2004xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002005 xmlAttrPtr prop;
2006
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (tree == NULL)
2008 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002009 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002010 if(tree->type == XML_ELEMENT_NODE) {
2011 prop = tree->properties;
2012 while (prop != NULL) {
2013 prop->doc = doc;
2014 xmlSetListDoc(prop->children, doc);
2015 prop = prop->next;
2016 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002017 }
Owen Taylor3473f882001-02-23 17:55:21 +00002018 if (tree->children != NULL)
2019 xmlSetListDoc(tree->children, doc);
2020 tree->doc = doc;
2021 }
2022}
2023
2024/**
2025 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002026 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002027 * @doc: the document
2028 *
2029 * update all nodes in the list to point to the right document
2030 */
2031void
2032xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2033 xmlNodePtr cur;
2034
2035 if (list == NULL)
2036 return;
2037 cur = list;
2038 while (cur != NULL) {
2039 if (cur->doc != doc)
2040 xmlSetTreeDoc(cur, doc);
2041 cur = cur->next;
2042 }
2043}
2044
2045
2046/**
2047 * xmlNewChild:
2048 * @parent: the parent node
2049 * @ns: a namespace if any
2050 * @name: the name of the child
2051 * @content: the XML content of the child if any.
2052 *
2053 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002054 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002055 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2056 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2057 * references, but XML special chars need to be escaped first by using
2058 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2059 * support is not needed.
2060 *
2061 * Returns a pointer to the new node object.
2062 */
2063xmlNodePtr
2064xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2065 const xmlChar *name, const xmlChar *content) {
2066 xmlNodePtr cur, prev;
2067
2068 if (parent == NULL) {
2069#ifdef DEBUG_TREE
2070 xmlGenericError(xmlGenericErrorContext,
2071 "xmlNewChild : parent == NULL\n");
2072#endif
2073 return(NULL);
2074 }
2075
2076 if (name == NULL) {
2077#ifdef DEBUG_TREE
2078 xmlGenericError(xmlGenericErrorContext,
2079 "xmlNewChild : name == NULL\n");
2080#endif
2081 return(NULL);
2082 }
2083
2084 /*
2085 * Allocate a new node
2086 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002087 if (parent->type == XML_ELEMENT_NODE) {
2088 if (ns == NULL)
2089 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2090 else
2091 cur = xmlNewDocNode(parent->doc, ns, name, content);
2092 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2093 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2094 if (ns == NULL)
2095 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2096 else
2097 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
2098 } else {
2099 return(NULL);
2100 }
Owen Taylor3473f882001-02-23 17:55:21 +00002101 if (cur == NULL) return(NULL);
2102
2103 /*
2104 * add the new element at the end of the children list.
2105 */
2106 cur->type = XML_ELEMENT_NODE;
2107 cur->parent = parent;
2108 cur->doc = parent->doc;
2109 if (parent->children == NULL) {
2110 parent->children = cur;
2111 parent->last = cur;
2112 } else {
2113 prev = parent->last;
2114 prev->next = cur;
2115 cur->prev = prev;
2116 parent->last = cur;
2117 }
2118
2119 return(cur);
2120}
2121
2122/**
2123 * xmlAddNextSibling:
2124 * @cur: the child node
2125 * @elem: the new node
2126 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002127 * Add a new node @elem as the next sibling of @cur
2128 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002129 * first unlinked from its existing context.
2130 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002131 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2132 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002133 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002134 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002135 */
2136xmlNodePtr
2137xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2138 if (cur == NULL) {
2139#ifdef DEBUG_TREE
2140 xmlGenericError(xmlGenericErrorContext,
2141 "xmlAddNextSibling : cur == NULL\n");
2142#endif
2143 return(NULL);
2144 }
2145 if (elem == NULL) {
2146#ifdef DEBUG_TREE
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlAddNextSibling : elem == NULL\n");
2149#endif
2150 return(NULL);
2151 }
2152
2153 xmlUnlinkNode(elem);
2154
2155 if (elem->type == XML_TEXT_NODE) {
2156 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002157 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002158 xmlFreeNode(elem);
2159 return(cur);
2160 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002161 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2162 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002163 xmlChar *tmp;
2164
2165 tmp = xmlStrdup(elem->content);
2166 tmp = xmlStrcat(tmp, cur->next->content);
2167 xmlNodeSetContent(cur->next, tmp);
2168 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002169 xmlFreeNode(elem);
2170 return(cur->next);
2171 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002172 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2173 /* check if an attribute with the same name exists */
2174 xmlAttrPtr attr;
2175
2176 if (elem->ns == NULL)
2177 attr = xmlHasProp(cur->parent, elem->name);
2178 else
2179 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2180 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2181 /* different instance, destroy it (attributes must be unique) */
2182 xmlFreeProp(attr);
2183 }
Owen Taylor3473f882001-02-23 17:55:21 +00002184 }
2185
2186 if (elem->doc != cur->doc) {
2187 xmlSetTreeDoc(elem, cur->doc);
2188 }
2189 elem->parent = cur->parent;
2190 elem->prev = cur;
2191 elem->next = cur->next;
2192 cur->next = elem;
2193 if (elem->next != NULL)
2194 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002195 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002196 elem->parent->last = elem;
2197 return(elem);
2198}
2199
2200/**
2201 * xmlAddPrevSibling:
2202 * @cur: the child node
2203 * @elem: the new node
2204 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002205 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002207 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002208 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002209 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2210 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002211 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002212 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002213 */
2214xmlNodePtr
2215xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2216 if (cur == NULL) {
2217#ifdef DEBUG_TREE
2218 xmlGenericError(xmlGenericErrorContext,
2219 "xmlAddPrevSibling : cur == NULL\n");
2220#endif
2221 return(NULL);
2222 }
2223 if (elem == NULL) {
2224#ifdef DEBUG_TREE
2225 xmlGenericError(xmlGenericErrorContext,
2226 "xmlAddPrevSibling : elem == NULL\n");
2227#endif
2228 return(NULL);
2229 }
2230
2231 xmlUnlinkNode(elem);
2232
2233 if (elem->type == XML_TEXT_NODE) {
2234 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002235 xmlChar *tmp;
2236
2237 tmp = xmlStrdup(elem->content);
2238 tmp = xmlStrcat(tmp, cur->content);
2239 xmlNodeSetContent(cur, tmp);
2240 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlFreeNode(elem);
2242 return(cur);
2243 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002244 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2245 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002247 xmlFreeNode(elem);
2248 return(cur->prev);
2249 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002250 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2251 /* check if an attribute with the same name exists */
2252 xmlAttrPtr attr;
2253
2254 if (elem->ns == NULL)
2255 attr = xmlHasProp(cur->parent, elem->name);
2256 else
2257 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2258 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2259 /* different instance, destroy it (attributes must be unique) */
2260 xmlFreeProp(attr);
2261 }
Owen Taylor3473f882001-02-23 17:55:21 +00002262 }
2263
2264 if (elem->doc != cur->doc) {
2265 xmlSetTreeDoc(elem, cur->doc);
2266 }
2267 elem->parent = cur->parent;
2268 elem->next = cur;
2269 elem->prev = cur->prev;
2270 cur->prev = elem;
2271 if (elem->prev != NULL)
2272 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002273 if (elem->parent != NULL) {
2274 if (elem->type == XML_ATTRIBUTE_NODE) {
2275 if (elem->parent->properties == (xmlAttrPtr) cur) {
2276 elem->parent->properties = (xmlAttrPtr) elem;
2277 }
2278 } else {
2279 if (elem->parent->children == cur) {
2280 elem->parent->children = elem;
2281 }
2282 }
2283 }
Owen Taylor3473f882001-02-23 17:55:21 +00002284 return(elem);
2285}
2286
2287/**
2288 * xmlAddSibling:
2289 * @cur: the child node
2290 * @elem: the new node
2291 *
2292 * Add a new element @elem to the list of siblings of @cur
2293 * merging adjacent TEXT nodes (@elem may be freed)
2294 * If the new element was already inserted in a document it is
2295 * first unlinked from its existing context.
2296 *
2297 * Returns the new element or NULL in case of error.
2298 */
2299xmlNodePtr
2300xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2301 xmlNodePtr parent;
2302
2303 if (cur == NULL) {
2304#ifdef DEBUG_TREE
2305 xmlGenericError(xmlGenericErrorContext,
2306 "xmlAddSibling : cur == NULL\n");
2307#endif
2308 return(NULL);
2309 }
2310
2311 if (elem == NULL) {
2312#ifdef DEBUG_TREE
2313 xmlGenericError(xmlGenericErrorContext,
2314 "xmlAddSibling : elem == NULL\n");
2315#endif
2316 return(NULL);
2317 }
2318
2319 /*
2320 * Constant time is we can rely on the ->parent->last to find
2321 * the last sibling.
2322 */
2323 if ((cur->parent != NULL) &&
2324 (cur->parent->children != NULL) &&
2325 (cur->parent->last != NULL) &&
2326 (cur->parent->last->next == NULL)) {
2327 cur = cur->parent->last;
2328 } else {
2329 while (cur->next != NULL) cur = cur->next;
2330 }
2331
2332 xmlUnlinkNode(elem);
2333
2334 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002335 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 xmlFreeNode(elem);
2337 return(cur);
2338 }
2339
2340 if (elem->doc != cur->doc) {
2341 xmlSetTreeDoc(elem, cur->doc);
2342 }
2343 parent = cur->parent;
2344 elem->prev = cur;
2345 elem->next = NULL;
2346 elem->parent = parent;
2347 cur->next = elem;
2348 if (parent != NULL)
2349 parent->last = elem;
2350
2351 return(elem);
2352}
2353
2354/**
2355 * xmlAddChildList:
2356 * @parent: the parent node
2357 * @cur: the first node in the list
2358 *
2359 * Add a list of node at the end of the child list of the parent
2360 * merging adjacent TEXT nodes (@cur may be freed)
2361 *
2362 * Returns the last child or NULL in case of error.
2363 */
2364xmlNodePtr
2365xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2366 xmlNodePtr prev;
2367
2368 if (parent == NULL) {
2369#ifdef DEBUG_TREE
2370 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002371 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002372#endif
2373 return(NULL);
2374 }
2375
2376 if (cur == NULL) {
2377#ifdef DEBUG_TREE
2378 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002379 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002380#endif
2381 return(NULL);
2382 }
2383
2384 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2385 (cur->doc != parent->doc)) {
2386#ifdef DEBUG_TREE
2387 xmlGenericError(xmlGenericErrorContext,
2388 "Elements moved to a different document\n");
2389#endif
2390 }
2391
2392 /*
2393 * add the first element at the end of the children list.
2394 */
2395 if (parent->children == NULL) {
2396 parent->children = cur;
2397 } else {
2398 /*
2399 * If cur and parent->last both are TEXT nodes, then merge them.
2400 */
2401 if ((cur->type == XML_TEXT_NODE) &&
2402 (parent->last->type == XML_TEXT_NODE) &&
2403 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002404 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002405 /*
2406 * if it's the only child, nothing more to be done.
2407 */
2408 if (cur->next == NULL) {
2409 xmlFreeNode(cur);
2410 return(parent->last);
2411 }
2412 prev = cur;
2413 cur = cur->next;
2414 xmlFreeNode(prev);
2415 }
2416 prev = parent->last;
2417 prev->next = cur;
2418 cur->prev = prev;
2419 }
2420 while (cur->next != NULL) {
2421 cur->parent = parent;
2422 if (cur->doc != parent->doc) {
2423 xmlSetTreeDoc(cur, parent->doc);
2424 }
2425 cur = cur->next;
2426 }
2427 cur->parent = parent;
2428 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2429 parent->last = cur;
2430
2431 return(cur);
2432}
2433
2434/**
2435 * xmlAddChild:
2436 * @parent: the parent node
2437 * @cur: the child node
2438 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002439 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002440 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002441 * If the new node was already inserted in a document it is
2442 * first unlinked from its existing context.
2443 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2444 * If there is an attribute with equal name, it is first destroyed.
2445 *
Owen Taylor3473f882001-02-23 17:55:21 +00002446 * Returns the child or NULL in case of error.
2447 */
2448xmlNodePtr
2449xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2450 xmlNodePtr prev;
2451
2452 if (parent == NULL) {
2453#ifdef DEBUG_TREE
2454 xmlGenericError(xmlGenericErrorContext,
2455 "xmlAddChild : parent == NULL\n");
2456#endif
2457 return(NULL);
2458 }
2459
2460 if (cur == NULL) {
2461#ifdef DEBUG_TREE
2462 xmlGenericError(xmlGenericErrorContext,
2463 "xmlAddChild : child == NULL\n");
2464#endif
2465 return(NULL);
2466 }
2467
Owen Taylor3473f882001-02-23 17:55:21 +00002468 /*
2469 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002470 * cur is then freed.
2471 */
2472 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002473 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002474 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002475 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002476 xmlFreeNode(cur);
2477 return(parent);
2478 }
2479 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2480 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002481 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002482 xmlFreeNode(cur);
2483 return(parent->last);
2484 }
2485 }
2486
2487 /*
2488 * add the new element at the end of the children list.
2489 */
2490 cur->parent = parent;
2491 if (cur->doc != parent->doc) {
2492 xmlSetTreeDoc(cur, parent->doc);
2493 }
2494
2495 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002496 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002497 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002498 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002499 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002500 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002501 xmlFreeNode(cur);
2502 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002503 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002504 if (cur->type == XML_ATTRIBUTE_NODE) {
2505 if (parent->properties == NULL) {
2506 parent->properties = (xmlAttrPtr) cur;
2507 } else {
2508 /* check if an attribute with the same name exists */
2509 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002510
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002511 if (cur->ns == NULL)
2512 lastattr = xmlHasProp(parent, cur->name);
2513 else
2514 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2515 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2516 /* different instance, destroy it (attributes must be unique) */
2517 xmlFreeProp(lastattr);
2518 }
2519 /* find the end */
2520 lastattr = parent->properties;
2521 while (lastattr->next != NULL) {
2522 lastattr = lastattr->next;
2523 }
2524 lastattr->next = (xmlAttrPtr) cur;
2525 ((xmlAttrPtr) cur)->prev = lastattr;
2526 }
2527 } else {
2528 if (parent->children == NULL) {
2529 parent->children = cur;
2530 parent->last = cur;
2531 } else {
2532 prev = parent->last;
2533 prev->next = cur;
2534 cur->prev = prev;
2535 parent->last = cur;
2536 }
2537 }
Owen Taylor3473f882001-02-23 17:55:21 +00002538 return(cur);
2539}
2540
2541/**
2542 * xmlGetLastChild:
2543 * @parent: the parent node
2544 *
2545 * Search the last child of a node.
2546 * Returns the last child or NULL if none.
2547 */
2548xmlNodePtr
2549xmlGetLastChild(xmlNodePtr parent) {
2550 if (parent == NULL) {
2551#ifdef DEBUG_TREE
2552 xmlGenericError(xmlGenericErrorContext,
2553 "xmlGetLastChild : parent == NULL\n");
2554#endif
2555 return(NULL);
2556 }
2557 return(parent->last);
2558}
2559
2560/**
2561 * xmlFreeNodeList:
2562 * @cur: the first node in the list
2563 *
2564 * Free a node and all its siblings, this is a recursive behaviour, all
2565 * the children are freed too.
2566 */
2567void
2568xmlFreeNodeList(xmlNodePtr cur) {
2569 xmlNodePtr next;
2570 if (cur == NULL) {
2571#ifdef DEBUG_TREE
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlFreeNodeList : node == NULL\n");
2574#endif
2575 return;
2576 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002577 if (cur->type == XML_NAMESPACE_DECL) {
2578 xmlFreeNsList((xmlNsPtr) cur);
2579 return;
2580 }
Owen Taylor3473f882001-02-23 17:55:21 +00002581 while (cur != NULL) {
2582 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002583 /* unroll to speed up freeing the document */
2584 if (cur->type != XML_DTD_NODE) {
2585 if ((cur->children != NULL) &&
2586 (cur->type != XML_ENTITY_REF_NODE))
2587 xmlFreeNodeList(cur->children);
2588 if (cur->properties != NULL)
2589 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002590 if ((cur->type != XML_ELEMENT_NODE) &&
2591 (cur->type != XML_XINCLUDE_START) &&
2592 (cur->type != XML_XINCLUDE_END) &&
2593 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002594 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002595 }
2596 if (((cur->type == XML_ELEMENT_NODE) ||
2597 (cur->type == XML_XINCLUDE_START) ||
2598 (cur->type == XML_XINCLUDE_END)) &&
2599 (cur->nsDef != NULL))
2600 xmlFreeNsList(cur->nsDef);
2601
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002602 /*
2603 * When a node is a text node or a comment, it uses a global static
2604 * variable for the name of the node.
2605 *
2606 * The xmlStrEqual comparisons need to be done when (happened with
2607 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002608 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002609 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002610 * the string addresses compare are not sufficient.
2611 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002612 if ((cur->name != NULL) &&
2613 (cur->name != xmlStringText) &&
2614 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002615 (cur->name != xmlStringComment)) {
2616 if (cur->type == XML_TEXT_NODE) {
2617 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2618 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2619 xmlFree((char *) cur->name);
2620 } else if (cur->type == XML_COMMENT_NODE) {
2621 if (!xmlStrEqual(cur->name, xmlStringComment))
2622 xmlFree((char *) cur->name);
2623 } else
2624 xmlFree((char *) cur->name);
2625 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002626 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002627 xmlFree(cur);
2628 }
Owen Taylor3473f882001-02-23 17:55:21 +00002629 cur = next;
2630 }
2631}
2632
2633/**
2634 * xmlFreeNode:
2635 * @cur: the node
2636 *
2637 * Free a node, this is a recursive behaviour, all the children are freed too.
2638 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2639 */
2640void
2641xmlFreeNode(xmlNodePtr cur) {
2642 if (cur == NULL) {
2643#ifdef DEBUG_TREE
2644 xmlGenericError(xmlGenericErrorContext,
2645 "xmlFreeNode : node == NULL\n");
2646#endif
2647 return;
2648 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002649 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002650 if (cur->type == XML_DTD_NODE) {
2651 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002652 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002653 }
2654 if (cur->type == XML_NAMESPACE_DECL) {
2655 xmlFreeNs((xmlNsPtr) cur);
2656 return;
2657 }
Owen Taylor3473f882001-02-23 17:55:21 +00002658 if ((cur->children != NULL) &&
2659 (cur->type != XML_ENTITY_REF_NODE))
2660 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002661 if (cur->properties != NULL)
2662 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002663 if ((cur->type != XML_ELEMENT_NODE) &&
2664 (cur->content != NULL) &&
2665 (cur->type != XML_ENTITY_REF_NODE) &&
2666 (cur->type != XML_XINCLUDE_END) &&
2667 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002668 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002669 }
2670
Daniel Veillardacd370f2001-06-09 17:17:51 +00002671 /*
2672 * When a node is a text node or a comment, it uses a global static
2673 * variable for the name of the node.
2674 *
2675 * The xmlStrEqual comparisons need to be done when (happened with
2676 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002677 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002678 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002679 * are not sufficient.
2680 */
Owen Taylor3473f882001-02-23 17:55:21 +00002681 if ((cur->name != NULL) &&
2682 (cur->name != xmlStringText) &&
2683 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002684 (cur->name != xmlStringComment)) {
2685 if (cur->type == XML_TEXT_NODE) {
2686 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2687 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2688 xmlFree((char *) cur->name);
2689 } else if (cur->type == XML_COMMENT_NODE) {
2690 if (!xmlStrEqual(cur->name, xmlStringComment))
2691 xmlFree((char *) cur->name);
2692 } else
2693 xmlFree((char *) cur->name);
2694 }
2695
Owen Taylor3473f882001-02-23 17:55:21 +00002696 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002697 xmlFree(cur);
2698}
2699
2700/**
2701 * xmlUnlinkNode:
2702 * @cur: the node
2703 *
2704 * Unlink a node from it's current context, the node is not freed
2705 */
2706void
2707xmlUnlinkNode(xmlNodePtr cur) {
2708 if (cur == NULL) {
2709#ifdef DEBUG_TREE
2710 xmlGenericError(xmlGenericErrorContext,
2711 "xmlUnlinkNode : node == NULL\n");
2712#endif
2713 return;
2714 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002715 if (cur->type == XML_DTD_NODE) {
2716 xmlDocPtr doc;
2717 doc = cur->doc;
2718 if (doc->intSubset == (xmlDtdPtr) cur)
2719 doc->intSubset = NULL;
2720 if (doc->extSubset == (xmlDtdPtr) cur)
2721 doc->extSubset = NULL;
2722 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002723 if (cur->parent != NULL) {
2724 xmlNodePtr parent;
2725 parent = cur->parent;
2726 if (cur->type == XML_ATTRIBUTE_NODE) {
2727 if (parent->properties == (xmlAttrPtr) cur)
2728 parent->properties = ((xmlAttrPtr) cur)->next;
2729 } else {
2730 if (parent->children == cur)
2731 parent->children = cur->next;
2732 if (parent->last == cur)
2733 parent->last = cur->prev;
2734 }
2735 cur->parent = NULL;
2736 }
Owen Taylor3473f882001-02-23 17:55:21 +00002737 if (cur->next != NULL)
2738 cur->next->prev = cur->prev;
2739 if (cur->prev != NULL)
2740 cur->prev->next = cur->next;
2741 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002742}
2743
2744/**
2745 * xmlReplaceNode:
2746 * @old: the old node
2747 * @cur: the node
2748 *
2749 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002750 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002751 * first unlinked from its existing context.
2752 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002753 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002754 */
2755xmlNodePtr
2756xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2757 if (old == NULL) {
2758#ifdef DEBUG_TREE
2759 xmlGenericError(xmlGenericErrorContext,
2760 "xmlReplaceNode : old == NULL\n");
2761#endif
2762 return(NULL);
2763 }
2764 if (cur == NULL) {
2765 xmlUnlinkNode(old);
2766 return(old);
2767 }
2768 if (cur == old) {
2769 return(old);
2770 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002771 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2772#ifdef DEBUG_TREE
2773 xmlGenericError(xmlGenericErrorContext,
2774 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2775#endif
2776 return(old);
2777 }
2778 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2779#ifdef DEBUG_TREE
2780 xmlGenericError(xmlGenericErrorContext,
2781 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2782#endif
2783 return(old);
2784 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002785 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2786#ifdef DEBUG_TREE
2787 xmlGenericError(xmlGenericErrorContext,
2788 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2789#endif
2790 return(old);
2791 }
2792 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2793#ifdef DEBUG_TREE
2794 xmlGenericError(xmlGenericErrorContext,
2795 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2796#endif
2797 return(old);
2798 }
Owen Taylor3473f882001-02-23 17:55:21 +00002799 xmlUnlinkNode(cur);
2800 cur->doc = old->doc;
2801 cur->parent = old->parent;
2802 cur->next = old->next;
2803 if (cur->next != NULL)
2804 cur->next->prev = cur;
2805 cur->prev = old->prev;
2806 if (cur->prev != NULL)
2807 cur->prev->next = cur;
2808 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002809 if (cur->type == XML_ATTRIBUTE_NODE) {
2810 if (cur->parent->properties == (xmlAttrPtr)old)
2811 cur->parent->properties = ((xmlAttrPtr) cur);
2812 } else {
2813 if (cur->parent->children == old)
2814 cur->parent->children = cur;
2815 if (cur->parent->last == old)
2816 cur->parent->last = cur;
2817 }
Owen Taylor3473f882001-02-23 17:55:21 +00002818 }
2819 old->next = old->prev = NULL;
2820 old->parent = NULL;
2821 return(old);
2822}
2823
2824/************************************************************************
2825 * *
2826 * Copy operations *
2827 * *
2828 ************************************************************************/
2829
2830/**
2831 * xmlCopyNamespace:
2832 * @cur: the namespace
2833 *
2834 * Do a copy of the namespace.
2835 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002836 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002837 */
2838xmlNsPtr
2839xmlCopyNamespace(xmlNsPtr cur) {
2840 xmlNsPtr ret;
2841
2842 if (cur == NULL) return(NULL);
2843 switch (cur->type) {
2844 case XML_LOCAL_NAMESPACE:
2845 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2846 break;
2847 default:
2848#ifdef DEBUG_TREE
2849 xmlGenericError(xmlGenericErrorContext,
2850 "xmlCopyNamespace: invalid type %d\n", cur->type);
2851#endif
2852 return(NULL);
2853 }
2854 return(ret);
2855}
2856
2857/**
2858 * xmlCopyNamespaceList:
2859 * @cur: the first namespace
2860 *
2861 * Do a copy of an namespace list.
2862 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002863 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002864 */
2865xmlNsPtr
2866xmlCopyNamespaceList(xmlNsPtr cur) {
2867 xmlNsPtr ret = NULL;
2868 xmlNsPtr p = NULL,q;
2869
2870 while (cur != NULL) {
2871 q = xmlCopyNamespace(cur);
2872 if (p == NULL) {
2873 ret = p = q;
2874 } else {
2875 p->next = q;
2876 p = q;
2877 }
2878 cur = cur->next;
2879 }
2880 return(ret);
2881}
2882
2883static xmlNodePtr
2884xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2885/**
2886 * xmlCopyProp:
2887 * @target: the element where the attribute will be grafted
2888 * @cur: the attribute
2889 *
2890 * Do a copy of the attribute.
2891 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002892 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002893 */
2894xmlAttrPtr
2895xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2896 xmlAttrPtr ret;
2897
2898 if (cur == NULL) return(NULL);
2899 if (target != NULL)
2900 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2901 else if (cur->parent != NULL)
2902 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2903 else if (cur->children != NULL)
2904 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2905 else
2906 ret = xmlNewDocProp(NULL, cur->name, NULL);
2907 if (ret == NULL) return(NULL);
2908 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002909
Owen Taylor3473f882001-02-23 17:55:21 +00002910 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002911 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002912/*
2913 * if (target->doc)
2914 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2915 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2916 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2917 * else
2918 * ns = NULL;
2919 * ret->ns = ns;
2920 */
2921 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2922 if (ns == NULL) {
2923 /*
2924 * Humm, we are copying an element whose namespace is defined
2925 * out of the new tree scope. Search it in the original tree
2926 * and add it at the top of the new tree
2927 */
2928 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2929 if (ns != NULL) {
2930 xmlNodePtr root = target;
2931 xmlNodePtr pred = NULL;
2932
2933 while (root->parent != NULL) {
2934 pred = root;
2935 root = root->parent;
2936 }
2937 if (root == (xmlNodePtr) target->doc) {
2938 /* correct possibly cycling above the document elt */
2939 root = pred;
2940 }
2941 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2942 }
2943 } else {
2944 /*
2945 * we have to find something appropriate here since
2946 * we cant be sure, that the namespce we found is identified
2947 * by the prefix
2948 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002949 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002950 /* this is the nice case */
2951 ret->ns = ns;
2952 } else {
2953 /*
2954 * we are in trouble: we need a new reconcilied namespace.
2955 * This is expensive
2956 */
2957 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2958 }
2959 }
2960
Owen Taylor3473f882001-02-23 17:55:21 +00002961 } else
2962 ret->ns = NULL;
2963
2964 if (cur->children != NULL) {
2965 xmlNodePtr tmp;
2966
2967 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2968 ret->last = NULL;
2969 tmp = ret->children;
2970 while (tmp != NULL) {
2971 /* tmp->parent = (xmlNodePtr)ret; */
2972 if (tmp->next == NULL)
2973 ret->last = tmp;
2974 tmp = tmp->next;
2975 }
2976 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002977 /*
2978 * Try to handle IDs
2979 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002980 if ((target!= NULL) && (cur!= NULL) &&
2981 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002982 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2983 if (xmlIsID(cur->doc, cur->parent, cur)) {
2984 xmlChar *id;
2985
2986 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2987 if (id != NULL) {
2988 xmlAddID(NULL, target->doc, id, ret);
2989 xmlFree(id);
2990 }
2991 }
2992 }
Owen Taylor3473f882001-02-23 17:55:21 +00002993 return(ret);
2994}
2995
2996/**
2997 * xmlCopyPropList:
2998 * @target: the element where the attributes will be grafted
2999 * @cur: the first attribute
3000 *
3001 * Do a copy of an attribute list.
3002 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003003 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003004 */
3005xmlAttrPtr
3006xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3007 xmlAttrPtr ret = NULL;
3008 xmlAttrPtr p = NULL,q;
3009
3010 while (cur != NULL) {
3011 q = xmlCopyProp(target, cur);
3012 if (p == NULL) {
3013 ret = p = q;
3014 } else {
3015 p->next = q;
3016 q->prev = p;
3017 p = q;
3018 }
3019 cur = cur->next;
3020 }
3021 return(ret);
3022}
3023
3024/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003025 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003026 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003027 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003028 * tricky reason: namespaces. Doing a direct copy of a node
3029 * say RPM:Copyright without changing the namespace pointer to
3030 * something else can produce stale links. One way to do it is
3031 * to keep a reference counter but this doesn't work as soon
3032 * as one move the element or the subtree out of the scope of
3033 * the existing namespace. The actual solution seems to add
3034 * a copy of the namespace at the top of the copied tree if
3035 * not available in the subtree.
3036 * Hence two functions, the public front-end call the inner ones
3037 */
3038
3039static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003040xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003041 int recursive) {
3042 xmlNodePtr ret;
3043
3044 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003045 switch (node->type) {
3046 case XML_TEXT_NODE:
3047 case XML_CDATA_SECTION_NODE:
3048 case XML_ELEMENT_NODE:
3049 case XML_ENTITY_REF_NODE:
3050 case XML_ENTITY_NODE:
3051 case XML_PI_NODE:
3052 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003053 case XML_XINCLUDE_START:
3054 case XML_XINCLUDE_END:
3055 break;
3056 case XML_ATTRIBUTE_NODE:
3057 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3058 case XML_NAMESPACE_DECL:
3059 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3060
Daniel Veillard39196eb2001-06-19 18:09:42 +00003061 case XML_DOCUMENT_NODE:
3062 case XML_HTML_DOCUMENT_NODE:
3063#ifdef LIBXML_DOCB_ENABLED
3064 case XML_DOCB_DOCUMENT_NODE:
3065#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003066 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003067 case XML_DOCUMENT_TYPE_NODE:
3068 case XML_DOCUMENT_FRAG_NODE:
3069 case XML_NOTATION_NODE:
3070 case XML_DTD_NODE:
3071 case XML_ELEMENT_DECL:
3072 case XML_ATTRIBUTE_DECL:
3073 case XML_ENTITY_DECL:
3074 return(NULL);
3075 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003076
Owen Taylor3473f882001-02-23 17:55:21 +00003077 /*
3078 * Allocate a new node and fill the fields.
3079 */
3080 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3081 if (ret == NULL) {
3082 xmlGenericError(xmlGenericErrorContext,
3083 "xmlStaticCopyNode : malloc failed\n");
3084 return(NULL);
3085 }
3086 memset(ret, 0, sizeof(xmlNode));
3087 ret->type = node->type;
3088
3089 ret->doc = doc;
3090 ret->parent = parent;
3091 if (node->name == xmlStringText)
3092 ret->name = xmlStringText;
3093 else if (node->name == xmlStringTextNoenc)
3094 ret->name = xmlStringTextNoenc;
3095 else if (node->name == xmlStringComment)
3096 ret->name = xmlStringComment;
3097 else if (node->name != NULL)
3098 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003099 if ((node->type != XML_ELEMENT_NODE) &&
3100 (node->content != NULL) &&
3101 (node->type != XML_ENTITY_REF_NODE) &&
3102 (node->type != XML_XINCLUDE_END) &&
3103 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003104 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003105 }else{
3106 if (node->type == XML_ELEMENT_NODE)
3107 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003108 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003109 if (parent != NULL) {
3110 xmlNodePtr tmp;
3111
3112 tmp = xmlAddChild(parent, ret);
3113 /* node could have coalesced */
3114 if (tmp != ret)
3115 return(tmp);
3116 }
Owen Taylor3473f882001-02-23 17:55:21 +00003117
3118 if (!recursive) return(ret);
3119 if (node->nsDef != NULL)
3120 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3121
3122 if (node->ns != NULL) {
3123 xmlNsPtr ns;
3124
3125 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3126 if (ns == NULL) {
3127 /*
3128 * Humm, we are copying an element whose namespace is defined
3129 * out of the new tree scope. Search it in the original tree
3130 * and add it at the top of the new tree
3131 */
3132 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3133 if (ns != NULL) {
3134 xmlNodePtr root = ret;
3135
3136 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003137 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003138 }
3139 } else {
3140 /*
3141 * reference the existing namespace definition in our own tree.
3142 */
3143 ret->ns = ns;
3144 }
3145 }
3146 if (node->properties != NULL)
3147 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003148 if (node->type == XML_ENTITY_REF_NODE) {
3149 if ((doc == NULL) || (node->doc != doc)) {
3150 /*
3151 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003152 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003153 * we cannot keep the reference. Try to find it in the
3154 * target document.
3155 */
3156 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3157 } else {
3158 ret->children = node->children;
3159 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003160 ret->last = ret->children;
3161 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003162 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003163 UPDATE_LAST_CHILD_AND_PARENT(ret)
3164 }
Owen Taylor3473f882001-02-23 17:55:21 +00003165 return(ret);
3166}
3167
3168static xmlNodePtr
3169xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3170 xmlNodePtr ret = NULL;
3171 xmlNodePtr p = NULL,q;
3172
3173 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003174 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003175 if (doc == NULL) {
3176 node = node->next;
3177 continue;
3178 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003179 if (doc->intSubset == NULL) {
3180 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3181 q->doc = doc;
3182 q->parent = parent;
3183 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003184 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003185 } else {
3186 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003187 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003188 }
3189 } else
3190 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003191 if (ret == NULL) {
3192 q->prev = NULL;
3193 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003194 } else if (p != q) {
3195 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003196 p->next = q;
3197 q->prev = p;
3198 p = q;
3199 }
3200 node = node->next;
3201 }
3202 return(ret);
3203}
3204
3205/**
3206 * xmlCopyNode:
3207 * @node: the node
3208 * @recursive: if 1 do a recursive copy.
3209 *
3210 * Do a copy of the node.
3211 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003212 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003213 */
3214xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003215xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003216 xmlNodePtr ret;
3217
3218 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3219 return(ret);
3220}
3221
3222/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003223 * xmlDocCopyNode:
3224 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003225 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003226 * @recursive: if 1 do a recursive copy.
3227 *
3228 * Do a copy of the node to a given document.
3229 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003230 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003231 */
3232xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003233xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003234 xmlNodePtr ret;
3235
3236 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3237 return(ret);
3238}
3239
3240/**
Owen Taylor3473f882001-02-23 17:55:21 +00003241 * xmlCopyNodeList:
3242 * @node: the first node in the list.
3243 *
3244 * Do a recursive copy of the node list.
3245 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003246 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003247 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003248xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003249 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3250 return(ret);
3251}
3252
3253/**
Owen Taylor3473f882001-02-23 17:55:21 +00003254 * xmlCopyDtd:
3255 * @dtd: the dtd
3256 *
3257 * Do a copy of the dtd.
3258 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003259 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003260 */
3261xmlDtdPtr
3262xmlCopyDtd(xmlDtdPtr dtd) {
3263 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003264 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003265
3266 if (dtd == NULL) return(NULL);
3267 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3268 if (ret == NULL) return(NULL);
3269 if (dtd->entities != NULL)
3270 ret->entities = (void *) xmlCopyEntitiesTable(
3271 (xmlEntitiesTablePtr) dtd->entities);
3272 if (dtd->notations != NULL)
3273 ret->notations = (void *) xmlCopyNotationTable(
3274 (xmlNotationTablePtr) dtd->notations);
3275 if (dtd->elements != NULL)
3276 ret->elements = (void *) xmlCopyElementTable(
3277 (xmlElementTablePtr) dtd->elements);
3278 if (dtd->attributes != NULL)
3279 ret->attributes = (void *) xmlCopyAttributeTable(
3280 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003281 if (dtd->pentities != NULL)
3282 ret->pentities = (void *) xmlCopyEntitiesTable(
3283 (xmlEntitiesTablePtr) dtd->pentities);
3284
3285 cur = dtd->children;
3286 while (cur != NULL) {
3287 q = NULL;
3288
3289 if (cur->type == XML_ENTITY_DECL) {
3290 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3291 switch (tmp->etype) {
3292 case XML_INTERNAL_GENERAL_ENTITY:
3293 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3294 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3295 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3296 break;
3297 case XML_INTERNAL_PARAMETER_ENTITY:
3298 case XML_EXTERNAL_PARAMETER_ENTITY:
3299 q = (xmlNodePtr)
3300 xmlGetParameterEntityFromDtd(ret, tmp->name);
3301 break;
3302 case XML_INTERNAL_PREDEFINED_ENTITY:
3303 break;
3304 }
3305 } else if (cur->type == XML_ELEMENT_DECL) {
3306 xmlElementPtr tmp = (xmlElementPtr) cur;
3307 q = (xmlNodePtr)
3308 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3309 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3310 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3311 q = (xmlNodePtr)
3312 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3313 } else if (cur->type == XML_COMMENT_NODE) {
3314 q = xmlCopyNode(cur, 0);
3315 }
3316
3317 if (q == NULL) {
3318 cur = cur->next;
3319 continue;
3320 }
3321
3322 if (p == NULL)
3323 ret->children = q;
3324 else
3325 p->next = q;
3326
3327 q->prev = p;
3328 q->parent = (xmlNodePtr) ret;
3329 q->next = NULL;
3330 ret->last = q;
3331 p = q;
3332 cur = cur->next;
3333 }
3334
Owen Taylor3473f882001-02-23 17:55:21 +00003335 return(ret);
3336}
3337
3338/**
3339 * xmlCopyDoc:
3340 * @doc: the document
3341 * @recursive: if 1 do a recursive copy.
3342 *
3343 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003344 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003345 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003346 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003347 */
3348xmlDocPtr
3349xmlCopyDoc(xmlDocPtr doc, int recursive) {
3350 xmlDocPtr ret;
3351
3352 if (doc == NULL) return(NULL);
3353 ret = xmlNewDoc(doc->version);
3354 if (ret == NULL) return(NULL);
3355 if (doc->name != NULL)
3356 ret->name = xmlMemStrdup(doc->name);
3357 if (doc->encoding != NULL)
3358 ret->encoding = xmlStrdup(doc->encoding);
3359 ret->charset = doc->charset;
3360 ret->compression = doc->compression;
3361 ret->standalone = doc->standalone;
3362 if (!recursive) return(ret);
3363
Daniel Veillardb33c2012001-04-25 12:59:04 +00003364 ret->last = NULL;
3365 ret->children = NULL;
3366 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003367 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003368 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003369 ret->intSubset->parent = ret;
3370 }
Owen Taylor3473f882001-02-23 17:55:21 +00003371 if (doc->oldNs != NULL)
3372 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3373 if (doc->children != NULL) {
3374 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003375
3376 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3377 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003378 ret->last = NULL;
3379 tmp = ret->children;
3380 while (tmp != NULL) {
3381 if (tmp->next == NULL)
3382 ret->last = tmp;
3383 tmp = tmp->next;
3384 }
3385 }
3386 return(ret);
3387}
3388
3389/************************************************************************
3390 * *
3391 * Content access functions *
3392 * *
3393 ************************************************************************/
3394
3395/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003396 * xmlGetLineNo:
3397 * @node : valid node
3398 *
3399 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003400 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003401 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003402 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003403 */
3404long
3405xmlGetLineNo(xmlNodePtr node)
3406{
3407 long result = -1;
3408
3409 if (!node)
3410 return result;
3411 if (node->type == XML_ELEMENT_NODE)
3412 result = (long) node->content;
3413 else if ((node->prev != NULL) &&
3414 ((node->prev->type == XML_ELEMENT_NODE) ||
3415 (node->prev->type == XML_TEXT_NODE)))
3416 result = xmlGetLineNo(node->prev);
3417 else if ((node->parent != NULL) &&
3418 ((node->parent->type == XML_ELEMENT_NODE) ||
3419 (node->parent->type == XML_TEXT_NODE)))
3420 result = xmlGetLineNo(node->parent);
3421
3422 return result;
3423}
3424
3425/**
3426 * xmlGetNodePath:
3427 * @node: a node
3428 *
3429 * Build a structure based Path for the given node
3430 *
3431 * Returns the new path or NULL in case of error. The caller must free
3432 * the returned string
3433 */
3434xmlChar *
3435xmlGetNodePath(xmlNodePtr node)
3436{
3437 xmlNodePtr cur, tmp, next;
3438 xmlChar *buffer = NULL, *temp;
3439 size_t buf_len;
3440 xmlChar *buf;
3441 char sep;
3442 const char *name;
3443 char nametemp[100];
3444 int occur = 0;
3445
3446 if (node == NULL)
3447 return (NULL);
3448
3449 buf_len = 500;
3450 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3451 if (buffer == NULL)
3452 return (NULL);
3453 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3454 if (buf == NULL) {
3455 xmlFree(buffer);
3456 return (NULL);
3457 }
3458
3459 buffer[0] = 0;
3460 cur = node;
3461 do {
3462 name = "";
3463 sep = '?';
3464 occur = 0;
3465 if ((cur->type == XML_DOCUMENT_NODE) ||
3466 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3467 if (buffer[0] == '/')
3468 break;
3469 sep = '/';
3470 next = NULL;
3471 } else if (cur->type == XML_ELEMENT_NODE) {
3472 sep = '/';
3473 name = (const char *) cur->name;
3474 if (cur->ns) {
3475 snprintf(nametemp, sizeof(nametemp) - 1,
3476 "%s:%s", cur->ns->prefix, cur->name);
3477 nametemp[sizeof(nametemp) - 1] = 0;
3478 name = nametemp;
3479 }
3480 next = cur->parent;
3481
3482 /*
3483 * Thumbler index computation
3484 */
3485 tmp = cur->prev;
3486 while (tmp != NULL) {
3487 if (xmlStrEqual(cur->name, tmp->name))
3488 occur++;
3489 tmp = tmp->prev;
3490 }
3491 if (occur == 0) {
3492 tmp = cur->next;
3493 while (tmp != NULL) {
3494 if (xmlStrEqual(cur->name, tmp->name))
3495 occur++;
3496 tmp = tmp->next;
3497 }
3498 if (occur != 0)
3499 occur = 1;
3500 } else
3501 occur++;
3502 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3503 sep = '@';
3504 name = (const char *) (((xmlAttrPtr) cur)->name);
3505 next = ((xmlAttrPtr) cur)->parent;
3506 } else {
3507 next = cur->parent;
3508 }
3509
3510 /*
3511 * Make sure there is enough room
3512 */
3513 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3514 buf_len =
3515 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3516 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3517 if (temp == NULL) {
3518 xmlFree(buf);
3519 xmlFree(buffer);
3520 return (NULL);
3521 }
3522 buffer = temp;
3523 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3524 if (temp == NULL) {
3525 xmlFree(buf);
3526 xmlFree(buffer);
3527 return (NULL);
3528 }
3529 buf = temp;
3530 }
3531 if (occur == 0)
3532 snprintf((char *) buf, buf_len, "%c%s%s",
3533 sep, name, (char *) buffer);
3534 else
3535 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3536 sep, name, occur, (char *) buffer);
3537 snprintf((char *) buffer, buf_len, "%s", buf);
3538 cur = next;
3539 } while (cur != NULL);
3540 xmlFree(buf);
3541 return (buffer);
3542}
3543
3544/**
Owen Taylor3473f882001-02-23 17:55:21 +00003545 * xmlDocGetRootElement:
3546 * @doc: the document
3547 *
3548 * Get the root element of the document (doc->children is a list
3549 * containing possibly comments, PIs, etc ...).
3550 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003551 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003552 */
3553xmlNodePtr
3554xmlDocGetRootElement(xmlDocPtr doc) {
3555 xmlNodePtr ret;
3556
3557 if (doc == NULL) return(NULL);
3558 ret = doc->children;
3559 while (ret != NULL) {
3560 if (ret->type == XML_ELEMENT_NODE)
3561 return(ret);
3562 ret = ret->next;
3563 }
3564 return(ret);
3565}
3566
3567/**
3568 * xmlDocSetRootElement:
3569 * @doc: the document
3570 * @root: the new document root element
3571 *
3572 * Set the root element of the document (doc->children is a list
3573 * containing possibly comments, PIs, etc ...).
3574 *
3575 * Returns the old root element if any was found
3576 */
3577xmlNodePtr
3578xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3579 xmlNodePtr old = NULL;
3580
3581 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003582 if (root == NULL)
3583 return(NULL);
3584 xmlUnlinkNode(root);
3585 root->doc = doc;
3586 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003587 old = doc->children;
3588 while (old != NULL) {
3589 if (old->type == XML_ELEMENT_NODE)
3590 break;
3591 old = old->next;
3592 }
3593 if (old == NULL) {
3594 if (doc->children == NULL) {
3595 doc->children = root;
3596 doc->last = root;
3597 } else {
3598 xmlAddSibling(doc->children, root);
3599 }
3600 } else {
3601 xmlReplaceNode(old, root);
3602 }
3603 return(old);
3604}
3605
3606/**
3607 * xmlNodeSetLang:
3608 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003609 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003610 *
3611 * Set the language of a node, i.e. the values of the xml:lang
3612 * attribute.
3613 */
3614void
3615xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003616 xmlNsPtr ns;
3617
Owen Taylor3473f882001-02-23 17:55:21 +00003618 if (cur == NULL) return;
3619 switch(cur->type) {
3620 case XML_TEXT_NODE:
3621 case XML_CDATA_SECTION_NODE:
3622 case XML_COMMENT_NODE:
3623 case XML_DOCUMENT_NODE:
3624 case XML_DOCUMENT_TYPE_NODE:
3625 case XML_DOCUMENT_FRAG_NODE:
3626 case XML_NOTATION_NODE:
3627 case XML_HTML_DOCUMENT_NODE:
3628 case XML_DTD_NODE:
3629 case XML_ELEMENT_DECL:
3630 case XML_ATTRIBUTE_DECL:
3631 case XML_ENTITY_DECL:
3632 case XML_PI_NODE:
3633 case XML_ENTITY_REF_NODE:
3634 case XML_ENTITY_NODE:
3635 case XML_NAMESPACE_DECL:
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 case XML_XINCLUDE_START:
3640 case XML_XINCLUDE_END:
3641 return;
3642 case XML_ELEMENT_NODE:
3643 case XML_ATTRIBUTE_NODE:
3644 break;
3645 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003646 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3647 if (ns == NULL)
3648 return;
3649 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003650}
3651
3652/**
3653 * xmlNodeGetLang:
3654 * @cur: the node being checked
3655 *
3656 * Searches the language of a node, i.e. the values of the xml:lang
3657 * attribute or the one carried by the nearest ancestor.
3658 *
3659 * Returns a pointer to the lang value, or NULL if not found
3660 * It's up to the caller to free the memory.
3661 */
3662xmlChar *
3663xmlNodeGetLang(xmlNodePtr cur) {
3664 xmlChar *lang;
3665
3666 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003667 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003668 if (lang != NULL)
3669 return(lang);
3670 cur = cur->parent;
3671 }
3672 return(NULL);
3673}
3674
3675
3676/**
3677 * xmlNodeSetSpacePreserve:
3678 * @cur: the node being changed
3679 * @val: the xml:space value ("0": default, 1: "preserve")
3680 *
3681 * Set (or reset) the space preserving behaviour of a node, i.e. the
3682 * value of the xml:space attribute.
3683 */
3684void
3685xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003686 xmlNsPtr ns;
3687
Owen Taylor3473f882001-02-23 17:55:21 +00003688 if (cur == NULL) return;
3689 switch(cur->type) {
3690 case XML_TEXT_NODE:
3691 case XML_CDATA_SECTION_NODE:
3692 case XML_COMMENT_NODE:
3693 case XML_DOCUMENT_NODE:
3694 case XML_DOCUMENT_TYPE_NODE:
3695 case XML_DOCUMENT_FRAG_NODE:
3696 case XML_NOTATION_NODE:
3697 case XML_HTML_DOCUMENT_NODE:
3698 case XML_DTD_NODE:
3699 case XML_ELEMENT_DECL:
3700 case XML_ATTRIBUTE_DECL:
3701 case XML_ENTITY_DECL:
3702 case XML_PI_NODE:
3703 case XML_ENTITY_REF_NODE:
3704 case XML_ENTITY_NODE:
3705 case XML_NAMESPACE_DECL:
3706 case XML_XINCLUDE_START:
3707 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003708#ifdef LIBXML_DOCB_ENABLED
3709 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003710#endif
3711 return;
3712 case XML_ELEMENT_NODE:
3713 case XML_ATTRIBUTE_NODE:
3714 break;
3715 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003716 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3717 if (ns == NULL)
3718 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003719 switch (val) {
3720 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003721 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003722 break;
3723 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003724 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003725 break;
3726 }
3727}
3728
3729/**
3730 * xmlNodeGetSpacePreserve:
3731 * @cur: the node being checked
3732 *
3733 * Searches the space preserving behaviour of a node, i.e. the values
3734 * of the xml:space attribute or the one carried by the nearest
3735 * ancestor.
3736 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003737 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003738 */
3739int
3740xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3741 xmlChar *space;
3742
3743 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003744 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003745 if (space != NULL) {
3746 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3747 xmlFree(space);
3748 return(1);
3749 }
3750 if (xmlStrEqual(space, BAD_CAST "default")) {
3751 xmlFree(space);
3752 return(0);
3753 }
3754 xmlFree(space);
3755 }
3756 cur = cur->parent;
3757 }
3758 return(-1);
3759}
3760
3761/**
3762 * xmlNodeSetName:
3763 * @cur: the node being changed
3764 * @name: the new tag name
3765 *
3766 * Set (or reset) the name of a node.
3767 */
3768void
3769xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3770 if (cur == NULL) return;
3771 if (name == NULL) return;
3772 switch(cur->type) {
3773 case XML_TEXT_NODE:
3774 case XML_CDATA_SECTION_NODE:
3775 case XML_COMMENT_NODE:
3776 case XML_DOCUMENT_TYPE_NODE:
3777 case XML_DOCUMENT_FRAG_NODE:
3778 case XML_NOTATION_NODE:
3779 case XML_HTML_DOCUMENT_NODE:
3780 case XML_NAMESPACE_DECL:
3781 case XML_XINCLUDE_START:
3782 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003783#ifdef LIBXML_DOCB_ENABLED
3784 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003785#endif
3786 return;
3787 case XML_ELEMENT_NODE:
3788 case XML_ATTRIBUTE_NODE:
3789 case XML_PI_NODE:
3790 case XML_ENTITY_REF_NODE:
3791 case XML_ENTITY_NODE:
3792 case XML_DTD_NODE:
3793 case XML_DOCUMENT_NODE:
3794 case XML_ELEMENT_DECL:
3795 case XML_ATTRIBUTE_DECL:
3796 case XML_ENTITY_DECL:
3797 break;
3798 }
3799 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3800 cur->name = xmlStrdup(name);
3801}
3802
3803/**
3804 * xmlNodeSetBase:
3805 * @cur: the node being changed
3806 * @uri: the new base URI
3807 *
3808 * Set (or reset) the base URI of a node, i.e. the value of the
3809 * xml:base attribute.
3810 */
3811void
3812xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003813 xmlNsPtr ns;
3814
Owen Taylor3473f882001-02-23 17:55:21 +00003815 if (cur == NULL) return;
3816 switch(cur->type) {
3817 case XML_TEXT_NODE:
3818 case XML_CDATA_SECTION_NODE:
3819 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003820 case XML_DOCUMENT_TYPE_NODE:
3821 case XML_DOCUMENT_FRAG_NODE:
3822 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003823 case XML_DTD_NODE:
3824 case XML_ELEMENT_DECL:
3825 case XML_ATTRIBUTE_DECL:
3826 case XML_ENTITY_DECL:
3827 case XML_PI_NODE:
3828 case XML_ENTITY_REF_NODE:
3829 case XML_ENTITY_NODE:
3830 case XML_NAMESPACE_DECL:
3831 case XML_XINCLUDE_START:
3832 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003833 return;
3834 case XML_ELEMENT_NODE:
3835 case XML_ATTRIBUTE_NODE:
3836 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003837 case XML_DOCUMENT_NODE:
3838#ifdef LIBXML_DOCB_ENABLED
3839 case XML_DOCB_DOCUMENT_NODE:
3840#endif
3841 case XML_HTML_DOCUMENT_NODE: {
3842 xmlDocPtr doc = (xmlDocPtr) cur;
3843
3844 if (doc->URL != NULL)
3845 xmlFree((xmlChar *) doc->URL);
3846 if (uri == NULL)
3847 doc->URL = NULL;
3848 else
3849 doc->URL = xmlStrdup(uri);
3850 return;
3851 }
Owen Taylor3473f882001-02-23 17:55:21 +00003852 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003853
3854 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3855 if (ns == NULL)
3856 return;
3857 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003858}
3859
3860/**
Owen Taylor3473f882001-02-23 17:55:21 +00003861 * xmlNodeGetBase:
3862 * @doc: the document the node pertains to
3863 * @cur: the node being checked
3864 *
3865 * Searches for the BASE URL. The code should work on both XML
3866 * and HTML document even if base mechanisms are completely different.
3867 * It returns the base as defined in RFC 2396 sections
3868 * 5.1.1. Base URI within Document Content
3869 * and
3870 * 5.1.2. Base URI from the Encapsulating Entity
3871 * However it does not return the document base (5.1.3), use
3872 * xmlDocumentGetBase() for this
3873 *
3874 * Returns a pointer to the base URL, or NULL if not found
3875 * It's up to the caller to free the memory.
3876 */
3877xmlChar *
3878xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003879 xmlChar *oldbase = NULL;
3880 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003881
3882 if ((cur == NULL) && (doc == NULL))
3883 return(NULL);
3884 if (doc == NULL) doc = cur->doc;
3885 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3886 cur = doc->children;
3887 while ((cur != NULL) && (cur->name != NULL)) {
3888 if (cur->type != XML_ELEMENT_NODE) {
3889 cur = cur->next;
3890 continue;
3891 }
3892 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3893 cur = cur->children;
3894 continue;
3895 }
3896 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3897 cur = cur->children;
3898 continue;
3899 }
3900 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3901 return(xmlGetProp(cur, BAD_CAST "href"));
3902 }
3903 cur = cur->next;
3904 }
3905 return(NULL);
3906 }
3907 while (cur != NULL) {
3908 if (cur->type == XML_ENTITY_DECL) {
3909 xmlEntityPtr ent = (xmlEntityPtr) cur;
3910 return(xmlStrdup(ent->URI));
3911 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003912 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003913 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003914 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003915 if (oldbase != NULL) {
3916 newbase = xmlBuildURI(oldbase, base);
3917 if (newbase != NULL) {
3918 xmlFree(oldbase);
3919 xmlFree(base);
3920 oldbase = newbase;
3921 } else {
3922 xmlFree(oldbase);
3923 xmlFree(base);
3924 return(NULL);
3925 }
3926 } else {
3927 oldbase = base;
3928 }
3929 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3930 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3931 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3932 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003933 }
3934 }
Owen Taylor3473f882001-02-23 17:55:21 +00003935 cur = cur->parent;
3936 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003937 if ((doc != NULL) && (doc->URL != NULL)) {
3938 if (oldbase == NULL)
3939 return(xmlStrdup(doc->URL));
3940 newbase = xmlBuildURI(oldbase, doc->URL);
3941 xmlFree(oldbase);
3942 return(newbase);
3943 }
3944 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003945}
3946
3947/**
3948 * xmlNodeGetContent:
3949 * @cur: the node being read
3950 *
3951 * Read the value of a node, this can be either the text carried
3952 * directly by this node if it's a TEXT node or the aggregate string
3953 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003954 * Entity references are substituted.
3955 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003956 * It's up to the caller to free the memory.
3957 */
3958xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00003959xmlNodeGetContent(xmlNodePtr cur)
3960{
3961 if (cur == NULL)
3962 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003963 switch (cur->type) {
3964 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003965 case XML_ELEMENT_NODE:{
3966 xmlNodePtr tmp = cur;
3967 xmlBufferPtr buffer;
3968 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003969
Daniel Veillard7646b182002-04-20 06:41:40 +00003970 buffer = xmlBufferCreate();
3971 if (buffer == NULL)
3972 return (NULL);
3973 while (tmp != NULL) {
3974 switch (tmp->type) {
3975 case XML_CDATA_SECTION_NODE:
3976 case XML_TEXT_NODE:
3977 if (tmp->content != NULL)
3978 xmlBufferCat(buffer, tmp->content);
3979 break;
3980 case XML_ENTITY_REF_NODE:{
3981 /* recursive substitution of entity references */
3982 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003983
Daniel Veillard7646b182002-04-20 06:41:40 +00003984 if (cont) {
3985 xmlBufferCat(buffer,
3986 (const xmlChar *) cont);
3987 xmlFree(cont);
3988 }
3989 break;
3990 }
3991 default:
3992 break;
3993 }
3994 /*
3995 * Skip to next node
3996 */
3997 if (tmp->children != NULL) {
3998 if (tmp->children->type != XML_ENTITY_DECL) {
3999 tmp = tmp->children;
4000 continue;
4001 }
4002 }
4003 if (tmp == cur)
4004 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004005
Daniel Veillard7646b182002-04-20 06:41:40 +00004006 if (tmp->next != NULL) {
4007 tmp = tmp->next;
4008 continue;
4009 }
4010
4011 do {
4012 tmp = tmp->parent;
4013 if (tmp == NULL)
4014 break;
4015 if (tmp == cur) {
4016 tmp = NULL;
4017 break;
4018 }
4019 if (tmp->next != NULL) {
4020 tmp = tmp->next;
4021 break;
4022 }
4023 } while (tmp != NULL);
4024 }
4025 ret = buffer->content;
4026 buffer->content = NULL;
4027 xmlBufferFree(buffer);
4028 return (ret);
4029 }
4030 case XML_ATTRIBUTE_NODE:{
4031 xmlAttrPtr attr = (xmlAttrPtr) cur;
4032
4033 if (attr->parent != NULL)
4034 return (xmlNodeListGetString
4035 (attr->parent->doc, attr->children, 1));
4036 else
4037 return (xmlNodeListGetString(NULL, attr->children, 1));
4038 break;
4039 }
Owen Taylor3473f882001-02-23 17:55:21 +00004040 case XML_COMMENT_NODE:
4041 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004042 if (cur->content != NULL)
4043 return (xmlStrdup(cur->content));
4044 return (NULL);
4045 case XML_ENTITY_REF_NODE:{
4046 xmlEntityPtr ent;
4047 xmlNodePtr tmp;
4048 xmlBufferPtr buffer;
4049 xmlChar *ret;
4050
4051 /* lookup entity declaration */
4052 ent = xmlGetDocEntity(cur->doc, cur->name);
4053 if (ent == NULL)
4054 return (NULL);
4055
4056 buffer = xmlBufferCreate();
4057 if (buffer == NULL)
4058 return (NULL);
4059
4060 /* an entity content can be any "well balanced chunk",
4061 * i.e. the result of the content [43] production:
4062 * http://www.w3.org/TR/REC-xml#NT-content
4063 * -> we iterate through child nodes and recursive call
4064 * xmlNodeGetContent() which handles all possible node types */
4065 tmp = ent->children;
4066 while (tmp) {
4067 xmlChar *cont = xmlNodeGetContent(tmp);
4068
4069 if (cont) {
4070 xmlBufferCat(buffer, (const xmlChar *) cont);
4071 xmlFree(cont);
4072 }
4073 tmp = tmp->next;
4074 }
4075
4076 ret = buffer->content;
4077 buffer->content = NULL;
4078 xmlBufferFree(buffer);
4079 return (ret);
4080 }
Owen Taylor3473f882001-02-23 17:55:21 +00004081 case XML_ENTITY_NODE:
4082 case XML_DOCUMENT_NODE:
4083 case XML_HTML_DOCUMENT_NODE:
4084 case XML_DOCUMENT_TYPE_NODE:
4085 case XML_NOTATION_NODE:
4086 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004087 case XML_XINCLUDE_START:
4088 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004089#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004090 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004091#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004092 return (NULL);
4093 case XML_NAMESPACE_DECL:
4094 return (xmlStrdup(((xmlNsPtr) cur)->href));
Owen Taylor3473f882001-02-23 17:55:21 +00004095 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004096 /* TODO !!! */
4097 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004098 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004099 /* TODO !!! */
4100 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004101 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004102 /* TODO !!! */
4103 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004104 case XML_CDATA_SECTION_NODE:
4105 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004106 if (cur->content != NULL)
4107 return (xmlStrdup(cur->content));
4108 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004109 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004110 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004111}
Owen Taylor3473f882001-02-23 17:55:21 +00004112/**
4113 * xmlNodeSetContent:
4114 * @cur: the node being modified
4115 * @content: the new value of the content
4116 *
4117 * Replace the content of a node.
4118 */
4119void
4120xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4121 if (cur == NULL) {
4122#ifdef DEBUG_TREE
4123 xmlGenericError(xmlGenericErrorContext,
4124 "xmlNodeSetContent : node == NULL\n");
4125#endif
4126 return;
4127 }
4128 switch (cur->type) {
4129 case XML_DOCUMENT_FRAG_NODE:
4130 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004131 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004132 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4133 cur->children = xmlStringGetNodeList(cur->doc, content);
4134 UPDATE_LAST_CHILD_AND_PARENT(cur)
4135 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004136 case XML_TEXT_NODE:
4137 case XML_CDATA_SECTION_NODE:
4138 case XML_ENTITY_REF_NODE:
4139 case XML_ENTITY_NODE:
4140 case XML_PI_NODE:
4141 case XML_COMMENT_NODE:
4142 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004143 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004144 }
4145 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4146 cur->last = cur->children = NULL;
4147 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004148 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004149 } else
4150 cur->content = NULL;
4151 break;
4152 case XML_DOCUMENT_NODE:
4153 case XML_HTML_DOCUMENT_NODE:
4154 case XML_DOCUMENT_TYPE_NODE:
4155 case XML_XINCLUDE_START:
4156 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004157#ifdef LIBXML_DOCB_ENABLED
4158 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004159#endif
4160 break;
4161 case XML_NOTATION_NODE:
4162 break;
4163 case XML_DTD_NODE:
4164 break;
4165 case XML_NAMESPACE_DECL:
4166 break;
4167 case XML_ELEMENT_DECL:
4168 /* TODO !!! */
4169 break;
4170 case XML_ATTRIBUTE_DECL:
4171 /* TODO !!! */
4172 break;
4173 case XML_ENTITY_DECL:
4174 /* TODO !!! */
4175 break;
4176 }
4177}
4178
4179/**
4180 * xmlNodeSetContentLen:
4181 * @cur: the node being modified
4182 * @content: the new value of the content
4183 * @len: the size of @content
4184 *
4185 * Replace the content of a node.
4186 */
4187void
4188xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4189 if (cur == NULL) {
4190#ifdef DEBUG_TREE
4191 xmlGenericError(xmlGenericErrorContext,
4192 "xmlNodeSetContentLen : node == NULL\n");
4193#endif
4194 return;
4195 }
4196 switch (cur->type) {
4197 case XML_DOCUMENT_FRAG_NODE:
4198 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004199 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004200 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4201 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4202 UPDATE_LAST_CHILD_AND_PARENT(cur)
4203 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004204 case XML_TEXT_NODE:
4205 case XML_CDATA_SECTION_NODE:
4206 case XML_ENTITY_REF_NODE:
4207 case XML_ENTITY_NODE:
4208 case XML_PI_NODE:
4209 case XML_COMMENT_NODE:
4210 case XML_NOTATION_NODE:
4211 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004212 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004213 }
4214 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4215 cur->children = cur->last = NULL;
4216 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004217 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004218 } else
4219 cur->content = NULL;
4220 break;
4221 case XML_DOCUMENT_NODE:
4222 case XML_DTD_NODE:
4223 case XML_HTML_DOCUMENT_NODE:
4224 case XML_DOCUMENT_TYPE_NODE:
4225 case XML_NAMESPACE_DECL:
4226 case XML_XINCLUDE_START:
4227 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004228#ifdef LIBXML_DOCB_ENABLED
4229 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004230#endif
4231 break;
4232 case XML_ELEMENT_DECL:
4233 /* TODO !!! */
4234 break;
4235 case XML_ATTRIBUTE_DECL:
4236 /* TODO !!! */
4237 break;
4238 case XML_ENTITY_DECL:
4239 /* TODO !!! */
4240 break;
4241 }
4242}
4243
4244/**
4245 * xmlNodeAddContentLen:
4246 * @cur: the node being modified
4247 * @content: extra content
4248 * @len: the size of @content
4249 *
4250 * Append the extra substring to the node content.
4251 */
4252void
4253xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4254 if (cur == NULL) {
4255#ifdef DEBUG_TREE
4256 xmlGenericError(xmlGenericErrorContext,
4257 "xmlNodeAddContentLen : node == NULL\n");
4258#endif
4259 return;
4260 }
4261 if (len <= 0) return;
4262 switch (cur->type) {
4263 case XML_DOCUMENT_FRAG_NODE:
4264 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004265 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004266
Daniel Veillard7db37732001-07-12 01:20:08 +00004267 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004268 newNode = xmlNewTextLen(content, len);
4269 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004270 tmp = xmlAddChild(cur, newNode);
4271 if (tmp != newNode)
4272 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004273 if ((last != NULL) && (last->next == newNode)) {
4274 xmlTextMerge(last, newNode);
4275 }
4276 }
4277 break;
4278 }
4279 case XML_ATTRIBUTE_NODE:
4280 break;
4281 case XML_TEXT_NODE:
4282 case XML_CDATA_SECTION_NODE:
4283 case XML_ENTITY_REF_NODE:
4284 case XML_ENTITY_NODE:
4285 case XML_PI_NODE:
4286 case XML_COMMENT_NODE:
4287 case XML_NOTATION_NODE:
4288 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004289 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004290 }
4291 case XML_DOCUMENT_NODE:
4292 case XML_DTD_NODE:
4293 case XML_HTML_DOCUMENT_NODE:
4294 case XML_DOCUMENT_TYPE_NODE:
4295 case XML_NAMESPACE_DECL:
4296 case XML_XINCLUDE_START:
4297 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004298#ifdef LIBXML_DOCB_ENABLED
4299 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004300#endif
4301 break;
4302 case XML_ELEMENT_DECL:
4303 case XML_ATTRIBUTE_DECL:
4304 case XML_ENTITY_DECL:
4305 break;
4306 }
4307}
4308
4309/**
4310 * xmlNodeAddContent:
4311 * @cur: the node being modified
4312 * @content: extra content
4313 *
4314 * Append the extra substring to the node content.
4315 */
4316void
4317xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4318 int len;
4319
4320 if (cur == NULL) {
4321#ifdef DEBUG_TREE
4322 xmlGenericError(xmlGenericErrorContext,
4323 "xmlNodeAddContent : node == NULL\n");
4324#endif
4325 return;
4326 }
4327 if (content == NULL) return;
4328 len = xmlStrlen(content);
4329 xmlNodeAddContentLen(cur, content, len);
4330}
4331
4332/**
4333 * xmlTextMerge:
4334 * @first: the first text node
4335 * @second: the second text node being merged
4336 *
4337 * Merge two text nodes into one
4338 * Returns the first text node augmented
4339 */
4340xmlNodePtr
4341xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4342 if (first == NULL) return(second);
4343 if (second == NULL) return(first);
4344 if (first->type != XML_TEXT_NODE) return(first);
4345 if (second->type != XML_TEXT_NODE) return(first);
4346 if (second->name != first->name)
4347 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004348 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004349 xmlUnlinkNode(second);
4350 xmlFreeNode(second);
4351 return(first);
4352}
4353
4354/**
4355 * xmlGetNsList:
4356 * @doc: the document
4357 * @node: the current node
4358 *
4359 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004360 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004361 * that need to be freed by the caller or NULL if no
4362 * namespace if defined
4363 */
4364xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004365xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4366{
Owen Taylor3473f882001-02-23 17:55:21 +00004367 xmlNsPtr cur;
4368 xmlNsPtr *ret = NULL;
4369 int nbns = 0;
4370 int maxns = 10;
4371 int i;
4372
4373 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004374 if (node->type == XML_ELEMENT_NODE) {
4375 cur = node->nsDef;
4376 while (cur != NULL) {
4377 if (ret == NULL) {
4378 ret =
4379 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4380 sizeof(xmlNsPtr));
4381 if (ret == NULL) {
4382 xmlGenericError(xmlGenericErrorContext,
4383 "xmlGetNsList : out of memory!\n");
4384 return (NULL);
4385 }
4386 ret[nbns] = NULL;
4387 }
4388 for (i = 0; i < nbns; i++) {
4389 if ((cur->prefix == ret[i]->prefix) ||
4390 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4391 break;
4392 }
4393 if (i >= nbns) {
4394 if (nbns >= maxns) {
4395 maxns *= 2;
4396 ret = (xmlNsPtr *) xmlRealloc(ret,
4397 (maxns +
4398 1) *
4399 sizeof(xmlNsPtr));
4400 if (ret == NULL) {
4401 xmlGenericError(xmlGenericErrorContext,
4402 "xmlGetNsList : realloc failed!\n");
4403 return (NULL);
4404 }
4405 }
4406 ret[nbns++] = cur;
4407 ret[nbns] = NULL;
4408 }
Owen Taylor3473f882001-02-23 17:55:21 +00004409
Daniel Veillard77044732001-06-29 21:31:07 +00004410 cur = cur->next;
4411 }
4412 }
4413 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004414 }
Daniel Veillard77044732001-06-29 21:31:07 +00004415 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004416}
4417
4418/**
4419 * xmlSearchNs:
4420 * @doc: the document
4421 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004422 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004423 *
4424 * Search a Ns registered under a given name space for a document.
4425 * recurse on the parents until it finds the defined namespace
4426 * or return NULL otherwise.
4427 * @nameSpace can be NULL, this is a search for the default namespace.
4428 * We don't allow to cross entities boundaries. If you don't declare
4429 * the namespace within those you will be in troubles !!! A warning
4430 * is generated to cover this case.
4431 *
4432 * Returns the namespace pointer or NULL.
4433 */
4434xmlNsPtr
4435xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4436 xmlNsPtr cur;
4437
4438 if (node == NULL) return(NULL);
4439 if ((nameSpace != NULL) &&
4440 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004441 if (doc == NULL)
4442 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004443 if (doc->oldNs == NULL) {
4444 /*
4445 * Allocate a new Namespace and fill the fields.
4446 */
4447 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4448 if (doc->oldNs == NULL) {
4449 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004450 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004451 return(NULL);
4452 }
4453 memset(doc->oldNs, 0, sizeof(xmlNs));
4454 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4455
4456 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4457 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4458 }
4459 return(doc->oldNs);
4460 }
4461 while (node != NULL) {
4462 if ((node->type == XML_ENTITY_REF_NODE) ||
4463 (node->type == XML_ENTITY_NODE) ||
4464 (node->type == XML_ENTITY_DECL))
4465 return(NULL);
4466 if (node->type == XML_ELEMENT_NODE) {
4467 cur = node->nsDef;
4468 while (cur != NULL) {
4469 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4470 (cur->href != NULL))
4471 return(cur);
4472 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4473 (cur->href != NULL) &&
4474 (xmlStrEqual(cur->prefix, nameSpace)))
4475 return(cur);
4476 cur = cur->next;
4477 }
4478 }
4479 node = node->parent;
4480 }
4481 return(NULL);
4482}
4483
4484/**
4485 * xmlSearchNsByHref:
4486 * @doc: the document
4487 * @node: the current node
4488 * @href: the namespace value
4489 *
4490 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4491 * the defined namespace or return NULL otherwise.
4492 * Returns the namespace pointer or NULL.
4493 */
4494xmlNsPtr
4495xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4496 xmlNsPtr cur;
4497 xmlNodePtr orig = node;
4498
4499 if ((node == NULL) || (href == NULL)) return(NULL);
4500 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004501 /*
4502 * Only the document can hold the XML spec namespace.
4503 */
4504 if (doc == NULL)
4505 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004506 if (doc->oldNs == NULL) {
4507 /*
4508 * Allocate a new Namespace and fill the fields.
4509 */
4510 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4511 if (doc->oldNs == NULL) {
4512 xmlGenericError(xmlGenericErrorContext,
4513 "xmlSearchNsByHref : malloc failed\n");
4514 return(NULL);
4515 }
4516 memset(doc->oldNs, 0, sizeof(xmlNs));
4517 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4518
4519 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4520 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4521 }
4522 return(doc->oldNs);
4523 }
4524 while (node != NULL) {
4525 cur = node->nsDef;
4526 while (cur != NULL) {
4527 if ((cur->href != NULL) && (href != NULL) &&
4528 (xmlStrEqual(cur->href, href))) {
4529 /*
4530 * Check that the prefix is not shadowed between orig and node
4531 */
4532 xmlNodePtr check = orig;
4533 xmlNsPtr tst;
4534
4535 while (check != node) {
4536 tst = check->nsDef;
4537 while (tst != NULL) {
4538 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4539 goto shadowed;
4540 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4541 (xmlStrEqual(tst->prefix, cur->prefix)))
4542 goto shadowed;
4543 tst = tst->next;
4544 }
4545 check = check->parent;
4546 }
4547 return(cur);
4548 }
4549shadowed:
4550 cur = cur->next;
4551 }
4552 node = node->parent;
4553 }
4554 return(NULL);
4555}
4556
4557/**
4558 * xmlNewReconciliedNs
4559 * @doc: the document
4560 * @tree: a node expected to hold the new namespace
4561 * @ns: the original namespace
4562 *
4563 * This function tries to locate a namespace definition in a tree
4564 * ancestors, or create a new namespace definition node similar to
4565 * @ns trying to reuse the same prefix. However if the given prefix is
4566 * null (default namespace) or reused within the subtree defined by
4567 * @tree or on one of its ancestors then a new prefix is generated.
4568 * Returns the (new) namespace definition or NULL in case of error
4569 */
4570xmlNsPtr
4571xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4572 xmlNsPtr def;
4573 xmlChar prefix[50];
4574 int counter = 1;
4575
4576 if (tree == NULL) {
4577#ifdef DEBUG_TREE
4578 xmlGenericError(xmlGenericErrorContext,
4579 "xmlNewReconciliedNs : tree == NULL\n");
4580#endif
4581 return(NULL);
4582 }
4583 if (ns == NULL) {
4584#ifdef DEBUG_TREE
4585 xmlGenericError(xmlGenericErrorContext,
4586 "xmlNewReconciliedNs : ns == NULL\n");
4587#endif
4588 return(NULL);
4589 }
4590 /*
4591 * Search an existing namespace definition inherited.
4592 */
4593 def = xmlSearchNsByHref(doc, tree, ns->href);
4594 if (def != NULL)
4595 return(def);
4596
4597 /*
4598 * Find a close prefix which is not already in use.
4599 * Let's strip namespace prefixes longer than 20 chars !
4600 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004601 if (ns->prefix == NULL)
4602 sprintf((char *) prefix, "default");
4603 else
4604 sprintf((char *) prefix, "%.20s", ns->prefix);
4605
Owen Taylor3473f882001-02-23 17:55:21 +00004606 def = xmlSearchNs(doc, tree, prefix);
4607 while (def != NULL) {
4608 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004609 if (ns->prefix == NULL)
4610 sprintf((char *) prefix, "default%d", counter++);
4611 else
4612 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004613 def = xmlSearchNs(doc, tree, prefix);
4614 }
4615
4616 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004617 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004618 */
4619 def = xmlNewNs(tree, ns->href, prefix);
4620 return(def);
4621}
4622
4623/**
4624 * xmlReconciliateNs
4625 * @doc: the document
4626 * @tree: a node defining the subtree to reconciliate
4627 *
4628 * This function checks that all the namespaces declared within the given
4629 * tree are properly declared. This is needed for example after Copy or Cut
4630 * and then paste operations. The subtree may still hold pointers to
4631 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004632 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004633 * the new environment. If not possible the new namespaces are redeclared
4634 * on @tree at the top of the given subtree.
4635 * Returns the number of namespace declarations created or -1 in case of error.
4636 */
4637int
4638xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4639 xmlNsPtr *oldNs = NULL;
4640 xmlNsPtr *newNs = NULL;
4641 int sizeCache = 0;
4642 int nbCache = 0;
4643
4644 xmlNsPtr n;
4645 xmlNodePtr node = tree;
4646 xmlAttrPtr attr;
4647 int ret = 0, i;
4648
4649 while (node != NULL) {
4650 /*
4651 * Reconciliate the node namespace
4652 */
4653 if (node->ns != NULL) {
4654 /*
4655 * initialize the cache if needed
4656 */
4657 if (sizeCache == 0) {
4658 sizeCache = 10;
4659 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4660 sizeof(xmlNsPtr));
4661 if (oldNs == NULL) {
4662 xmlGenericError(xmlGenericErrorContext,
4663 "xmlReconciliateNs : memory pbm\n");
4664 return(-1);
4665 }
4666 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4667 sizeof(xmlNsPtr));
4668 if (newNs == NULL) {
4669 xmlGenericError(xmlGenericErrorContext,
4670 "xmlReconciliateNs : memory pbm\n");
4671 xmlFree(oldNs);
4672 return(-1);
4673 }
4674 }
4675 for (i = 0;i < nbCache;i++) {
4676 if (oldNs[i] == node->ns) {
4677 node->ns = newNs[i];
4678 break;
4679 }
4680 }
4681 if (i == nbCache) {
4682 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004683 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004684 */
4685 n = xmlNewReconciliedNs(doc, tree, node->ns);
4686 if (n != NULL) { /* :-( what if else ??? */
4687 /*
4688 * check if we need to grow the cache buffers.
4689 */
4690 if (sizeCache <= nbCache) {
4691 sizeCache *= 2;
4692 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4693 sizeof(xmlNsPtr));
4694 if (oldNs == NULL) {
4695 xmlGenericError(xmlGenericErrorContext,
4696 "xmlReconciliateNs : memory pbm\n");
4697 xmlFree(newNs);
4698 return(-1);
4699 }
4700 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4701 sizeof(xmlNsPtr));
4702 if (newNs == NULL) {
4703 xmlGenericError(xmlGenericErrorContext,
4704 "xmlReconciliateNs : memory pbm\n");
4705 xmlFree(oldNs);
4706 return(-1);
4707 }
4708 }
4709 newNs[nbCache] = n;
4710 oldNs[nbCache++] = node->ns;
4711 node->ns = n;
4712 }
4713 }
4714 }
4715 /*
4716 * now check for namespace hold by attributes on the node.
4717 */
4718 attr = node->properties;
4719 while (attr != NULL) {
4720 if (attr->ns != NULL) {
4721 /*
4722 * initialize the cache if needed
4723 */
4724 if (sizeCache == 0) {
4725 sizeCache = 10;
4726 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4727 sizeof(xmlNsPtr));
4728 if (oldNs == NULL) {
4729 xmlGenericError(xmlGenericErrorContext,
4730 "xmlReconciliateNs : memory pbm\n");
4731 return(-1);
4732 }
4733 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4734 sizeof(xmlNsPtr));
4735 if (newNs == NULL) {
4736 xmlGenericError(xmlGenericErrorContext,
4737 "xmlReconciliateNs : memory pbm\n");
4738 xmlFree(oldNs);
4739 return(-1);
4740 }
4741 }
4742 for (i = 0;i < nbCache;i++) {
4743 if (oldNs[i] == attr->ns) {
4744 node->ns = newNs[i];
4745 break;
4746 }
4747 }
4748 if (i == nbCache) {
4749 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004750 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004751 */
4752 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4753 if (n != NULL) { /* :-( what if else ??? */
4754 /*
4755 * check if we need to grow the cache buffers.
4756 */
4757 if (sizeCache <= nbCache) {
4758 sizeCache *= 2;
4759 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4760 sizeof(xmlNsPtr));
4761 if (oldNs == NULL) {
4762 xmlGenericError(xmlGenericErrorContext,
4763 "xmlReconciliateNs : memory pbm\n");
4764 xmlFree(newNs);
4765 return(-1);
4766 }
4767 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4768 sizeof(xmlNsPtr));
4769 if (newNs == NULL) {
4770 xmlGenericError(xmlGenericErrorContext,
4771 "xmlReconciliateNs : memory pbm\n");
4772 xmlFree(oldNs);
4773 return(-1);
4774 }
4775 }
4776 newNs[nbCache] = n;
4777 oldNs[nbCache++] = attr->ns;
4778 attr->ns = n;
4779 }
4780 }
4781 }
4782 attr = attr->next;
4783 }
4784
4785 /*
4786 * Browse the full subtree, deep first
4787 */
4788 if (node->children != NULL) {
4789 /* deep first */
4790 node = node->children;
4791 } else if ((node != tree) && (node->next != NULL)) {
4792 /* then siblings */
4793 node = node->next;
4794 } else if (node != tree) {
4795 /* go up to parents->next if needed */
4796 while (node != tree) {
4797 if (node->parent != NULL)
4798 node = node->parent;
4799 if ((node != tree) && (node->next != NULL)) {
4800 node = node->next;
4801 break;
4802 }
4803 if (node->parent == NULL) {
4804 node = NULL;
4805 break;
4806 }
4807 }
4808 /* exit condition */
4809 if (node == tree)
4810 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004811 } else
4812 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004813 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004814 if (oldNs != NULL)
4815 xmlFree(oldNs);
4816 if (newNs != NULL)
4817 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004818 return(ret);
4819}
4820
4821/**
4822 * xmlHasProp:
4823 * @node: the node
4824 * @name: the attribute name
4825 *
4826 * Search an attribute associated to a node
4827 * This function also looks in DTD attribute declaration for #FIXED or
4828 * default declaration values unless DTD use has been turned off.
4829 *
4830 * Returns the attribute or the attribute declaration or NULL if
4831 * neither was found.
4832 */
4833xmlAttrPtr
4834xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4835 xmlAttrPtr prop;
4836 xmlDocPtr doc;
4837
4838 if ((node == NULL) || (name == NULL)) return(NULL);
4839 /*
4840 * Check on the properties attached to the node
4841 */
4842 prop = node->properties;
4843 while (prop != NULL) {
4844 if (xmlStrEqual(prop->name, name)) {
4845 return(prop);
4846 }
4847 prop = prop->next;
4848 }
4849 if (!xmlCheckDTD) return(NULL);
4850
4851 /*
4852 * Check if there is a default declaration in the internal
4853 * or external subsets
4854 */
4855 doc = node->doc;
4856 if (doc != NULL) {
4857 xmlAttributePtr attrDecl;
4858 if (doc->intSubset != NULL) {
4859 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4860 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4861 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4862 if (attrDecl != NULL)
4863 return((xmlAttrPtr) attrDecl);
4864 }
4865 }
4866 return(NULL);
4867}
4868
4869/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004870 * xmlHasNsProp:
4871 * @node: the node
4872 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004873 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004874 *
4875 * Search for an attribute associated to a node
4876 * This attribute has to be anchored in the namespace specified.
4877 * This does the entity substitution.
4878 * This function looks in DTD attribute declaration for #FIXED or
4879 * default declaration values unless DTD use has been turned off.
4880 *
4881 * Returns the attribute or the attribute declaration or NULL
4882 * if neither was found.
4883 */
4884xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004885xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004886 xmlAttrPtr prop;
4887 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004888
4889 if (node == NULL)
4890 return(NULL);
4891
4892 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004893 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004894 return(xmlHasProp(node, name));
4895 while (prop != NULL) {
4896 /*
4897 * One need to have
4898 * - same attribute names
4899 * - and the attribute carrying that namespace
4900 * or
4901 * no namespace on the attribute and the element carrying it
4902 */
4903 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004904 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4905 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004906 }
4907 prop = prop->next;
4908 }
4909 if (!xmlCheckDTD) return(NULL);
4910
4911 /*
4912 * Check if there is a default declaration in the internal
4913 * or external subsets
4914 */
4915 doc = node->doc;
4916 if (doc != NULL) {
4917 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004918 xmlAttributePtr attrDecl = NULL;
4919 xmlNsPtr *nsList, *cur;
4920 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004921
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004922 nsList = xmlGetNsList(node->doc, node);
4923 if (nsList == NULL)
4924 return(NULL);
4925 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4926 ename = xmlStrdup(node->ns->prefix);
4927 ename = xmlStrcat(ename, BAD_CAST ":");
4928 ename = xmlStrcat(ename, node->name);
4929 } else {
4930 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004931 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004932 if (ename == NULL) {
4933 xmlFree(nsList);
4934 return(NULL);
4935 }
4936
4937 cur = nsList;
4938 while (*cur != NULL) {
4939 if (xmlStrEqual((*cur)->href, nameSpace)) {
4940 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4941 name, (*cur)->prefix);
4942 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4943 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4944 name, (*cur)->prefix);
4945 }
4946 cur++;
4947 }
4948 xmlFree(nsList);
4949 xmlFree(ename);
4950 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004951 }
4952 }
4953 return(NULL);
4954}
4955
4956/**
Owen Taylor3473f882001-02-23 17:55:21 +00004957 * xmlGetProp:
4958 * @node: the node
4959 * @name: the attribute name
4960 *
4961 * Search and get the value of an attribute associated to a node
4962 * This does the entity substitution.
4963 * This function looks in DTD attribute declaration for #FIXED or
4964 * default declaration values unless DTD use has been turned off.
4965 *
4966 * Returns the attribute value or NULL if not found.
4967 * It's up to the caller to free the memory.
4968 */
4969xmlChar *
4970xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4971 xmlAttrPtr prop;
4972 xmlDocPtr doc;
4973
4974 if ((node == NULL) || (name == NULL)) return(NULL);
4975 /*
4976 * Check on the properties attached to the node
4977 */
4978 prop = node->properties;
4979 while (prop != NULL) {
4980 if (xmlStrEqual(prop->name, name)) {
4981 xmlChar *ret;
4982
4983 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4984 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4985 return(ret);
4986 }
4987 prop = prop->next;
4988 }
4989 if (!xmlCheckDTD) return(NULL);
4990
4991 /*
4992 * Check if there is a default declaration in the internal
4993 * or external subsets
4994 */
4995 doc = node->doc;
4996 if (doc != NULL) {
4997 xmlAttributePtr attrDecl;
4998 if (doc->intSubset != NULL) {
4999 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5000 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5001 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5002 if (attrDecl != NULL)
5003 return(xmlStrdup(attrDecl->defaultValue));
5004 }
5005 }
5006 return(NULL);
5007}
5008
5009/**
5010 * xmlGetNsProp:
5011 * @node: the node
5012 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005013 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005014 *
5015 * Search and get the value of an attribute associated to a node
5016 * This attribute has to be anchored in the namespace specified.
5017 * This does the entity substitution.
5018 * This function looks in DTD attribute declaration for #FIXED or
5019 * default declaration values unless DTD use has been turned off.
5020 *
5021 * Returns the attribute value or NULL if not found.
5022 * It's up to the caller to free the memory.
5023 */
5024xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005025xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005026 xmlAttrPtr prop;
5027 xmlDocPtr doc;
5028 xmlNsPtr ns;
5029
5030 if (node == NULL)
5031 return(NULL);
5032
5033 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005034 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005035 return(xmlGetProp(node, name));
5036 while (prop != NULL) {
5037 /*
5038 * One need to have
5039 * - same attribute names
5040 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005041 */
5042 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005043 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005044 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005045 xmlChar *ret;
5046
5047 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5048 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5049 return(ret);
5050 }
5051 prop = prop->next;
5052 }
5053 if (!xmlCheckDTD) return(NULL);
5054
5055 /*
5056 * Check if there is a default declaration in the internal
5057 * or external subsets
5058 */
5059 doc = node->doc;
5060 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005061 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005062 xmlAttributePtr attrDecl;
5063
Owen Taylor3473f882001-02-23 17:55:21 +00005064 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5065 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5066 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5067
5068 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5069 /*
5070 * The DTD declaration only allows a prefix search
5071 */
5072 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005073 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005074 return(xmlStrdup(attrDecl->defaultValue));
5075 }
5076 }
5077 }
5078 return(NULL);
5079}
5080
5081/**
5082 * xmlSetProp:
5083 * @node: the node
5084 * @name: the attribute name
5085 * @value: the attribute value
5086 *
5087 * Set (or reset) an attribute carried by a node.
5088 * Returns the attribute pointer.
5089 */
5090xmlAttrPtr
5091xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005092 xmlAttrPtr prop;
5093 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005094
5095 if ((node == NULL) || (name == NULL))
5096 return(NULL);
5097 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005098 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005099 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005100 if ((xmlStrEqual(prop->name, name)) &&
5101 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005102 xmlNodePtr oldprop = prop->children;
5103
Owen Taylor3473f882001-02-23 17:55:21 +00005104 prop->children = NULL;
5105 prop->last = NULL;
5106 if (value != NULL) {
5107 xmlChar *buffer;
5108 xmlNodePtr tmp;
5109
5110 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5111 prop->children = xmlStringGetNodeList(node->doc, buffer);
5112 prop->last = NULL;
5113 prop->doc = doc;
5114 tmp = prop->children;
5115 while (tmp != NULL) {
5116 tmp->parent = (xmlNodePtr) prop;
5117 tmp->doc = doc;
5118 if (tmp->next == NULL)
5119 prop->last = tmp;
5120 tmp = tmp->next;
5121 }
5122 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005123 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005124 if (oldprop != NULL)
5125 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005126 return(prop);
5127 }
5128 prop = prop->next;
5129 }
5130 prop = xmlNewProp(node, name, value);
5131 return(prop);
5132}
5133
5134/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005135 * xmlUnsetProp:
5136 * @node: the node
5137 * @name: the attribute name
5138 *
5139 * Remove an attribute carried by a node.
5140 * Returns 0 if successful, -1 if not found
5141 */
5142int
5143xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5144 xmlAttrPtr prop = node->properties, prev = NULL;;
5145
5146 if ((node == NULL) || (name == NULL))
5147 return(-1);
5148 while (prop != NULL) {
5149 if ((xmlStrEqual(prop->name, name)) &&
5150 (prop->ns == NULL)) {
5151 if (prev == NULL)
5152 node->properties = prop->next;
5153 else
5154 prev->next = prop->next;
5155 xmlFreeProp(prop);
5156 return(0);
5157 }
5158 prev = prop;
5159 prop = prop->next;
5160 }
5161 return(-1);
5162}
5163
5164/**
Owen Taylor3473f882001-02-23 17:55:21 +00005165 * xmlSetNsProp:
5166 * @node: the node
5167 * @ns: the namespace definition
5168 * @name: the attribute name
5169 * @value: the attribute value
5170 *
5171 * Set (or reset) an attribute carried by a node.
5172 * The ns structure must be in scope, this is not checked.
5173 *
5174 * Returns the attribute pointer.
5175 */
5176xmlAttrPtr
5177xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5178 const xmlChar *value) {
5179 xmlAttrPtr prop;
5180
5181 if ((node == NULL) || (name == NULL))
5182 return(NULL);
5183
5184 if (ns == NULL)
5185 return(xmlSetProp(node, name, value));
5186 if (ns->href == NULL)
5187 return(NULL);
5188 prop = node->properties;
5189
5190 while (prop != NULL) {
5191 /*
5192 * One need to have
5193 * - same attribute names
5194 * - and the attribute carrying that namespace
5195 * or
5196 * no namespace on the attribute and the element carrying it
5197 */
5198 if ((xmlStrEqual(prop->name, name)) &&
5199 (((prop->ns == NULL) && (node->ns != NULL) &&
5200 (xmlStrEqual(node->ns->href, ns->href))) ||
5201 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5202 if (prop->children != NULL)
5203 xmlFreeNodeList(prop->children);
5204 prop->children = NULL;
5205 prop->last = NULL;
5206 prop->ns = ns;
5207 if (value != NULL) {
5208 xmlChar *buffer;
5209 xmlNodePtr tmp;
5210
5211 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5212 prop->children = xmlStringGetNodeList(node->doc, buffer);
5213 prop->last = NULL;
5214 tmp = prop->children;
5215 while (tmp != NULL) {
5216 tmp->parent = (xmlNodePtr) prop;
5217 if (tmp->next == NULL)
5218 prop->last = tmp;
5219 tmp = tmp->next;
5220 }
5221 xmlFree(buffer);
5222 }
5223 return(prop);
5224 }
5225 prop = prop->next;
5226 }
5227 prop = xmlNewNsProp(node, ns, name, value);
5228 return(prop);
5229}
5230
5231/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005232 * xmlUnsetNsProp:
5233 * @node: the node
5234 * @ns: the namespace definition
5235 * @name: the attribute name
5236 *
5237 * Remove an attribute carried by a node.
5238 * Returns 0 if successful, -1 if not found
5239 */
5240int
5241xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5242 xmlAttrPtr prop = node->properties, prev = NULL;;
5243
5244 if ((node == NULL) || (name == NULL))
5245 return(-1);
5246 if (ns == NULL)
5247 return(xmlUnsetProp(node, name));
5248 if (ns->href == NULL)
5249 return(-1);
5250 while (prop != NULL) {
5251 if ((xmlStrEqual(prop->name, name)) &&
5252 (((prop->ns == NULL) && (node->ns != NULL) &&
5253 (xmlStrEqual(node->ns->href, ns->href))) ||
5254 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5255 if (prev == NULL)
5256 node->properties = prop->next;
5257 else
5258 prev->next = prop->next;
5259 xmlFreeProp(prop);
5260 return(0);
5261 }
5262 prev = prop;
5263 prop = prop->next;
5264 }
5265 return(-1);
5266}
5267
5268/**
Owen Taylor3473f882001-02-23 17:55:21 +00005269 * xmlNodeIsText:
5270 * @node: the node
5271 *
5272 * Is this node a Text node ?
5273 * Returns 1 yes, 0 no
5274 */
5275int
5276xmlNodeIsText(xmlNodePtr node) {
5277 if (node == NULL) return(0);
5278
5279 if (node->type == XML_TEXT_NODE) return(1);
5280 return(0);
5281}
5282
5283/**
5284 * xmlIsBlankNode:
5285 * @node: the node
5286 *
5287 * Checks whether this node is an empty or whitespace only
5288 * (and possibly ignorable) text-node.
5289 *
5290 * Returns 1 yes, 0 no
5291 */
5292int
5293xmlIsBlankNode(xmlNodePtr node) {
5294 const xmlChar *cur;
5295 if (node == NULL) return(0);
5296
Daniel Veillard7db37732001-07-12 01:20:08 +00005297 if ((node->type != XML_TEXT_NODE) &&
5298 (node->type != XML_CDATA_SECTION_NODE))
5299 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005300 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005301 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005302 while (*cur != 0) {
5303 if (!IS_BLANK(*cur)) return(0);
5304 cur++;
5305 }
5306
5307 return(1);
5308}
5309
5310/**
5311 * xmlTextConcat:
5312 * @node: the node
5313 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005314 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005315 *
5316 * Concat the given string at the end of the existing node content
5317 */
5318
5319void
5320xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5321 if (node == NULL) return;
5322
5323 if ((node->type != XML_TEXT_NODE) &&
5324 (node->type != XML_CDATA_SECTION_NODE)) {
5325#ifdef DEBUG_TREE
5326 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005327 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005328#endif
5329 return;
5330 }
Owen Taylor3473f882001-02-23 17:55:21 +00005331 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005332}
5333
5334/************************************************************************
5335 * *
5336 * Output : to a FILE or in memory *
5337 * *
5338 ************************************************************************/
5339
Owen Taylor3473f882001-02-23 17:55:21 +00005340/**
5341 * xmlBufferCreate:
5342 *
5343 * routine to create an XML buffer.
5344 * returns the new structure.
5345 */
5346xmlBufferPtr
5347xmlBufferCreate(void) {
5348 xmlBufferPtr ret;
5349
5350 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5351 if (ret == NULL) {
5352 xmlGenericError(xmlGenericErrorContext,
5353 "xmlBufferCreate : out of memory!\n");
5354 return(NULL);
5355 }
5356 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005357 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005358 ret->alloc = xmlBufferAllocScheme;
5359 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5360 if (ret->content == NULL) {
5361 xmlGenericError(xmlGenericErrorContext,
5362 "xmlBufferCreate : out of memory!\n");
5363 xmlFree(ret);
5364 return(NULL);
5365 }
5366 ret->content[0] = 0;
5367 return(ret);
5368}
5369
5370/**
5371 * xmlBufferCreateSize:
5372 * @size: initial size of buffer
5373 *
5374 * routine to create an XML buffer.
5375 * returns the new structure.
5376 */
5377xmlBufferPtr
5378xmlBufferCreateSize(size_t size) {
5379 xmlBufferPtr ret;
5380
5381 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5382 if (ret == NULL) {
5383 xmlGenericError(xmlGenericErrorContext,
5384 "xmlBufferCreate : out of memory!\n");
5385 return(NULL);
5386 }
5387 ret->use = 0;
5388 ret->alloc = xmlBufferAllocScheme;
5389 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5390 if (ret->size){
5391 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5392 if (ret->content == NULL) {
5393 xmlGenericError(xmlGenericErrorContext,
5394 "xmlBufferCreate : out of memory!\n");
5395 xmlFree(ret);
5396 return(NULL);
5397 }
5398 ret->content[0] = 0;
5399 } else
5400 ret->content = NULL;
5401 return(ret);
5402}
5403
5404/**
5405 * xmlBufferSetAllocationScheme:
5406 * @buf: the buffer to free
5407 * @scheme: allocation scheme to use
5408 *
5409 * Sets the allocation scheme for this buffer
5410 */
5411void
5412xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5413 xmlBufferAllocationScheme scheme) {
5414 if (buf == NULL) {
5415#ifdef DEBUG_BUFFER
5416 xmlGenericError(xmlGenericErrorContext,
5417 "xmlBufferSetAllocationScheme: buf == NULL\n");
5418#endif
5419 return;
5420 }
5421
5422 buf->alloc = scheme;
5423}
5424
5425/**
5426 * xmlBufferFree:
5427 * @buf: the buffer to free
5428 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005429 * Frees an XML buffer. It frees both the content and the structure which
5430 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005431 */
5432void
5433xmlBufferFree(xmlBufferPtr buf) {
5434 if (buf == NULL) {
5435#ifdef DEBUG_BUFFER
5436 xmlGenericError(xmlGenericErrorContext,
5437 "xmlBufferFree: buf == NULL\n");
5438#endif
5439 return;
5440 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005441 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005442 xmlFree(buf->content);
5443 }
Owen Taylor3473f882001-02-23 17:55:21 +00005444 xmlFree(buf);
5445}
5446
5447/**
5448 * xmlBufferEmpty:
5449 * @buf: the buffer
5450 *
5451 * empty a buffer.
5452 */
5453void
5454xmlBufferEmpty(xmlBufferPtr buf) {
5455 if (buf->content == NULL) return;
5456 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005457 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005458}
5459
5460/**
5461 * xmlBufferShrink:
5462 * @buf: the buffer to dump
5463 * @len: the number of xmlChar to remove
5464 *
5465 * Remove the beginning of an XML buffer.
5466 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005467 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005468 */
5469int
5470xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5471 if (len == 0) return(0);
5472 if (len > buf->use) return(-1);
5473
5474 buf->use -= len;
5475 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5476
5477 buf->content[buf->use] = 0;
5478 return(len);
5479}
5480
5481/**
5482 * xmlBufferGrow:
5483 * @buf: the buffer
5484 * @len: the minimum free size to allocate
5485 *
5486 * Grow the available space of an XML buffer.
5487 *
5488 * Returns the new available space or -1 in case of error
5489 */
5490int
5491xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5492 int size;
5493 xmlChar *newbuf;
5494
5495 if (len + buf->use < buf->size) return(0);
5496
5497 size = buf->use + len + 100;
5498
5499 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5500 if (newbuf == NULL) return(-1);
5501 buf->content = newbuf;
5502 buf->size = size;
5503 return(buf->size - buf->use);
5504}
5505
5506/**
5507 * xmlBufferDump:
5508 * @file: the file output
5509 * @buf: the buffer to dump
5510 *
5511 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005512 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005513 */
5514int
5515xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5516 int ret;
5517
5518 if (buf == NULL) {
5519#ifdef DEBUG_BUFFER
5520 xmlGenericError(xmlGenericErrorContext,
5521 "xmlBufferDump: buf == NULL\n");
5522#endif
5523 return(0);
5524 }
5525 if (buf->content == NULL) {
5526#ifdef DEBUG_BUFFER
5527 xmlGenericError(xmlGenericErrorContext,
5528 "xmlBufferDump: buf->content == NULL\n");
5529#endif
5530 return(0);
5531 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005532 if (file == NULL)
5533 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005534 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5535 return(ret);
5536}
5537
5538/**
5539 * xmlBufferContent:
5540 * @buf: the buffer
5541 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005542 * Function to extract the content of a buffer
5543 *
Owen Taylor3473f882001-02-23 17:55:21 +00005544 * Returns the internal content
5545 */
5546
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005547const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005548xmlBufferContent(const xmlBufferPtr buf)
5549{
5550 if(!buf)
5551 return NULL;
5552
5553 return buf->content;
5554}
5555
5556/**
5557 * xmlBufferLength:
5558 * @buf: the buffer
5559 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005560 * Function to get the length of a buffer
5561 *
Owen Taylor3473f882001-02-23 17:55:21 +00005562 * Returns the length of data in the internal content
5563 */
5564
5565int
5566xmlBufferLength(const xmlBufferPtr buf)
5567{
5568 if(!buf)
5569 return 0;
5570
5571 return buf->use;
5572}
5573
5574/**
5575 * xmlBufferResize:
5576 * @buf: the buffer to resize
5577 * @size: the desired size
5578 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005579 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005580 *
5581 * Returns 0 in case of problems, 1 otherwise
5582 */
5583int
5584xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5585{
5586 unsigned int newSize;
5587 xmlChar* rebuf = NULL;
5588
5589 /*take care of empty case*/
5590 newSize = (buf->size ? buf->size*2 : size);
5591
5592 /* Don't resize if we don't have to */
5593 if (size < buf->size)
5594 return 1;
5595
5596 /* figure out new size */
5597 switch (buf->alloc){
5598 case XML_BUFFER_ALLOC_DOUBLEIT:
5599 while (size > newSize) newSize *= 2;
5600 break;
5601 case XML_BUFFER_ALLOC_EXACT:
5602 newSize = size+10;
5603 break;
5604 default:
5605 newSize = size+10;
5606 break;
5607 }
5608
5609 if (buf->content == NULL)
5610 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5611 else
5612 rebuf = (xmlChar *) xmlRealloc(buf->content,
5613 newSize * sizeof(xmlChar));
5614 if (rebuf == NULL) {
5615 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005616 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005617 return 0;
5618 }
5619 buf->content = rebuf;
5620 buf->size = newSize;
5621
5622 return 1;
5623}
5624
5625/**
5626 * xmlBufferAdd:
5627 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005628 * @str: the #xmlChar string
5629 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005630 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005631 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005632 * str is recomputed.
5633 */
5634void
5635xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5636 unsigned int needSize;
5637
5638 if (str == NULL) {
5639#ifdef DEBUG_BUFFER
5640 xmlGenericError(xmlGenericErrorContext,
5641 "xmlBufferAdd: str == NULL\n");
5642#endif
5643 return;
5644 }
5645 if (len < -1) {
5646#ifdef DEBUG_BUFFER
5647 xmlGenericError(xmlGenericErrorContext,
5648 "xmlBufferAdd: len < 0\n");
5649#endif
5650 return;
5651 }
5652 if (len == 0) return;
5653
5654 if (len < 0)
5655 len = xmlStrlen(str);
5656
5657 if (len <= 0) return;
5658
5659 needSize = buf->use + len + 2;
5660 if (needSize > buf->size){
5661 if (!xmlBufferResize(buf, needSize)){
5662 xmlGenericError(xmlGenericErrorContext,
5663 "xmlBufferAdd : out of memory!\n");
5664 return;
5665 }
5666 }
5667
5668 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5669 buf->use += len;
5670 buf->content[buf->use] = 0;
5671}
5672
5673/**
5674 * xmlBufferAddHead:
5675 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005676 * @str: the #xmlChar string
5677 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005678 *
5679 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005680 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005681 */
5682void
5683xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5684 unsigned int needSize;
5685
5686 if (str == NULL) {
5687#ifdef DEBUG_BUFFER
5688 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005689 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005690#endif
5691 return;
5692 }
5693 if (len < -1) {
5694#ifdef DEBUG_BUFFER
5695 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005696 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005697#endif
5698 return;
5699 }
5700 if (len == 0) return;
5701
5702 if (len < 0)
5703 len = xmlStrlen(str);
5704
5705 if (len <= 0) return;
5706
5707 needSize = buf->use + len + 2;
5708 if (needSize > buf->size){
5709 if (!xmlBufferResize(buf, needSize)){
5710 xmlGenericError(xmlGenericErrorContext,
5711 "xmlBufferAddHead : out of memory!\n");
5712 return;
5713 }
5714 }
5715
5716 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5717 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5718 buf->use += len;
5719 buf->content[buf->use] = 0;
5720}
5721
5722/**
5723 * xmlBufferCat:
5724 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005725 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005726 *
5727 * Append a zero terminated string to an XML buffer.
5728 */
5729void
5730xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5731 if (str != NULL)
5732 xmlBufferAdd(buf, str, -1);
5733}
5734
5735/**
5736 * xmlBufferCCat:
5737 * @buf: the buffer to dump
5738 * @str: the C char string
5739 *
5740 * Append a zero terminated C string to an XML buffer.
5741 */
5742void
5743xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5744 const char *cur;
5745
5746 if (str == NULL) {
5747#ifdef DEBUG_BUFFER
5748 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005749 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005750#endif
5751 return;
5752 }
5753 for (cur = str;*cur != 0;cur++) {
5754 if (buf->use + 10 >= buf->size) {
5755 if (!xmlBufferResize(buf, buf->use+10)){
5756 xmlGenericError(xmlGenericErrorContext,
5757 "xmlBufferCCat : out of memory!\n");
5758 return;
5759 }
5760 }
5761 buf->content[buf->use++] = *cur;
5762 }
5763 buf->content[buf->use] = 0;
5764}
5765
5766/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005767 * xmlBufferWriteXmlCHAR:
5768 * @buf: the XML buffer
5769 * @string: the string to add
5770 *
5771 * For VMS only.
5772 * routine which manages and grows an output buffer. This one adds
5773 * xmlChars at the end of the buffer.
5774 */
5775/**
Owen Taylor3473f882001-02-23 17:55:21 +00005776 * xmlBufferWriteCHAR:
5777 * @buf: the XML buffer
5778 * @string: the string to add
5779 *
5780 * routine which manages and grows an output buffer. This one adds
5781 * xmlChars at the end of the buffer.
5782 */
5783void
5784#ifdef VMS
5785xmlBufferWriteXmlCHAR
5786#else
5787xmlBufferWriteCHAR
5788#endif
5789(xmlBufferPtr buf, const xmlChar *string) {
5790 xmlBufferCat(buf, string);
5791}
5792
5793/**
5794 * xmlBufferWriteChar:
5795 * @buf: the XML buffer output
5796 * @string: the string to add
5797 *
5798 * routine which manage and grows an output buffer. This one add
5799 * C chars at the end of the array.
5800 */
5801void
5802xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5803 xmlBufferCCat(buf, string);
5804}
5805
5806
5807/**
5808 * xmlBufferWriteQuotedString:
5809 * @buf: the XML buffer output
5810 * @string: the string to add
5811 *
5812 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005813 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005814 * quote or double-quotes internally
5815 */
5816void
5817xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5818 if (xmlStrchr(string, '"')) {
5819 if (xmlStrchr(string, '\'')) {
5820#ifdef DEBUG_BUFFER
5821 xmlGenericError(xmlGenericErrorContext,
5822 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5823#endif
5824 }
5825 xmlBufferCCat(buf, "'");
5826 xmlBufferCat(buf, string);
5827 xmlBufferCCat(buf, "'");
5828 } else {
5829 xmlBufferCCat(buf, "\"");
5830 xmlBufferCat(buf, string);
5831 xmlBufferCCat(buf, "\"");
5832 }
5833}
5834
5835
5836/************************************************************************
5837 * *
5838 * Dumping XML tree content to a simple buffer *
5839 * *
5840 ************************************************************************/
5841
Owen Taylor3473f882001-02-23 17:55:21 +00005842static void
5843xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5844 int format);
5845void
5846htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5847
5848/**
5849 * xmlNsDump:
5850 * @buf: the XML buffer output
5851 * @cur: a namespace
5852 *
5853 * Dump a local Namespace definition.
5854 * Should be called in the context of attributes dumps.
5855 */
5856static void
5857xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5858 if (cur == NULL) {
5859#ifdef DEBUG_TREE
5860 xmlGenericError(xmlGenericErrorContext,
5861 "xmlNsDump : Ns == NULL\n");
5862#endif
5863 return;
5864 }
5865 if (cur->type == XML_LOCAL_NAMESPACE) {
5866 /* Within the context of an element attributes */
5867 if (cur->prefix != NULL) {
5868 xmlBufferWriteChar(buf, " xmlns:");
5869 xmlBufferWriteCHAR(buf, cur->prefix);
5870 } else
5871 xmlBufferWriteChar(buf, " xmlns");
5872 xmlBufferWriteChar(buf, "=");
5873 xmlBufferWriteQuotedString(buf, cur->href);
5874 }
5875}
5876
5877/**
5878 * xmlNsListDump:
5879 * @buf: the XML buffer output
5880 * @cur: the first namespace
5881 *
5882 * Dump a list of local Namespace definitions.
5883 * Should be called in the context of attributes dumps.
5884 */
5885static void
5886xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5887 while (cur != NULL) {
5888 xmlNsDump(buf, cur);
5889 cur = cur->next;
5890 }
5891}
5892
5893/**
5894 * xmlDtdDump:
5895 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005896 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005897 *
5898 * Dump the XML document DTD, if any.
5899 */
5900static void
5901xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5902 if (dtd == NULL) {
5903#ifdef DEBUG_TREE
5904 xmlGenericError(xmlGenericErrorContext,
5905 "xmlDtdDump : no internal subset\n");
5906#endif
5907 return;
5908 }
5909 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5910 xmlBufferWriteCHAR(buf, dtd->name);
5911 if (dtd->ExternalID != NULL) {
5912 xmlBufferWriteChar(buf, " PUBLIC ");
5913 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5914 xmlBufferWriteChar(buf, " ");
5915 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5916 } else if (dtd->SystemID != NULL) {
5917 xmlBufferWriteChar(buf, " SYSTEM ");
5918 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5919 }
5920 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5921 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5922 xmlBufferWriteChar(buf, ">");
5923 return;
5924 }
5925 xmlBufferWriteChar(buf, " [\n");
5926 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5927#if 0
5928 if (dtd->entities != NULL)
5929 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5930 if (dtd->notations != NULL)
5931 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5932 if (dtd->elements != NULL)
5933 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5934 if (dtd->attributes != NULL)
5935 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5936#endif
5937 xmlBufferWriteChar(buf, "]>");
5938}
5939
5940/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005941 * xmlAttrSerializeContent:
5942 * @buf: the XML buffer output
5943 * @doc: the document
5944 * @attr: the attribute pointer
5945 *
5946 * Serialize the attribute in the buffer
5947 */
5948static void
5949xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5950 const xmlChar *cur, *base;
5951 xmlNodePtr children;
5952
5953 children = attr->children;
5954 while (children != NULL) {
5955 switch (children->type) {
5956 case XML_TEXT_NODE:
5957 base = cur = children->content;
5958 while (*cur != 0) {
5959 if (*cur == '\n') {
5960 if (base != cur)
5961 xmlBufferAdd(buf, base, cur - base);
5962 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5963 cur++;
5964 base = cur;
5965#if 0
5966 } else if (*cur == '\'') {
5967 if (base != cur)
5968 xmlBufferAdd(buf, base, cur - base);
5969 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5970 cur++;
5971 base = cur;
5972#endif
5973 } else if (*cur == '"') {
5974 if (base != cur)
5975 xmlBufferAdd(buf, base, cur - base);
5976 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5977 cur++;
5978 base = cur;
5979 } else if (*cur == '<') {
5980 if (base != cur)
5981 xmlBufferAdd(buf, base, cur - base);
5982 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
5983 cur++;
5984 base = cur;
5985 } else if (*cur == '>') {
5986 if (base != cur)
5987 xmlBufferAdd(buf, base, cur - base);
5988 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
5989 cur++;
5990 base = cur;
5991 } else if (*cur == '&') {
5992 if (base != cur)
5993 xmlBufferAdd(buf, base, cur - base);
5994 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
5995 cur++;
5996 base = cur;
5997 } else if ((*cur >= 0x80) && ((doc == NULL) ||
5998 (doc->encoding == NULL))) {
5999 /*
6000 * We assume we have UTF-8 content.
6001 */
6002 char tmp[10];
6003 int val = 0, l = 1;
6004
6005 if (base != cur)
6006 xmlBufferAdd(buf, base, cur - base);
6007 if (*cur < 0xC0) {
6008 xmlGenericError(xmlGenericErrorContext,
6009 "xmlAttrSerializeContent : input not UTF-8\n");
6010 if (doc != NULL)
6011 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6012 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6013 tmp[sizeof(tmp) - 1] = 0;
6014 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6015 cur++;
6016 base = cur;
6017 continue;
6018 } else if (*cur < 0xE0) {
6019 val = (cur[0]) & 0x1F;
6020 val <<= 6;
6021 val |= (cur[1]) & 0x3F;
6022 l = 2;
6023 } else if (*cur < 0xF0) {
6024 val = (cur[0]) & 0x0F;
6025 val <<= 6;
6026 val |= (cur[1]) & 0x3F;
6027 val <<= 6;
6028 val |= (cur[2]) & 0x3F;
6029 l = 3;
6030 } else if (*cur < 0xF8) {
6031 val = (cur[0]) & 0x07;
6032 val <<= 6;
6033 val |= (cur[1]) & 0x3F;
6034 val <<= 6;
6035 val |= (cur[2]) & 0x3F;
6036 val <<= 6;
6037 val |= (cur[3]) & 0x3F;
6038 l = 4;
6039 }
6040 if ((l == 1) || (!IS_CHAR(val))) {
6041 xmlGenericError(xmlGenericErrorContext,
6042 "xmlAttrSerializeContent : char out of range\n");
6043 if (doc != NULL)
6044 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6045 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6046 tmp[sizeof(tmp) - 1] = 0;
6047 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6048 cur++;
6049 base = cur;
6050 continue;
6051 }
6052 /*
6053 * We could do multiple things here. Just save
6054 * as a char ref
6055 */
6056 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6057 tmp[sizeof(tmp) - 1] = 0;
6058 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6059 cur += l;
6060 base = cur;
6061 } else {
6062 cur++;
6063 }
6064 }
6065 if (base != cur)
6066 xmlBufferAdd(buf, base, cur - base);
6067 break;
6068 case XML_ENTITY_REF_NODE:
6069 xmlBufferAdd(buf, BAD_CAST "&", 1);
6070 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6071 xmlBufferAdd(buf, BAD_CAST ";", 1);
6072 break;
6073 default:
6074 /* should not happen unless we have a badly built tree */
6075 break;
6076 }
6077 children = children->next;
6078 }
6079}
6080
6081/**
Owen Taylor3473f882001-02-23 17:55:21 +00006082 * xmlAttrDump:
6083 * @buf: the XML buffer output
6084 * @doc: the document
6085 * @cur: the attribute pointer
6086 *
6087 * Dump an XML attribute
6088 */
6089static void
6090xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006091 if (cur == NULL) {
6092#ifdef DEBUG_TREE
6093 xmlGenericError(xmlGenericErrorContext,
6094 "xmlAttrDump : property == NULL\n");
6095#endif
6096 return;
6097 }
6098 xmlBufferWriteChar(buf, " ");
6099 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6100 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6101 xmlBufferWriteChar(buf, ":");
6102 }
6103 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006104 xmlBufferWriteChar(buf, "=\"");
6105 xmlAttrSerializeContent(buf, doc, cur);
6106 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006107}
6108
6109/**
6110 * xmlAttrListDump:
6111 * @buf: the XML buffer output
6112 * @doc: the document
6113 * @cur: the first attribute pointer
6114 *
6115 * Dump a list of XML attributes
6116 */
6117static void
6118xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6119 if (cur == NULL) {
6120#ifdef DEBUG_TREE
6121 xmlGenericError(xmlGenericErrorContext,
6122 "xmlAttrListDump : property == NULL\n");
6123#endif
6124 return;
6125 }
6126 while (cur != NULL) {
6127 xmlAttrDump(buf, doc, cur);
6128 cur = cur->next;
6129 }
6130}
6131
6132
6133
6134/**
6135 * xmlNodeListDump:
6136 * @buf: the XML buffer output
6137 * @doc: the document
6138 * @cur: the first node
6139 * @level: the imbrication level for indenting
6140 * @format: is formatting allowed
6141 *
6142 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006143 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6144 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006145 */
6146static void
6147xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6148 int format) {
6149 int i;
6150
6151 if (cur == NULL) {
6152#ifdef DEBUG_TREE
6153 xmlGenericError(xmlGenericErrorContext,
6154 "xmlNodeListDump : node == NULL\n");
6155#endif
6156 return;
6157 }
6158 while (cur != NULL) {
6159 if ((format) && (xmlIndentTreeOutput) &&
6160 (cur->type == XML_ELEMENT_NODE))
6161 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006162 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006163 xmlNodeDump(buf, doc, cur, level, format);
6164 if (format) {
6165 xmlBufferWriteChar(buf, "\n");
6166 }
6167 cur = cur->next;
6168 }
6169}
6170
6171/**
6172 * xmlNodeDump:
6173 * @buf: the XML buffer output
6174 * @doc: the document
6175 * @cur: the current node
6176 * @level: the imbrication level for indenting
6177 * @format: is formatting allowed
6178 *
6179 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006180 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6181 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006182 */
6183void
6184xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6185 int format) {
6186 int i;
6187 xmlNodePtr tmp;
6188
6189 if (cur == NULL) {
6190#ifdef DEBUG_TREE
6191 xmlGenericError(xmlGenericErrorContext,
6192 "xmlNodeDump : node == NULL\n");
6193#endif
6194 return;
6195 }
6196 if (cur->type == XML_XINCLUDE_START)
6197 return;
6198 if (cur->type == XML_XINCLUDE_END)
6199 return;
6200 if (cur->type == XML_DTD_NODE) {
6201 xmlDtdDump(buf, (xmlDtdPtr) cur);
6202 return;
6203 }
6204 if (cur->type == XML_ELEMENT_DECL) {
6205 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6206 return;
6207 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006208 if (cur->type == XML_ATTRIBUTE_NODE){
6209 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6210 return;
6211 }
Owen Taylor3473f882001-02-23 17:55:21 +00006212 if (cur->type == XML_ATTRIBUTE_DECL) {
6213 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6214 return;
6215 }
6216 if (cur->type == XML_ENTITY_DECL) {
6217 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6218 return;
6219 }
6220 if (cur->type == XML_TEXT_NODE) {
6221 if (cur->content != NULL) {
6222 if ((cur->name == xmlStringText) ||
6223 (cur->name != xmlStringTextNoenc)) {
6224 xmlChar *buffer;
6225
Owen Taylor3473f882001-02-23 17:55:21 +00006226 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006227 if (buffer != NULL) {
6228 xmlBufferWriteCHAR(buf, buffer);
6229 xmlFree(buffer);
6230 }
6231 } else {
6232 /*
6233 * Disable escaping, needed for XSLT
6234 */
Owen Taylor3473f882001-02-23 17:55:21 +00006235 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006236 }
6237 }
6238 return;
6239 }
6240 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006241 xmlBufferWriteChar(buf, "<?");
6242 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006243 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006244 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006245 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006246 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006247 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006248 return;
6249 }
6250 if (cur->type == XML_COMMENT_NODE) {
6251 if (cur->content != NULL) {
6252 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006253 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006254 xmlBufferWriteChar(buf, "-->");
6255 }
6256 return;
6257 }
6258 if (cur->type == XML_ENTITY_REF_NODE) {
6259 xmlBufferWriteChar(buf, "&");
6260 xmlBufferWriteCHAR(buf, cur->name);
6261 xmlBufferWriteChar(buf, ";");
6262 return;
6263 }
6264 if (cur->type == XML_CDATA_SECTION_NODE) {
6265 xmlBufferWriteChar(buf, "<![CDATA[");
6266 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006267 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006268 xmlBufferWriteChar(buf, "]]>");
6269 return;
6270 }
6271
6272 if (format == 1) {
6273 tmp = cur->children;
6274 while (tmp != NULL) {
6275 if ((tmp->type == XML_TEXT_NODE) ||
6276 (tmp->type == XML_ENTITY_REF_NODE)) {
6277 format = 0;
6278 break;
6279 }
6280 tmp = tmp->next;
6281 }
6282 }
6283 xmlBufferWriteChar(buf, "<");
6284 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6285 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6286 xmlBufferWriteChar(buf, ":");
6287 }
6288
6289 xmlBufferWriteCHAR(buf, cur->name);
6290 if (cur->nsDef)
6291 xmlNsListDump(buf, cur->nsDef);
6292 if (cur->properties != NULL)
6293 xmlAttrListDump(buf, doc, cur->properties);
6294
Daniel Veillard7db37732001-07-12 01:20:08 +00006295 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6296 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006297 (!xmlSaveNoEmptyTags)) {
6298 xmlBufferWriteChar(buf, "/>");
6299 return;
6300 }
6301 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006302 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006303 xmlChar *buffer;
6304
Owen Taylor3473f882001-02-23 17:55:21 +00006305 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006306 if (buffer != NULL) {
6307 xmlBufferWriteCHAR(buf, buffer);
6308 xmlFree(buffer);
6309 }
6310 }
6311 if (cur->children != NULL) {
6312 if (format) xmlBufferWriteChar(buf, "\n");
6313 xmlNodeListDump(buf, doc, cur->children,
6314 (level >= 0?level+1:-1), format);
6315 if ((xmlIndentTreeOutput) && (format))
6316 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006317 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006318 }
6319 xmlBufferWriteChar(buf, "</");
6320 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6321 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6322 xmlBufferWriteChar(buf, ":");
6323 }
6324
6325 xmlBufferWriteCHAR(buf, cur->name);
6326 xmlBufferWriteChar(buf, ">");
6327}
6328
6329/**
6330 * xmlElemDump:
6331 * @f: the FILE * for the output
6332 * @doc: the document
6333 * @cur: the current node
6334 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006335 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006336 */
6337void
6338xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6339 xmlBufferPtr buf;
6340
6341 if (cur == NULL) {
6342#ifdef DEBUG_TREE
6343 xmlGenericError(xmlGenericErrorContext,
6344 "xmlElemDump : cur == NULL\n");
6345#endif
6346 return;
6347 }
Owen Taylor3473f882001-02-23 17:55:21 +00006348#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006349 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006350 xmlGenericError(xmlGenericErrorContext,
6351 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006352 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006353#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006354
Owen Taylor3473f882001-02-23 17:55:21 +00006355 buf = xmlBufferCreate();
6356 if (buf == NULL) return;
6357 if ((doc != NULL) &&
6358 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6359#ifdef LIBXML_HTML_ENABLED
6360 htmlNodeDump(buf, doc, cur);
6361#else
6362 xmlGenericError(xmlGenericErrorContext,
6363 "HTML support not compiled in\n");
6364#endif /* LIBXML_HTML_ENABLED */
6365 } else
6366 xmlNodeDump(buf, doc, cur, 0, 1);
6367 xmlBufferDump(f, buf);
6368 xmlBufferFree(buf);
6369}
6370
6371/************************************************************************
6372 * *
6373 * Dumping XML tree content to an I/O output buffer *
6374 * *
6375 ************************************************************************/
6376
Owen Taylor3473f882001-02-23 17:55:21 +00006377static void
6378xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6379 int level, int format, const char *encoding);
6380/**
6381 * xmlNsDumpOutput:
6382 * @buf: the XML buffer output
6383 * @cur: a namespace
6384 *
6385 * Dump a local Namespace definition.
6386 * Should be called in the context of attributes dumps.
6387 */
6388static void
6389xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6390 if (cur == NULL) {
6391#ifdef DEBUG_TREE
6392 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006393 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006394#endif
6395 return;
6396 }
6397 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6398 /* Within the context of an element attributes */
6399 if (cur->prefix != NULL) {
6400 xmlOutputBufferWriteString(buf, " xmlns:");
6401 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6402 } else
6403 xmlOutputBufferWriteString(buf, " xmlns");
6404 xmlOutputBufferWriteString(buf, "=");
6405 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6406 }
6407}
6408
6409/**
6410 * xmlNsListDumpOutput:
6411 * @buf: the XML buffer output
6412 * @cur: the first namespace
6413 *
6414 * Dump a list of local Namespace definitions.
6415 * Should be called in the context of attributes dumps.
6416 */
6417static void
6418xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6419 while (cur != NULL) {
6420 xmlNsDumpOutput(buf, cur);
6421 cur = cur->next;
6422 }
6423}
6424
6425/**
6426 * xmlDtdDumpOutput:
6427 * @buf: the XML buffer output
6428 * @doc: the document
6429 * @encoding: an optional encoding string
6430 *
6431 * Dump the XML document DTD, if any.
6432 */
6433static void
6434xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6435 if (dtd == NULL) {
6436#ifdef DEBUG_TREE
6437 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006438 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006439#endif
6440 return;
6441 }
6442 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6443 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6444 if (dtd->ExternalID != NULL) {
6445 xmlOutputBufferWriteString(buf, " PUBLIC ");
6446 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6447 xmlOutputBufferWriteString(buf, " ");
6448 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6449 } else if (dtd->SystemID != NULL) {
6450 xmlOutputBufferWriteString(buf, " SYSTEM ");
6451 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6452 }
6453 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6454 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6455 xmlOutputBufferWriteString(buf, ">");
6456 return;
6457 }
6458 xmlOutputBufferWriteString(buf, " [\n");
6459 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6460 xmlOutputBufferWriteString(buf, "]>");
6461}
6462
6463/**
6464 * xmlAttrDumpOutput:
6465 * @buf: the XML buffer output
6466 * @doc: the document
6467 * @cur: the attribute pointer
6468 * @encoding: an optional encoding string
6469 *
6470 * Dump an XML attribute
6471 */
6472static void
6473xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006474 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006475 if (cur == NULL) {
6476#ifdef DEBUG_TREE
6477 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006478 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006479#endif
6480 return;
6481 }
6482 xmlOutputBufferWriteString(buf, " ");
6483 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6484 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6485 xmlOutputBufferWriteString(buf, ":");
6486 }
6487 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006488 xmlOutputBufferWriteString(buf, "=\"");
6489 xmlAttrSerializeContent(buf->buffer, doc, cur);
6490 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006491}
6492
6493/**
6494 * xmlAttrListDumpOutput:
6495 * @buf: the XML buffer output
6496 * @doc: the document
6497 * @cur: the first attribute pointer
6498 * @encoding: an optional encoding string
6499 *
6500 * Dump a list of XML attributes
6501 */
6502static void
6503xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6504 xmlAttrPtr cur, const char *encoding) {
6505 if (cur == NULL) {
6506#ifdef DEBUG_TREE
6507 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006508 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006509#endif
6510 return;
6511 }
6512 while (cur != NULL) {
6513 xmlAttrDumpOutput(buf, doc, cur, encoding);
6514 cur = cur->next;
6515 }
6516}
6517
6518
6519
6520/**
6521 * xmlNodeListDumpOutput:
6522 * @buf: the XML buffer output
6523 * @doc: the document
6524 * @cur: the first node
6525 * @level: the imbrication level for indenting
6526 * @format: is formatting allowed
6527 * @encoding: an optional encoding string
6528 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006529 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006530 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6531 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006532 */
6533static void
6534xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6535 xmlNodePtr cur, int level, int format, const char *encoding) {
6536 int i;
6537
6538 if (cur == NULL) {
6539#ifdef DEBUG_TREE
6540 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006541 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006542#endif
6543 return;
6544 }
6545 while (cur != NULL) {
6546 if ((format) && (xmlIndentTreeOutput) &&
6547 (cur->type == XML_ELEMENT_NODE))
6548 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006549 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006550 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6551 if (format) {
6552 xmlOutputBufferWriteString(buf, "\n");
6553 }
6554 cur = cur->next;
6555 }
6556}
6557
6558/**
6559 * xmlNodeDumpOutput:
6560 * @buf: the XML buffer output
6561 * @doc: the document
6562 * @cur: the current node
6563 * @level: the imbrication level for indenting
6564 * @format: is formatting allowed
6565 * @encoding: an optional encoding string
6566 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006567 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006568 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6569 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006570 */
6571void
6572xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6573 int level, int format, const char *encoding) {
6574 int i;
6575 xmlNodePtr tmp;
6576
6577 if (cur == NULL) {
6578#ifdef DEBUG_TREE
6579 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006580 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006581#endif
6582 return;
6583 }
6584 if (cur->type == XML_XINCLUDE_START)
6585 return;
6586 if (cur->type == XML_XINCLUDE_END)
6587 return;
6588 if (cur->type == XML_DTD_NODE) {
6589 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6590 return;
6591 }
6592 if (cur->type == XML_ELEMENT_DECL) {
6593 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6594 return;
6595 }
6596 if (cur->type == XML_ATTRIBUTE_DECL) {
6597 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6598 return;
6599 }
6600 if (cur->type == XML_ENTITY_DECL) {
6601 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6602 return;
6603 }
6604 if (cur->type == XML_TEXT_NODE) {
6605 if (cur->content != NULL) {
6606 if ((cur->name == xmlStringText) ||
6607 (cur->name != xmlStringTextNoenc)) {
6608 xmlChar *buffer;
6609
Owen Taylor3473f882001-02-23 17:55:21 +00006610 if (encoding == NULL)
6611 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6612 else
6613 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006614 if (buffer != NULL) {
6615 xmlOutputBufferWriteString(buf, (const char *)buffer);
6616 xmlFree(buffer);
6617 }
6618 } else {
6619 /*
6620 * Disable escaping, needed for XSLT
6621 */
Owen Taylor3473f882001-02-23 17:55:21 +00006622 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006623 }
6624 }
6625
6626 return;
6627 }
6628 if (cur->type == XML_PI_NODE) {
6629 if (cur->content != NULL) {
6630 xmlOutputBufferWriteString(buf, "<?");
6631 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6632 if (cur->content != NULL) {
6633 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006634 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006635 }
6636 xmlOutputBufferWriteString(buf, "?>");
6637 } else {
6638 xmlOutputBufferWriteString(buf, "<?");
6639 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6640 xmlOutputBufferWriteString(buf, "?>");
6641 }
6642 return;
6643 }
6644 if (cur->type == XML_COMMENT_NODE) {
6645 if (cur->content != NULL) {
6646 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006647 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006648 xmlOutputBufferWriteString(buf, "-->");
6649 }
6650 return;
6651 }
6652 if (cur->type == XML_ENTITY_REF_NODE) {
6653 xmlOutputBufferWriteString(buf, "&");
6654 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6655 xmlOutputBufferWriteString(buf, ";");
6656 return;
6657 }
6658 if (cur->type == XML_CDATA_SECTION_NODE) {
6659 xmlOutputBufferWriteString(buf, "<![CDATA[");
6660 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006661 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006662 xmlOutputBufferWriteString(buf, "]]>");
6663 return;
6664 }
6665
6666 if (format == 1) {
6667 tmp = cur->children;
6668 while (tmp != NULL) {
6669 if ((tmp->type == XML_TEXT_NODE) ||
6670 (tmp->type == XML_ENTITY_REF_NODE)) {
6671 format = 0;
6672 break;
6673 }
6674 tmp = tmp->next;
6675 }
6676 }
6677 xmlOutputBufferWriteString(buf, "<");
6678 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6679 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6680 xmlOutputBufferWriteString(buf, ":");
6681 }
6682
6683 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6684 if (cur->nsDef)
6685 xmlNsListDumpOutput(buf, cur->nsDef);
6686 if (cur->properties != NULL)
6687 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6688
Daniel Veillard7db37732001-07-12 01:20:08 +00006689 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6690 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006691 xmlOutputBufferWriteString(buf, "/>");
6692 return;
6693 }
6694 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006695 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006696 xmlChar *buffer;
6697
Owen Taylor3473f882001-02-23 17:55:21 +00006698 if (encoding == NULL)
6699 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6700 else
6701 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006702 if (buffer != NULL) {
6703 xmlOutputBufferWriteString(buf, (const char *)buffer);
6704 xmlFree(buffer);
6705 }
6706 }
6707 if (cur->children != NULL) {
6708 if (format) xmlOutputBufferWriteString(buf, "\n");
6709 xmlNodeListDumpOutput(buf, doc, cur->children,
6710 (level >= 0?level+1:-1), format, encoding);
6711 if ((xmlIndentTreeOutput) && (format))
6712 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006713 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006714 }
6715 xmlOutputBufferWriteString(buf, "</");
6716 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6717 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6718 xmlOutputBufferWriteString(buf, ":");
6719 }
6720
6721 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6722 xmlOutputBufferWriteString(buf, ">");
6723}
6724
6725/**
6726 * xmlDocContentDumpOutput:
6727 * @buf: the XML buffer output
6728 * @cur: the document
6729 * @encoding: an optional encoding string
6730 * @format: should formatting spaces been added
6731 *
6732 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006733 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6734 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006735 */
6736static void
6737xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6738 const char *encoding, int format) {
6739 xmlOutputBufferWriteString(buf, "<?xml version=");
6740 if (cur->version != NULL)
6741 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6742 else
6743 xmlOutputBufferWriteString(buf, "\"1.0\"");
6744 if (encoding == NULL) {
6745 if (cur->encoding != NULL)
6746 encoding = (const char *) cur->encoding;
6747 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6748 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6749 }
6750 if (encoding != NULL) {
6751 xmlOutputBufferWriteString(buf, " encoding=");
6752 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6753 }
6754 switch (cur->standalone) {
6755 case 0:
6756 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6757 break;
6758 case 1:
6759 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6760 break;
6761 }
6762 xmlOutputBufferWriteString(buf, "?>\n");
6763 if (cur->children != NULL) {
6764 xmlNodePtr child = cur->children;
6765
6766 while (child != NULL) {
6767 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6768 xmlOutputBufferWriteString(buf, "\n");
6769 child = child->next;
6770 }
6771 }
6772}
6773
6774/************************************************************************
6775 * *
6776 * Saving functions front-ends *
6777 * *
6778 ************************************************************************/
6779
6780/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006781 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006782 * @out_doc: Document to generate XML text from
6783 * @doc_txt_ptr: Memory pointer for allocated XML text
6784 * @doc_txt_len: Length of the generated XML text
6785 * @txt_encoding: Character encoding to use when generating XML text
6786 * @format: should formatting spaces been added
6787 *
6788 * Dump the current DOM tree into memory using the character encoding specified
6789 * by the caller. Note it is up to the caller of this function to free the
6790 * allocated memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006791 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6792 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006793 */
6794
6795void
6796xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006797 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006798 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006799 int dummy = 0;
6800
6801 xmlCharEncoding doc_charset;
6802 xmlOutputBufferPtr out_buff = NULL;
6803 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6804
6805 if (doc_txt_len == NULL) {
6806 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6807 }
6808
6809 if (doc_txt_ptr == NULL) {
6810 *doc_txt_len = 0;
6811 xmlGenericError(xmlGenericErrorContext,
6812 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6813 return;
6814 }
6815
6816 *doc_txt_ptr = NULL;
6817 *doc_txt_len = 0;
6818
6819 if (out_doc == NULL) {
6820 /* No document, no output */
6821 xmlGenericError(xmlGenericErrorContext,
6822 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6823 return;
6824 }
6825
6826 /*
6827 * Validate the encoding value, if provided.
6828 * This logic is copied from xmlSaveFileEnc.
6829 */
6830
6831 if (txt_encoding == NULL)
6832 txt_encoding = (const char *) out_doc->encoding;
6833 if (txt_encoding != NULL) {
6834 doc_charset = xmlParseCharEncoding(txt_encoding);
6835
6836 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6837 xmlGenericError(xmlGenericErrorContext,
6838 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6839 return;
6840
6841 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6842 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6843 if ( conv_hdlr == NULL ) {
6844 xmlGenericError(xmlGenericErrorContext,
6845 "%s: %s %s '%s'\n",
6846 "xmlDocDumpFormatMemoryEnc",
6847 "Failed to identify encoding handler for",
6848 "character set",
6849 txt_encoding);
6850 return;
6851 }
6852 }
6853 }
6854
6855 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6856 xmlGenericError(xmlGenericErrorContext,
6857 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6858 return;
6859 }
6860
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006861 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006862 xmlOutputBufferFlush(out_buff);
6863 if (out_buff->conv != NULL) {
6864 *doc_txt_len = out_buff->conv->use;
6865 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6866 } else {
6867 *doc_txt_len = out_buff->buffer->use;
6868 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6869 }
6870 (void)xmlOutputBufferClose(out_buff);
6871
6872 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6873 *doc_txt_len = 0;
6874 xmlGenericError(xmlGenericErrorContext,
6875 "xmlDocDumpFormatMemoryEnc: %s\n",
6876 "Failed to allocate memory for document text representation.");
6877 }
6878
6879 return;
6880}
6881
6882/**
6883 * xmlDocDumpMemory:
6884 * @cur: the document
6885 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006886 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006887 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006888 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006889 * It's up to the caller to free the memory.
6890 */
6891void
6892xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6893 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6894}
6895
6896/**
6897 * xmlDocDumpFormatMemory:
6898 * @cur: the document
6899 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006900 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006901 * @format: should formatting spaces been added
6902 *
6903 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006904 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006905 * It's up to the caller to free the memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006906 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6907 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006908 */
6909void
6910xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6911 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6912}
6913
6914/**
6915 * xmlDocDumpMemoryEnc:
6916 * @out_doc: Document to generate XML text from
6917 * @doc_txt_ptr: Memory pointer for allocated XML text
6918 * @doc_txt_len: Length of the generated XML text
6919 * @txt_encoding: Character encoding to use when generating XML text
6920 *
6921 * Dump the current DOM tree into memory using the character encoding specified
6922 * by the caller. Note it is up to the caller of this function to free the
6923 * allocated memory.
6924 */
6925
6926void
6927xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6928 int * doc_txt_len, const char * txt_encoding) {
6929 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006930 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006931}
6932
6933/**
6934 * xmlGetDocCompressMode:
6935 * @doc: the document
6936 *
6937 * get the compression ratio for a document, ZLIB based
6938 * Returns 0 (uncompressed) to 9 (max compression)
6939 */
6940int
6941xmlGetDocCompressMode (xmlDocPtr doc) {
6942 if (doc == NULL) return(-1);
6943 return(doc->compression);
6944}
6945
6946/**
6947 * xmlSetDocCompressMode:
6948 * @doc: the document
6949 * @mode: the compression ratio
6950 *
6951 * set the compression ratio for a document, ZLIB based
6952 * Correct values: 0 (uncompressed) to 9 (max compression)
6953 */
6954void
6955xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6956 if (doc == NULL) return;
6957 if (mode < 0) doc->compression = 0;
6958 else if (mode > 9) doc->compression = 9;
6959 else doc->compression = mode;
6960}
6961
6962/**
6963 * xmlGetCompressMode:
6964 *
6965 * get the default compression mode used, ZLIB based.
6966 * Returns 0 (uncompressed) to 9 (max compression)
6967 */
6968int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006969xmlGetCompressMode(void)
6970{
6971 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006972}
6973
6974/**
6975 * xmlSetCompressMode:
6976 * @mode: the compression ratio
6977 *
6978 * set the default compression mode used, ZLIB based
6979 * Correct values: 0 (uncompressed) to 9 (max compression)
6980 */
6981void
6982xmlSetCompressMode(int mode) {
6983 if (mode < 0) xmlCompressMode = 0;
6984 else if (mode > 9) xmlCompressMode = 9;
6985 else xmlCompressMode = mode;
6986}
6987
6988/**
Daniel Veillard9e412302002-06-10 15:59:44 +00006989 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00006990 * @f: the FILE*
6991 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00006992 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006993 *
6994 * Dump an XML document to an open FILE.
6995 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006996 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006997 */
6998int
Daniel Veillard9e412302002-06-10 15:59:44 +00006999xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007000 xmlOutputBufferPtr buf;
7001 const char * encoding;
7002 xmlCharEncodingHandlerPtr handler = NULL;
7003 int ret;
7004
7005 if (cur == NULL) {
7006#ifdef DEBUG_TREE
7007 xmlGenericError(xmlGenericErrorContext,
7008 "xmlDocDump : document == NULL\n");
7009#endif
7010 return(-1);
7011 }
7012 encoding = (const char *) cur->encoding;
7013
7014 if (encoding != NULL) {
7015 xmlCharEncoding enc;
7016
7017 enc = xmlParseCharEncoding(encoding);
7018
7019 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7020 xmlGenericError(xmlGenericErrorContext,
7021 "xmlDocDump: document not in UTF8\n");
7022 return(-1);
7023 }
7024 if (enc != XML_CHAR_ENCODING_UTF8) {
7025 handler = xmlFindCharEncodingHandler(encoding);
7026 if (handler == NULL) {
7027 xmlFree((char *) cur->encoding);
7028 cur->encoding = NULL;
7029 }
7030 }
7031 }
7032 buf = xmlOutputBufferCreateFile(f, handler);
7033 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007034 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007035
7036 ret = xmlOutputBufferClose(buf);
7037 return(ret);
7038}
7039
7040/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007041 * xmlDocDump:
7042 * @f: the FILE*
7043 * @cur: the document
7044 *
7045 * Dump an XML document to an open FILE.
7046 *
7047 * returns: the number of bytes written or -1 in case of failure.
7048 */
7049int
7050xmlDocDump(FILE *f, xmlDocPtr cur) {
7051 return(xmlDocFormatDump (f, cur, 0));
7052}
7053
7054/**
Owen Taylor3473f882001-02-23 17:55:21 +00007055 * xmlSaveFileTo:
7056 * @buf: an output I/O buffer
7057 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007058 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007059 *
7060 * Dump an XML document to an I/O buffer.
7061 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007062 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007063 */
7064int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007065xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007066 int ret;
7067
7068 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007069 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007070 ret = xmlOutputBufferClose(buf);
7071 return(ret);
7072}
7073
7074/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007075 * xmlSaveFormatFileTo:
7076 * @buf: an output I/O buffer
7077 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007078 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007079 * @format: should formatting spaces been added
7080 *
7081 * Dump an XML document to an I/O buffer.
7082 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007083 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007084 */
7085int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007086xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007087 int ret;
7088
7089 if (buf == NULL) return(0);
7090 xmlDocContentDumpOutput(buf, cur, encoding, format);
7091 ret = xmlOutputBufferClose(buf);
7092 return(ret);
7093}
7094
7095/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007096 * xmlSaveFormatFileEnc
7097 * @filename: the filename or URL to output
7098 * @cur: the document being saved
7099 * @encoding: the name of the encoding to use or NULL.
7100 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007101 *
7102 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007103 */
7104int
Daniel Veillardf012a642001-07-23 19:10:52 +00007105xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7106 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007107 xmlOutputBufferPtr buf;
7108 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007109 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007110 int ret;
7111
Daniel Veillardfb25a512002-01-13 20:32:08 +00007112 if (encoding == NULL)
7113 encoding = (const char *) cur->encoding;
7114
Owen Taylor3473f882001-02-23 17:55:21 +00007115 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007116
7117 enc = xmlParseCharEncoding(encoding);
7118 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7119 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007120 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007121 return(-1);
7122 }
7123 if (enc != XML_CHAR_ENCODING_UTF8) {
7124 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007125 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007126 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007127 }
7128 }
7129
Daniel Veillardf012a642001-07-23 19:10:52 +00007130#ifdef HAVE_ZLIB_H
7131 if (cur->compression < 0) cur->compression = xmlCompressMode;
7132#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007133 /*
7134 * save the content to a temp buffer.
7135 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007136 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007137 if (buf == NULL) return(-1);
7138
Daniel Veillardf012a642001-07-23 19:10:52 +00007139 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007140
7141 ret = xmlOutputBufferClose(buf);
7142 return(ret);
7143}
7144
Daniel Veillardf012a642001-07-23 19:10:52 +00007145
7146/**
7147 * xmlSaveFileEnc:
7148 * @filename: the filename (or URL)
7149 * @cur: the document
7150 * @encoding: the name of an encoding (or NULL)
7151 *
7152 * Dump an XML document, converting it to the given encoding
7153 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007154 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007155 */
7156int
7157xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7158 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7159}
7160
Owen Taylor3473f882001-02-23 17:55:21 +00007161/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007162 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007163 * @filename: the filename (or URL)
7164 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007165 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007166 *
7167 * Dump an XML document to a file. Will use compression if
7168 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007169 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007170 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007171 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007172 */
7173int
Daniel Veillard67fee942001-04-26 18:59:03 +00007174xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007175 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007176}
7177
Daniel Veillard67fee942001-04-26 18:59:03 +00007178/**
7179 * xmlSaveFile:
7180 * @filename: the filename (or URL)
7181 * @cur: the document
7182 *
7183 * Dump an XML document to a file. Will use compression if
7184 * compiled in and enabled. If @filename is "-" the stdout file is
7185 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007186 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007187 */
7188int
7189xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007190 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007191}
7192