blob: 83bf621cfad242bca853e1e67c0f8ecc900e5209 [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 Veillard6f46f6c2002-08-01 12:22:24 +00004441 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4442 /*
4443 * The XML-1.0 namespace is normally held on the root
4444 * element. In this case exceptionally create it on the
4445 * node element.
4446 */
4447 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4448 if (cur == NULL) {
4449 xmlGenericError(xmlGenericErrorContext,
4450 "xmlSearchNs : malloc failed\n");
4451 return(NULL);
4452 }
4453 memset(cur, 0, sizeof(xmlNs));
4454 cur->type = XML_LOCAL_NAMESPACE;
4455 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4456 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4457 cur->next = node->nsDef;
4458 node->nsDef = cur;
4459 return(cur);
4460 }
Owen Taylor3473f882001-02-23 17:55:21 +00004461 if (doc->oldNs == NULL) {
4462 /*
4463 * Allocate a new Namespace and fill the fields.
4464 */
4465 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4466 if (doc->oldNs == NULL) {
4467 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004468 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004469 return(NULL);
4470 }
4471 memset(doc->oldNs, 0, sizeof(xmlNs));
4472 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4473
4474 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4475 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4476 }
4477 return(doc->oldNs);
4478 }
4479 while (node != NULL) {
4480 if ((node->type == XML_ENTITY_REF_NODE) ||
4481 (node->type == XML_ENTITY_NODE) ||
4482 (node->type == XML_ENTITY_DECL))
4483 return(NULL);
4484 if (node->type == XML_ELEMENT_NODE) {
4485 cur = node->nsDef;
4486 while (cur != NULL) {
4487 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4488 (cur->href != NULL))
4489 return(cur);
4490 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4491 (cur->href != NULL) &&
4492 (xmlStrEqual(cur->prefix, nameSpace)))
4493 return(cur);
4494 cur = cur->next;
4495 }
4496 }
4497 node = node->parent;
4498 }
4499 return(NULL);
4500}
4501
4502/**
4503 * xmlSearchNsByHref:
4504 * @doc: the document
4505 * @node: the current node
4506 * @href: the namespace value
4507 *
4508 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4509 * the defined namespace or return NULL otherwise.
4510 * Returns the namespace pointer or NULL.
4511 */
4512xmlNsPtr
4513xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4514 xmlNsPtr cur;
4515 xmlNodePtr orig = node;
4516
4517 if ((node == NULL) || (href == NULL)) return(NULL);
4518 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004519 /*
4520 * Only the document can hold the XML spec namespace.
4521 */
4522 if (doc == NULL)
4523 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004524 if (doc->oldNs == NULL) {
4525 /*
4526 * Allocate a new Namespace and fill the fields.
4527 */
4528 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4529 if (doc->oldNs == NULL) {
4530 xmlGenericError(xmlGenericErrorContext,
4531 "xmlSearchNsByHref : malloc failed\n");
4532 return(NULL);
4533 }
4534 memset(doc->oldNs, 0, sizeof(xmlNs));
4535 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4536
4537 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4538 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4539 }
4540 return(doc->oldNs);
4541 }
4542 while (node != NULL) {
4543 cur = node->nsDef;
4544 while (cur != NULL) {
4545 if ((cur->href != NULL) && (href != NULL) &&
4546 (xmlStrEqual(cur->href, href))) {
4547 /*
4548 * Check that the prefix is not shadowed between orig and node
4549 */
4550 xmlNodePtr check = orig;
4551 xmlNsPtr tst;
4552
4553 while (check != node) {
4554 tst = check->nsDef;
4555 while (tst != NULL) {
4556 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4557 goto shadowed;
4558 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4559 (xmlStrEqual(tst->prefix, cur->prefix)))
4560 goto shadowed;
4561 tst = tst->next;
4562 }
4563 check = check->parent;
4564 }
4565 return(cur);
4566 }
4567shadowed:
4568 cur = cur->next;
4569 }
4570 node = node->parent;
4571 }
4572 return(NULL);
4573}
4574
4575/**
4576 * xmlNewReconciliedNs
4577 * @doc: the document
4578 * @tree: a node expected to hold the new namespace
4579 * @ns: the original namespace
4580 *
4581 * This function tries to locate a namespace definition in a tree
4582 * ancestors, or create a new namespace definition node similar to
4583 * @ns trying to reuse the same prefix. However if the given prefix is
4584 * null (default namespace) or reused within the subtree defined by
4585 * @tree or on one of its ancestors then a new prefix is generated.
4586 * Returns the (new) namespace definition or NULL in case of error
4587 */
4588xmlNsPtr
4589xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4590 xmlNsPtr def;
4591 xmlChar prefix[50];
4592 int counter = 1;
4593
4594 if (tree == NULL) {
4595#ifdef DEBUG_TREE
4596 xmlGenericError(xmlGenericErrorContext,
4597 "xmlNewReconciliedNs : tree == NULL\n");
4598#endif
4599 return(NULL);
4600 }
4601 if (ns == NULL) {
4602#ifdef DEBUG_TREE
4603 xmlGenericError(xmlGenericErrorContext,
4604 "xmlNewReconciliedNs : ns == NULL\n");
4605#endif
4606 return(NULL);
4607 }
4608 /*
4609 * Search an existing namespace definition inherited.
4610 */
4611 def = xmlSearchNsByHref(doc, tree, ns->href);
4612 if (def != NULL)
4613 return(def);
4614
4615 /*
4616 * Find a close prefix which is not already in use.
4617 * Let's strip namespace prefixes longer than 20 chars !
4618 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004619 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004620 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004621 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004622 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004623
Owen Taylor3473f882001-02-23 17:55:21 +00004624 def = xmlSearchNs(doc, tree, prefix);
4625 while (def != NULL) {
4626 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004627 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004628 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004629 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004630 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004631 def = xmlSearchNs(doc, tree, prefix);
4632 }
4633
4634 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004635 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004636 */
4637 def = xmlNewNs(tree, ns->href, prefix);
4638 return(def);
4639}
4640
4641/**
4642 * xmlReconciliateNs
4643 * @doc: the document
4644 * @tree: a node defining the subtree to reconciliate
4645 *
4646 * This function checks that all the namespaces declared within the given
4647 * tree are properly declared. This is needed for example after Copy or Cut
4648 * and then paste operations. The subtree may still hold pointers to
4649 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004650 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004651 * the new environment. If not possible the new namespaces are redeclared
4652 * on @tree at the top of the given subtree.
4653 * Returns the number of namespace declarations created or -1 in case of error.
4654 */
4655int
4656xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4657 xmlNsPtr *oldNs = NULL;
4658 xmlNsPtr *newNs = NULL;
4659 int sizeCache = 0;
4660 int nbCache = 0;
4661
4662 xmlNsPtr n;
4663 xmlNodePtr node = tree;
4664 xmlAttrPtr attr;
4665 int ret = 0, i;
4666
4667 while (node != NULL) {
4668 /*
4669 * Reconciliate the node namespace
4670 */
4671 if (node->ns != NULL) {
4672 /*
4673 * initialize the cache if needed
4674 */
4675 if (sizeCache == 0) {
4676 sizeCache = 10;
4677 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4678 sizeof(xmlNsPtr));
4679 if (oldNs == NULL) {
4680 xmlGenericError(xmlGenericErrorContext,
4681 "xmlReconciliateNs : memory pbm\n");
4682 return(-1);
4683 }
4684 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4685 sizeof(xmlNsPtr));
4686 if (newNs == NULL) {
4687 xmlGenericError(xmlGenericErrorContext,
4688 "xmlReconciliateNs : memory pbm\n");
4689 xmlFree(oldNs);
4690 return(-1);
4691 }
4692 }
4693 for (i = 0;i < nbCache;i++) {
4694 if (oldNs[i] == node->ns) {
4695 node->ns = newNs[i];
4696 break;
4697 }
4698 }
4699 if (i == nbCache) {
4700 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004701 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004702 */
4703 n = xmlNewReconciliedNs(doc, tree, node->ns);
4704 if (n != NULL) { /* :-( what if else ??? */
4705 /*
4706 * check if we need to grow the cache buffers.
4707 */
4708 if (sizeCache <= nbCache) {
4709 sizeCache *= 2;
4710 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4711 sizeof(xmlNsPtr));
4712 if (oldNs == NULL) {
4713 xmlGenericError(xmlGenericErrorContext,
4714 "xmlReconciliateNs : memory pbm\n");
4715 xmlFree(newNs);
4716 return(-1);
4717 }
4718 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4719 sizeof(xmlNsPtr));
4720 if (newNs == NULL) {
4721 xmlGenericError(xmlGenericErrorContext,
4722 "xmlReconciliateNs : memory pbm\n");
4723 xmlFree(oldNs);
4724 return(-1);
4725 }
4726 }
4727 newNs[nbCache] = n;
4728 oldNs[nbCache++] = node->ns;
4729 node->ns = n;
4730 }
4731 }
4732 }
4733 /*
4734 * now check for namespace hold by attributes on the node.
4735 */
4736 attr = node->properties;
4737 while (attr != NULL) {
4738 if (attr->ns != NULL) {
4739 /*
4740 * initialize the cache if needed
4741 */
4742 if (sizeCache == 0) {
4743 sizeCache = 10;
4744 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4745 sizeof(xmlNsPtr));
4746 if (oldNs == NULL) {
4747 xmlGenericError(xmlGenericErrorContext,
4748 "xmlReconciliateNs : memory pbm\n");
4749 return(-1);
4750 }
4751 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4752 sizeof(xmlNsPtr));
4753 if (newNs == NULL) {
4754 xmlGenericError(xmlGenericErrorContext,
4755 "xmlReconciliateNs : memory pbm\n");
4756 xmlFree(oldNs);
4757 return(-1);
4758 }
4759 }
4760 for (i = 0;i < nbCache;i++) {
4761 if (oldNs[i] == attr->ns) {
4762 node->ns = newNs[i];
4763 break;
4764 }
4765 }
4766 if (i == nbCache) {
4767 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004768 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004769 */
4770 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4771 if (n != NULL) { /* :-( what if else ??? */
4772 /*
4773 * check if we need to grow the cache buffers.
4774 */
4775 if (sizeCache <= nbCache) {
4776 sizeCache *= 2;
4777 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4778 sizeof(xmlNsPtr));
4779 if (oldNs == NULL) {
4780 xmlGenericError(xmlGenericErrorContext,
4781 "xmlReconciliateNs : memory pbm\n");
4782 xmlFree(newNs);
4783 return(-1);
4784 }
4785 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4786 sizeof(xmlNsPtr));
4787 if (newNs == NULL) {
4788 xmlGenericError(xmlGenericErrorContext,
4789 "xmlReconciliateNs : memory pbm\n");
4790 xmlFree(oldNs);
4791 return(-1);
4792 }
4793 }
4794 newNs[nbCache] = n;
4795 oldNs[nbCache++] = attr->ns;
4796 attr->ns = n;
4797 }
4798 }
4799 }
4800 attr = attr->next;
4801 }
4802
4803 /*
4804 * Browse the full subtree, deep first
4805 */
4806 if (node->children != NULL) {
4807 /* deep first */
4808 node = node->children;
4809 } else if ((node != tree) && (node->next != NULL)) {
4810 /* then siblings */
4811 node = node->next;
4812 } else if (node != tree) {
4813 /* go up to parents->next if needed */
4814 while (node != tree) {
4815 if (node->parent != NULL)
4816 node = node->parent;
4817 if ((node != tree) && (node->next != NULL)) {
4818 node = node->next;
4819 break;
4820 }
4821 if (node->parent == NULL) {
4822 node = NULL;
4823 break;
4824 }
4825 }
4826 /* exit condition */
4827 if (node == tree)
4828 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004829 } else
4830 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004831 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004832 if (oldNs != NULL)
4833 xmlFree(oldNs);
4834 if (newNs != NULL)
4835 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004836 return(ret);
4837}
4838
4839/**
4840 * xmlHasProp:
4841 * @node: the node
4842 * @name: the attribute name
4843 *
4844 * Search an attribute associated to a node
4845 * This function also looks in DTD attribute declaration for #FIXED or
4846 * default declaration values unless DTD use has been turned off.
4847 *
4848 * Returns the attribute or the attribute declaration or NULL if
4849 * neither was found.
4850 */
4851xmlAttrPtr
4852xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4853 xmlAttrPtr prop;
4854 xmlDocPtr doc;
4855
4856 if ((node == NULL) || (name == NULL)) return(NULL);
4857 /*
4858 * Check on the properties attached to the node
4859 */
4860 prop = node->properties;
4861 while (prop != NULL) {
4862 if (xmlStrEqual(prop->name, name)) {
4863 return(prop);
4864 }
4865 prop = prop->next;
4866 }
4867 if (!xmlCheckDTD) return(NULL);
4868
4869 /*
4870 * Check if there is a default declaration in the internal
4871 * or external subsets
4872 */
4873 doc = node->doc;
4874 if (doc != NULL) {
4875 xmlAttributePtr attrDecl;
4876 if (doc->intSubset != NULL) {
4877 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4878 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4879 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4880 if (attrDecl != NULL)
4881 return((xmlAttrPtr) attrDecl);
4882 }
4883 }
4884 return(NULL);
4885}
4886
4887/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004888 * xmlHasNsProp:
4889 * @node: the node
4890 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004891 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004892 *
4893 * Search for an attribute associated to a node
4894 * This attribute has to be anchored in the namespace specified.
4895 * This does the entity substitution.
4896 * This function looks in DTD attribute declaration for #FIXED or
4897 * default declaration values unless DTD use has been turned off.
4898 *
4899 * Returns the attribute or the attribute declaration or NULL
4900 * if neither was found.
4901 */
4902xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004903xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004904 xmlAttrPtr prop;
4905 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004906
4907 if (node == NULL)
4908 return(NULL);
4909
4910 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004911 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004912 return(xmlHasProp(node, name));
4913 while (prop != NULL) {
4914 /*
4915 * One need to have
4916 * - same attribute names
4917 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004918 */
4919 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004920 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4921 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004922 }
4923 prop = prop->next;
4924 }
4925 if (!xmlCheckDTD) return(NULL);
4926
4927 /*
4928 * Check if there is a default declaration in the internal
4929 * or external subsets
4930 */
4931 doc = node->doc;
4932 if (doc != NULL) {
4933 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004934 xmlAttributePtr attrDecl = NULL;
4935 xmlNsPtr *nsList, *cur;
4936 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004937
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004938 nsList = xmlGetNsList(node->doc, node);
4939 if (nsList == NULL)
4940 return(NULL);
4941 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4942 ename = xmlStrdup(node->ns->prefix);
4943 ename = xmlStrcat(ename, BAD_CAST ":");
4944 ename = xmlStrcat(ename, node->name);
4945 } else {
4946 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004947 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004948 if (ename == NULL) {
4949 xmlFree(nsList);
4950 return(NULL);
4951 }
4952
4953 cur = nsList;
4954 while (*cur != NULL) {
4955 if (xmlStrEqual((*cur)->href, nameSpace)) {
4956 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4957 name, (*cur)->prefix);
4958 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4959 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4960 name, (*cur)->prefix);
4961 }
4962 cur++;
4963 }
4964 xmlFree(nsList);
4965 xmlFree(ename);
4966 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004967 }
4968 }
4969 return(NULL);
4970}
4971
4972/**
Owen Taylor3473f882001-02-23 17:55:21 +00004973 * xmlGetProp:
4974 * @node: the node
4975 * @name: the attribute name
4976 *
4977 * Search and get the value of an attribute associated to a node
4978 * This does the entity substitution.
4979 * This function looks in DTD attribute declaration for #FIXED or
4980 * default declaration values unless DTD use has been turned off.
4981 *
4982 * Returns the attribute value or NULL if not found.
4983 * It's up to the caller to free the memory.
4984 */
4985xmlChar *
4986xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4987 xmlAttrPtr prop;
4988 xmlDocPtr doc;
4989
4990 if ((node == NULL) || (name == NULL)) return(NULL);
4991 /*
4992 * Check on the properties attached to the node
4993 */
4994 prop = node->properties;
4995 while (prop != NULL) {
4996 if (xmlStrEqual(prop->name, name)) {
4997 xmlChar *ret;
4998
4999 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5000 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5001 return(ret);
5002 }
5003 prop = prop->next;
5004 }
5005 if (!xmlCheckDTD) return(NULL);
5006
5007 /*
5008 * Check if there is a default declaration in the internal
5009 * or external subsets
5010 */
5011 doc = node->doc;
5012 if (doc != NULL) {
5013 xmlAttributePtr attrDecl;
5014 if (doc->intSubset != NULL) {
5015 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5016 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5017 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5018 if (attrDecl != NULL)
5019 return(xmlStrdup(attrDecl->defaultValue));
5020 }
5021 }
5022 return(NULL);
5023}
5024
5025/**
5026 * xmlGetNsProp:
5027 * @node: the node
5028 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005029 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005030 *
5031 * Search and get the value of an attribute associated to a node
5032 * This attribute has to be anchored in the namespace specified.
5033 * This does the entity substitution.
5034 * This function looks in DTD attribute declaration for #FIXED or
5035 * default declaration values unless DTD use has been turned off.
5036 *
5037 * Returns the attribute value or NULL if not found.
5038 * It's up to the caller to free the memory.
5039 */
5040xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005041xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005042 xmlAttrPtr prop;
5043 xmlDocPtr doc;
5044 xmlNsPtr ns;
5045
5046 if (node == NULL)
5047 return(NULL);
5048
5049 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005050 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005051 return(xmlGetProp(node, name));
5052 while (prop != NULL) {
5053 /*
5054 * One need to have
5055 * - same attribute names
5056 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005057 */
5058 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005059 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005060 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005061 xmlChar *ret;
5062
5063 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5064 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5065 return(ret);
5066 }
5067 prop = prop->next;
5068 }
5069 if (!xmlCheckDTD) return(NULL);
5070
5071 /*
5072 * Check if there is a default declaration in the internal
5073 * or external subsets
5074 */
5075 doc = node->doc;
5076 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005077 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005078 xmlAttributePtr attrDecl;
5079
Owen Taylor3473f882001-02-23 17:55:21 +00005080 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5081 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5082 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5083
5084 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5085 /*
5086 * The DTD declaration only allows a prefix search
5087 */
5088 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005089 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005090 return(xmlStrdup(attrDecl->defaultValue));
5091 }
5092 }
5093 }
5094 return(NULL);
5095}
5096
5097/**
5098 * xmlSetProp:
5099 * @node: the node
5100 * @name: the attribute name
5101 * @value: the attribute value
5102 *
5103 * Set (or reset) an attribute carried by a node.
5104 * Returns the attribute pointer.
5105 */
5106xmlAttrPtr
5107xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005108 xmlAttrPtr prop;
5109 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005110
5111 if ((node == NULL) || (name == NULL))
5112 return(NULL);
5113 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005114 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005115 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005116 if ((xmlStrEqual(prop->name, name)) &&
5117 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005118 xmlNodePtr oldprop = prop->children;
5119
Owen Taylor3473f882001-02-23 17:55:21 +00005120 prop->children = NULL;
5121 prop->last = NULL;
5122 if (value != NULL) {
5123 xmlChar *buffer;
5124 xmlNodePtr tmp;
5125
5126 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5127 prop->children = xmlStringGetNodeList(node->doc, buffer);
5128 prop->last = NULL;
5129 prop->doc = doc;
5130 tmp = prop->children;
5131 while (tmp != NULL) {
5132 tmp->parent = (xmlNodePtr) prop;
5133 tmp->doc = doc;
5134 if (tmp->next == NULL)
5135 prop->last = tmp;
5136 tmp = tmp->next;
5137 }
5138 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005139 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005140 if (oldprop != NULL)
5141 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005142 return(prop);
5143 }
5144 prop = prop->next;
5145 }
5146 prop = xmlNewProp(node, name, value);
5147 return(prop);
5148}
5149
5150/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005151 * xmlUnsetProp:
5152 * @node: the node
5153 * @name: the attribute name
5154 *
5155 * Remove an attribute carried by a node.
5156 * Returns 0 if successful, -1 if not found
5157 */
5158int
5159xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5160 xmlAttrPtr prop = node->properties, prev = NULL;;
5161
5162 if ((node == NULL) || (name == NULL))
5163 return(-1);
5164 while (prop != NULL) {
5165 if ((xmlStrEqual(prop->name, name)) &&
5166 (prop->ns == NULL)) {
5167 if (prev == NULL)
5168 node->properties = prop->next;
5169 else
5170 prev->next = prop->next;
5171 xmlFreeProp(prop);
5172 return(0);
5173 }
5174 prev = prop;
5175 prop = prop->next;
5176 }
5177 return(-1);
5178}
5179
5180/**
Owen Taylor3473f882001-02-23 17:55:21 +00005181 * xmlSetNsProp:
5182 * @node: the node
5183 * @ns: the namespace definition
5184 * @name: the attribute name
5185 * @value: the attribute value
5186 *
5187 * Set (or reset) an attribute carried by a node.
5188 * The ns structure must be in scope, this is not checked.
5189 *
5190 * Returns the attribute pointer.
5191 */
5192xmlAttrPtr
5193xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5194 const xmlChar *value) {
5195 xmlAttrPtr prop;
5196
5197 if ((node == NULL) || (name == NULL))
5198 return(NULL);
5199
5200 if (ns == NULL)
5201 return(xmlSetProp(node, name, value));
5202 if (ns->href == NULL)
5203 return(NULL);
5204 prop = node->properties;
5205
5206 while (prop != NULL) {
5207 /*
5208 * One need to have
5209 * - same attribute names
5210 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005211 */
5212 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005213 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005214 if (prop->children != NULL)
5215 xmlFreeNodeList(prop->children);
5216 prop->children = NULL;
5217 prop->last = NULL;
5218 prop->ns = ns;
5219 if (value != NULL) {
5220 xmlChar *buffer;
5221 xmlNodePtr tmp;
5222
5223 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5224 prop->children = xmlStringGetNodeList(node->doc, buffer);
5225 prop->last = NULL;
5226 tmp = prop->children;
5227 while (tmp != NULL) {
5228 tmp->parent = (xmlNodePtr) prop;
5229 if (tmp->next == NULL)
5230 prop->last = tmp;
5231 tmp = tmp->next;
5232 }
5233 xmlFree(buffer);
5234 }
5235 return(prop);
5236 }
5237 prop = prop->next;
5238 }
5239 prop = xmlNewNsProp(node, ns, name, value);
5240 return(prop);
5241}
5242
5243/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005244 * xmlUnsetNsProp:
5245 * @node: the node
5246 * @ns: the namespace definition
5247 * @name: the attribute name
5248 *
5249 * Remove an attribute carried by a node.
5250 * Returns 0 if successful, -1 if not found
5251 */
5252int
5253xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5254 xmlAttrPtr prop = node->properties, prev = NULL;;
5255
5256 if ((node == NULL) || (name == NULL))
5257 return(-1);
5258 if (ns == NULL)
5259 return(xmlUnsetProp(node, name));
5260 if (ns->href == NULL)
5261 return(-1);
5262 while (prop != NULL) {
5263 if ((xmlStrEqual(prop->name, name)) &&
5264 (((prop->ns == NULL) && (node->ns != NULL) &&
5265 (xmlStrEqual(node->ns->href, ns->href))) ||
5266 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5267 if (prev == NULL)
5268 node->properties = prop->next;
5269 else
5270 prev->next = prop->next;
5271 xmlFreeProp(prop);
5272 return(0);
5273 }
5274 prev = prop;
5275 prop = prop->next;
5276 }
5277 return(-1);
5278}
5279
5280/**
Owen Taylor3473f882001-02-23 17:55:21 +00005281 * xmlNodeIsText:
5282 * @node: the node
5283 *
5284 * Is this node a Text node ?
5285 * Returns 1 yes, 0 no
5286 */
5287int
5288xmlNodeIsText(xmlNodePtr node) {
5289 if (node == NULL) return(0);
5290
5291 if (node->type == XML_TEXT_NODE) return(1);
5292 return(0);
5293}
5294
5295/**
5296 * xmlIsBlankNode:
5297 * @node: the node
5298 *
5299 * Checks whether this node is an empty or whitespace only
5300 * (and possibly ignorable) text-node.
5301 *
5302 * Returns 1 yes, 0 no
5303 */
5304int
5305xmlIsBlankNode(xmlNodePtr node) {
5306 const xmlChar *cur;
5307 if (node == NULL) return(0);
5308
Daniel Veillard7db37732001-07-12 01:20:08 +00005309 if ((node->type != XML_TEXT_NODE) &&
5310 (node->type != XML_CDATA_SECTION_NODE))
5311 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005312 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005313 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005314 while (*cur != 0) {
5315 if (!IS_BLANK(*cur)) return(0);
5316 cur++;
5317 }
5318
5319 return(1);
5320}
5321
5322/**
5323 * xmlTextConcat:
5324 * @node: the node
5325 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005326 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005327 *
5328 * Concat the given string at the end of the existing node content
5329 */
5330
5331void
5332xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5333 if (node == NULL) return;
5334
5335 if ((node->type != XML_TEXT_NODE) &&
5336 (node->type != XML_CDATA_SECTION_NODE)) {
5337#ifdef DEBUG_TREE
5338 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005339 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005340#endif
5341 return;
5342 }
Owen Taylor3473f882001-02-23 17:55:21 +00005343 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005344}
5345
5346/************************************************************************
5347 * *
5348 * Output : to a FILE or in memory *
5349 * *
5350 ************************************************************************/
5351
Owen Taylor3473f882001-02-23 17:55:21 +00005352/**
5353 * xmlBufferCreate:
5354 *
5355 * routine to create an XML buffer.
5356 * returns the new structure.
5357 */
5358xmlBufferPtr
5359xmlBufferCreate(void) {
5360 xmlBufferPtr ret;
5361
5362 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5363 if (ret == NULL) {
5364 xmlGenericError(xmlGenericErrorContext,
5365 "xmlBufferCreate : out of memory!\n");
5366 return(NULL);
5367 }
5368 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005369 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005370 ret->alloc = xmlBufferAllocScheme;
5371 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5372 if (ret->content == NULL) {
5373 xmlGenericError(xmlGenericErrorContext,
5374 "xmlBufferCreate : out of memory!\n");
5375 xmlFree(ret);
5376 return(NULL);
5377 }
5378 ret->content[0] = 0;
5379 return(ret);
5380}
5381
5382/**
5383 * xmlBufferCreateSize:
5384 * @size: initial size of buffer
5385 *
5386 * routine to create an XML buffer.
5387 * returns the new structure.
5388 */
5389xmlBufferPtr
5390xmlBufferCreateSize(size_t size) {
5391 xmlBufferPtr ret;
5392
5393 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5394 if (ret == NULL) {
5395 xmlGenericError(xmlGenericErrorContext,
5396 "xmlBufferCreate : out of memory!\n");
5397 return(NULL);
5398 }
5399 ret->use = 0;
5400 ret->alloc = xmlBufferAllocScheme;
5401 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5402 if (ret->size){
5403 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5404 if (ret->content == NULL) {
5405 xmlGenericError(xmlGenericErrorContext,
5406 "xmlBufferCreate : out of memory!\n");
5407 xmlFree(ret);
5408 return(NULL);
5409 }
5410 ret->content[0] = 0;
5411 } else
5412 ret->content = NULL;
5413 return(ret);
5414}
5415
5416/**
5417 * xmlBufferSetAllocationScheme:
5418 * @buf: the buffer to free
5419 * @scheme: allocation scheme to use
5420 *
5421 * Sets the allocation scheme for this buffer
5422 */
5423void
5424xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5425 xmlBufferAllocationScheme scheme) {
5426 if (buf == NULL) {
5427#ifdef DEBUG_BUFFER
5428 xmlGenericError(xmlGenericErrorContext,
5429 "xmlBufferSetAllocationScheme: buf == NULL\n");
5430#endif
5431 return;
5432 }
5433
5434 buf->alloc = scheme;
5435}
5436
5437/**
5438 * xmlBufferFree:
5439 * @buf: the buffer to free
5440 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005441 * Frees an XML buffer. It frees both the content and the structure which
5442 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005443 */
5444void
5445xmlBufferFree(xmlBufferPtr buf) {
5446 if (buf == NULL) {
5447#ifdef DEBUG_BUFFER
5448 xmlGenericError(xmlGenericErrorContext,
5449 "xmlBufferFree: buf == NULL\n");
5450#endif
5451 return;
5452 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005453 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005454 xmlFree(buf->content);
5455 }
Owen Taylor3473f882001-02-23 17:55:21 +00005456 xmlFree(buf);
5457}
5458
5459/**
5460 * xmlBufferEmpty:
5461 * @buf: the buffer
5462 *
5463 * empty a buffer.
5464 */
5465void
5466xmlBufferEmpty(xmlBufferPtr buf) {
5467 if (buf->content == NULL) return;
5468 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005469 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005470}
5471
5472/**
5473 * xmlBufferShrink:
5474 * @buf: the buffer to dump
5475 * @len: the number of xmlChar to remove
5476 *
5477 * Remove the beginning of an XML buffer.
5478 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005479 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005480 */
5481int
5482xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5483 if (len == 0) return(0);
5484 if (len > buf->use) return(-1);
5485
5486 buf->use -= len;
5487 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5488
5489 buf->content[buf->use] = 0;
5490 return(len);
5491}
5492
5493/**
5494 * xmlBufferGrow:
5495 * @buf: the buffer
5496 * @len: the minimum free size to allocate
5497 *
5498 * Grow the available space of an XML buffer.
5499 *
5500 * Returns the new available space or -1 in case of error
5501 */
5502int
5503xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5504 int size;
5505 xmlChar *newbuf;
5506
5507 if (len + buf->use < buf->size) return(0);
5508
5509 size = buf->use + len + 100;
5510
5511 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5512 if (newbuf == NULL) return(-1);
5513 buf->content = newbuf;
5514 buf->size = size;
5515 return(buf->size - buf->use);
5516}
5517
5518/**
5519 * xmlBufferDump:
5520 * @file: the file output
5521 * @buf: the buffer to dump
5522 *
5523 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005524 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005525 */
5526int
5527xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5528 int ret;
5529
5530 if (buf == NULL) {
5531#ifdef DEBUG_BUFFER
5532 xmlGenericError(xmlGenericErrorContext,
5533 "xmlBufferDump: buf == NULL\n");
5534#endif
5535 return(0);
5536 }
5537 if (buf->content == NULL) {
5538#ifdef DEBUG_BUFFER
5539 xmlGenericError(xmlGenericErrorContext,
5540 "xmlBufferDump: buf->content == NULL\n");
5541#endif
5542 return(0);
5543 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005544 if (file == NULL)
5545 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005546 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5547 return(ret);
5548}
5549
5550/**
5551 * xmlBufferContent:
5552 * @buf: the buffer
5553 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005554 * Function to extract the content of a buffer
5555 *
Owen Taylor3473f882001-02-23 17:55:21 +00005556 * Returns the internal content
5557 */
5558
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005559const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005560xmlBufferContent(const xmlBufferPtr buf)
5561{
5562 if(!buf)
5563 return NULL;
5564
5565 return buf->content;
5566}
5567
5568/**
5569 * xmlBufferLength:
5570 * @buf: the buffer
5571 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005572 * Function to get the length of a buffer
5573 *
Owen Taylor3473f882001-02-23 17:55:21 +00005574 * Returns the length of data in the internal content
5575 */
5576
5577int
5578xmlBufferLength(const xmlBufferPtr buf)
5579{
5580 if(!buf)
5581 return 0;
5582
5583 return buf->use;
5584}
5585
5586/**
5587 * xmlBufferResize:
5588 * @buf: the buffer to resize
5589 * @size: the desired size
5590 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005591 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005592 *
5593 * Returns 0 in case of problems, 1 otherwise
5594 */
5595int
5596xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5597{
5598 unsigned int newSize;
5599 xmlChar* rebuf = NULL;
5600
5601 /*take care of empty case*/
5602 newSize = (buf->size ? buf->size*2 : size);
5603
5604 /* Don't resize if we don't have to */
5605 if (size < buf->size)
5606 return 1;
5607
5608 /* figure out new size */
5609 switch (buf->alloc){
5610 case XML_BUFFER_ALLOC_DOUBLEIT:
5611 while (size > newSize) newSize *= 2;
5612 break;
5613 case XML_BUFFER_ALLOC_EXACT:
5614 newSize = size+10;
5615 break;
5616 default:
5617 newSize = size+10;
5618 break;
5619 }
5620
5621 if (buf->content == NULL)
5622 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5623 else
5624 rebuf = (xmlChar *) xmlRealloc(buf->content,
5625 newSize * sizeof(xmlChar));
5626 if (rebuf == NULL) {
5627 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005628 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005629 return 0;
5630 }
5631 buf->content = rebuf;
5632 buf->size = newSize;
5633
5634 return 1;
5635}
5636
5637/**
5638 * xmlBufferAdd:
5639 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005640 * @str: the #xmlChar string
5641 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005642 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005643 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005644 * str is recomputed.
5645 */
5646void
5647xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5648 unsigned int needSize;
5649
5650 if (str == NULL) {
5651#ifdef DEBUG_BUFFER
5652 xmlGenericError(xmlGenericErrorContext,
5653 "xmlBufferAdd: str == NULL\n");
5654#endif
5655 return;
5656 }
5657 if (len < -1) {
5658#ifdef DEBUG_BUFFER
5659 xmlGenericError(xmlGenericErrorContext,
5660 "xmlBufferAdd: len < 0\n");
5661#endif
5662 return;
5663 }
5664 if (len == 0) return;
5665
5666 if (len < 0)
5667 len = xmlStrlen(str);
5668
5669 if (len <= 0) return;
5670
5671 needSize = buf->use + len + 2;
5672 if (needSize > buf->size){
5673 if (!xmlBufferResize(buf, needSize)){
5674 xmlGenericError(xmlGenericErrorContext,
5675 "xmlBufferAdd : out of memory!\n");
5676 return;
5677 }
5678 }
5679
5680 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5681 buf->use += len;
5682 buf->content[buf->use] = 0;
5683}
5684
5685/**
5686 * xmlBufferAddHead:
5687 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005688 * @str: the #xmlChar string
5689 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005690 *
5691 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005692 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005693 */
5694void
5695xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5696 unsigned int needSize;
5697
5698 if (str == NULL) {
5699#ifdef DEBUG_BUFFER
5700 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005701 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005702#endif
5703 return;
5704 }
5705 if (len < -1) {
5706#ifdef DEBUG_BUFFER
5707 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005708 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005709#endif
5710 return;
5711 }
5712 if (len == 0) return;
5713
5714 if (len < 0)
5715 len = xmlStrlen(str);
5716
5717 if (len <= 0) return;
5718
5719 needSize = buf->use + len + 2;
5720 if (needSize > buf->size){
5721 if (!xmlBufferResize(buf, needSize)){
5722 xmlGenericError(xmlGenericErrorContext,
5723 "xmlBufferAddHead : out of memory!\n");
5724 return;
5725 }
5726 }
5727
5728 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5729 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5730 buf->use += len;
5731 buf->content[buf->use] = 0;
5732}
5733
5734/**
5735 * xmlBufferCat:
5736 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005737 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005738 *
5739 * Append a zero terminated string to an XML buffer.
5740 */
5741void
5742xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5743 if (str != NULL)
5744 xmlBufferAdd(buf, str, -1);
5745}
5746
5747/**
5748 * xmlBufferCCat:
5749 * @buf: the buffer to dump
5750 * @str: the C char string
5751 *
5752 * Append a zero terminated C string to an XML buffer.
5753 */
5754void
5755xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5756 const char *cur;
5757
5758 if (str == NULL) {
5759#ifdef DEBUG_BUFFER
5760 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005761 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005762#endif
5763 return;
5764 }
5765 for (cur = str;*cur != 0;cur++) {
5766 if (buf->use + 10 >= buf->size) {
5767 if (!xmlBufferResize(buf, buf->use+10)){
5768 xmlGenericError(xmlGenericErrorContext,
5769 "xmlBufferCCat : out of memory!\n");
5770 return;
5771 }
5772 }
5773 buf->content[buf->use++] = *cur;
5774 }
5775 buf->content[buf->use] = 0;
5776}
5777
5778/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005779 * xmlBufferWriteXmlCHAR:
5780 * @buf: the XML buffer
5781 * @string: the string to add
5782 *
5783 * For VMS only.
5784 * routine which manages and grows an output buffer. This one adds
5785 * xmlChars at the end of the buffer.
5786 */
5787/**
Owen Taylor3473f882001-02-23 17:55:21 +00005788 * xmlBufferWriteCHAR:
5789 * @buf: the XML buffer
5790 * @string: the string to add
5791 *
5792 * routine which manages and grows an output buffer. This one adds
5793 * xmlChars at the end of the buffer.
5794 */
5795void
5796#ifdef VMS
5797xmlBufferWriteXmlCHAR
5798#else
5799xmlBufferWriteCHAR
5800#endif
5801(xmlBufferPtr buf, const xmlChar *string) {
5802 xmlBufferCat(buf, string);
5803}
5804
5805/**
5806 * xmlBufferWriteChar:
5807 * @buf: the XML buffer output
5808 * @string: the string to add
5809 *
5810 * routine which manage and grows an output buffer. This one add
5811 * C chars at the end of the array.
5812 */
5813void
5814xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5815 xmlBufferCCat(buf, string);
5816}
5817
5818
5819/**
5820 * xmlBufferWriteQuotedString:
5821 * @buf: the XML buffer output
5822 * @string: the string to add
5823 *
5824 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005825 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005826 * quote or double-quotes internally
5827 */
5828void
5829xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5830 if (xmlStrchr(string, '"')) {
5831 if (xmlStrchr(string, '\'')) {
5832#ifdef DEBUG_BUFFER
5833 xmlGenericError(xmlGenericErrorContext,
5834 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5835#endif
5836 }
5837 xmlBufferCCat(buf, "'");
5838 xmlBufferCat(buf, string);
5839 xmlBufferCCat(buf, "'");
5840 } else {
5841 xmlBufferCCat(buf, "\"");
5842 xmlBufferCat(buf, string);
5843 xmlBufferCCat(buf, "\"");
5844 }
5845}
5846
5847
5848/************************************************************************
5849 * *
5850 * Dumping XML tree content to a simple buffer *
5851 * *
5852 ************************************************************************/
5853
Owen Taylor3473f882001-02-23 17:55:21 +00005854static void
5855xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5856 int format);
5857void
5858htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5859
5860/**
5861 * xmlNsDump:
5862 * @buf: the XML buffer output
5863 * @cur: a namespace
5864 *
5865 * Dump a local Namespace definition.
5866 * Should be called in the context of attributes dumps.
5867 */
5868static void
5869xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5870 if (cur == NULL) {
5871#ifdef DEBUG_TREE
5872 xmlGenericError(xmlGenericErrorContext,
5873 "xmlNsDump : Ns == NULL\n");
5874#endif
5875 return;
5876 }
5877 if (cur->type == XML_LOCAL_NAMESPACE) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005878 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
5879 return;
5880
Owen Taylor3473f882001-02-23 17:55:21 +00005881 /* Within the context of an element attributes */
5882 if (cur->prefix != NULL) {
5883 xmlBufferWriteChar(buf, " xmlns:");
5884 xmlBufferWriteCHAR(buf, cur->prefix);
5885 } else
5886 xmlBufferWriteChar(buf, " xmlns");
5887 xmlBufferWriteChar(buf, "=");
5888 xmlBufferWriteQuotedString(buf, cur->href);
5889 }
5890}
5891
5892/**
5893 * xmlNsListDump:
5894 * @buf: the XML buffer output
5895 * @cur: the first namespace
5896 *
5897 * Dump a list of local Namespace definitions.
5898 * Should be called in the context of attributes dumps.
5899 */
5900static void
5901xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5902 while (cur != NULL) {
5903 xmlNsDump(buf, cur);
5904 cur = cur->next;
5905 }
5906}
5907
5908/**
5909 * xmlDtdDump:
5910 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005911 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005912 *
5913 * Dump the XML document DTD, if any.
5914 */
5915static void
5916xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5917 if (dtd == NULL) {
5918#ifdef DEBUG_TREE
5919 xmlGenericError(xmlGenericErrorContext,
5920 "xmlDtdDump : no internal subset\n");
5921#endif
5922 return;
5923 }
5924 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5925 xmlBufferWriteCHAR(buf, dtd->name);
5926 if (dtd->ExternalID != NULL) {
5927 xmlBufferWriteChar(buf, " PUBLIC ");
5928 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5929 xmlBufferWriteChar(buf, " ");
5930 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5931 } else if (dtd->SystemID != NULL) {
5932 xmlBufferWriteChar(buf, " SYSTEM ");
5933 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5934 }
5935 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5936 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5937 xmlBufferWriteChar(buf, ">");
5938 return;
5939 }
5940 xmlBufferWriteChar(buf, " [\n");
5941 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5942#if 0
5943 if (dtd->entities != NULL)
5944 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5945 if (dtd->notations != NULL)
5946 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5947 if (dtd->elements != NULL)
5948 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5949 if (dtd->attributes != NULL)
5950 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5951#endif
5952 xmlBufferWriteChar(buf, "]>");
5953}
5954
5955/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005956 * xmlAttrSerializeContent:
5957 * @buf: the XML buffer output
5958 * @doc: the document
5959 * @attr: the attribute pointer
5960 *
5961 * Serialize the attribute in the buffer
5962 */
5963static void
5964xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5965 const xmlChar *cur, *base;
5966 xmlNodePtr children;
5967
5968 children = attr->children;
5969 while (children != NULL) {
5970 switch (children->type) {
5971 case XML_TEXT_NODE:
5972 base = cur = children->content;
5973 while (*cur != 0) {
5974 if (*cur == '\n') {
5975 if (base != cur)
5976 xmlBufferAdd(buf, base, cur - base);
5977 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5978 cur++;
5979 base = cur;
5980#if 0
5981 } else if (*cur == '\'') {
5982 if (base != cur)
5983 xmlBufferAdd(buf, base, cur - base);
5984 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5985 cur++;
5986 base = cur;
5987#endif
5988 } else if (*cur == '"') {
5989 if (base != cur)
5990 xmlBufferAdd(buf, base, cur - base);
5991 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5992 cur++;
5993 base = cur;
5994 } else if (*cur == '<') {
5995 if (base != cur)
5996 xmlBufferAdd(buf, base, cur - base);
5997 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
5998 cur++;
5999 base = cur;
6000 } else if (*cur == '>') {
6001 if (base != cur)
6002 xmlBufferAdd(buf, base, cur - base);
6003 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6004 cur++;
6005 base = cur;
6006 } else if (*cur == '&') {
6007 if (base != cur)
6008 xmlBufferAdd(buf, base, cur - base);
6009 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6010 cur++;
6011 base = cur;
6012 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6013 (doc->encoding == NULL))) {
6014 /*
6015 * We assume we have UTF-8 content.
6016 */
6017 char tmp[10];
6018 int val = 0, l = 1;
6019
6020 if (base != cur)
6021 xmlBufferAdd(buf, base, cur - base);
6022 if (*cur < 0xC0) {
6023 xmlGenericError(xmlGenericErrorContext,
6024 "xmlAttrSerializeContent : input not UTF-8\n");
6025 if (doc != NULL)
6026 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6027 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6028 tmp[sizeof(tmp) - 1] = 0;
6029 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6030 cur++;
6031 base = cur;
6032 continue;
6033 } else if (*cur < 0xE0) {
6034 val = (cur[0]) & 0x1F;
6035 val <<= 6;
6036 val |= (cur[1]) & 0x3F;
6037 l = 2;
6038 } else if (*cur < 0xF0) {
6039 val = (cur[0]) & 0x0F;
6040 val <<= 6;
6041 val |= (cur[1]) & 0x3F;
6042 val <<= 6;
6043 val |= (cur[2]) & 0x3F;
6044 l = 3;
6045 } else if (*cur < 0xF8) {
6046 val = (cur[0]) & 0x07;
6047 val <<= 6;
6048 val |= (cur[1]) & 0x3F;
6049 val <<= 6;
6050 val |= (cur[2]) & 0x3F;
6051 val <<= 6;
6052 val |= (cur[3]) & 0x3F;
6053 l = 4;
6054 }
6055 if ((l == 1) || (!IS_CHAR(val))) {
6056 xmlGenericError(xmlGenericErrorContext,
6057 "xmlAttrSerializeContent : char out of range\n");
6058 if (doc != NULL)
6059 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6060 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6061 tmp[sizeof(tmp) - 1] = 0;
6062 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6063 cur++;
6064 base = cur;
6065 continue;
6066 }
6067 /*
6068 * We could do multiple things here. Just save
6069 * as a char ref
6070 */
6071 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6072 tmp[sizeof(tmp) - 1] = 0;
6073 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6074 cur += l;
6075 base = cur;
6076 } else {
6077 cur++;
6078 }
6079 }
6080 if (base != cur)
6081 xmlBufferAdd(buf, base, cur - base);
6082 break;
6083 case XML_ENTITY_REF_NODE:
6084 xmlBufferAdd(buf, BAD_CAST "&", 1);
6085 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6086 xmlBufferAdd(buf, BAD_CAST ";", 1);
6087 break;
6088 default:
6089 /* should not happen unless we have a badly built tree */
6090 break;
6091 }
6092 children = children->next;
6093 }
6094}
6095
6096/**
Owen Taylor3473f882001-02-23 17:55:21 +00006097 * xmlAttrDump:
6098 * @buf: the XML buffer output
6099 * @doc: the document
6100 * @cur: the attribute pointer
6101 *
6102 * Dump an XML attribute
6103 */
6104static void
6105xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006106 if (cur == NULL) {
6107#ifdef DEBUG_TREE
6108 xmlGenericError(xmlGenericErrorContext,
6109 "xmlAttrDump : property == NULL\n");
6110#endif
6111 return;
6112 }
6113 xmlBufferWriteChar(buf, " ");
6114 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6115 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6116 xmlBufferWriteChar(buf, ":");
6117 }
6118 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006119 xmlBufferWriteChar(buf, "=\"");
6120 xmlAttrSerializeContent(buf, doc, cur);
6121 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006122}
6123
6124/**
6125 * xmlAttrListDump:
6126 * @buf: the XML buffer output
6127 * @doc: the document
6128 * @cur: the first attribute pointer
6129 *
6130 * Dump a list of XML attributes
6131 */
6132static void
6133xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6134 if (cur == NULL) {
6135#ifdef DEBUG_TREE
6136 xmlGenericError(xmlGenericErrorContext,
6137 "xmlAttrListDump : property == NULL\n");
6138#endif
6139 return;
6140 }
6141 while (cur != NULL) {
6142 xmlAttrDump(buf, doc, cur);
6143 cur = cur->next;
6144 }
6145}
6146
6147
6148
6149/**
6150 * xmlNodeListDump:
6151 * @buf: the XML buffer output
6152 * @doc: the document
6153 * @cur: the first node
6154 * @level: the imbrication level for indenting
6155 * @format: is formatting allowed
6156 *
6157 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006158 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6159 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006160 */
6161static void
6162xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6163 int format) {
6164 int i;
6165
6166 if (cur == NULL) {
6167#ifdef DEBUG_TREE
6168 xmlGenericError(xmlGenericErrorContext,
6169 "xmlNodeListDump : node == NULL\n");
6170#endif
6171 return;
6172 }
6173 while (cur != NULL) {
6174 if ((format) && (xmlIndentTreeOutput) &&
6175 (cur->type == XML_ELEMENT_NODE))
6176 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006177 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006178 xmlNodeDump(buf, doc, cur, level, format);
6179 if (format) {
6180 xmlBufferWriteChar(buf, "\n");
6181 }
6182 cur = cur->next;
6183 }
6184}
6185
6186/**
6187 * xmlNodeDump:
6188 * @buf: the XML buffer output
6189 * @doc: the document
6190 * @cur: the current node
6191 * @level: the imbrication level for indenting
6192 * @format: is formatting allowed
6193 *
6194 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006195 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6196 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006197 */
6198void
6199xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6200 int format) {
6201 int i;
6202 xmlNodePtr tmp;
6203
6204 if (cur == NULL) {
6205#ifdef DEBUG_TREE
6206 xmlGenericError(xmlGenericErrorContext,
6207 "xmlNodeDump : node == NULL\n");
6208#endif
6209 return;
6210 }
6211 if (cur->type == XML_XINCLUDE_START)
6212 return;
6213 if (cur->type == XML_XINCLUDE_END)
6214 return;
6215 if (cur->type == XML_DTD_NODE) {
6216 xmlDtdDump(buf, (xmlDtdPtr) cur);
6217 return;
6218 }
6219 if (cur->type == XML_ELEMENT_DECL) {
6220 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6221 return;
6222 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006223 if (cur->type == XML_ATTRIBUTE_NODE){
6224 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6225 return;
6226 }
Owen Taylor3473f882001-02-23 17:55:21 +00006227 if (cur->type == XML_ATTRIBUTE_DECL) {
6228 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6229 return;
6230 }
6231 if (cur->type == XML_ENTITY_DECL) {
6232 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6233 return;
6234 }
6235 if (cur->type == XML_TEXT_NODE) {
6236 if (cur->content != NULL) {
6237 if ((cur->name == xmlStringText) ||
6238 (cur->name != xmlStringTextNoenc)) {
6239 xmlChar *buffer;
6240
Owen Taylor3473f882001-02-23 17:55:21 +00006241 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006242 if (buffer != NULL) {
6243 xmlBufferWriteCHAR(buf, buffer);
6244 xmlFree(buffer);
6245 }
6246 } else {
6247 /*
6248 * Disable escaping, needed for XSLT
6249 */
Owen Taylor3473f882001-02-23 17:55:21 +00006250 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006251 }
6252 }
6253 return;
6254 }
6255 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006256 xmlBufferWriteChar(buf, "<?");
6257 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006258 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006259 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006260 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006261 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006262 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006263 return;
6264 }
6265 if (cur->type == XML_COMMENT_NODE) {
6266 if (cur->content != NULL) {
6267 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006268 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006269 xmlBufferWriteChar(buf, "-->");
6270 }
6271 return;
6272 }
6273 if (cur->type == XML_ENTITY_REF_NODE) {
6274 xmlBufferWriteChar(buf, "&");
6275 xmlBufferWriteCHAR(buf, cur->name);
6276 xmlBufferWriteChar(buf, ";");
6277 return;
6278 }
6279 if (cur->type == XML_CDATA_SECTION_NODE) {
6280 xmlBufferWriteChar(buf, "<![CDATA[");
6281 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006282 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006283 xmlBufferWriteChar(buf, "]]>");
6284 return;
6285 }
6286
6287 if (format == 1) {
6288 tmp = cur->children;
6289 while (tmp != NULL) {
6290 if ((tmp->type == XML_TEXT_NODE) ||
6291 (tmp->type == XML_ENTITY_REF_NODE)) {
6292 format = 0;
6293 break;
6294 }
6295 tmp = tmp->next;
6296 }
6297 }
6298 xmlBufferWriteChar(buf, "<");
6299 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6300 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6301 xmlBufferWriteChar(buf, ":");
6302 }
6303
6304 xmlBufferWriteCHAR(buf, cur->name);
6305 if (cur->nsDef)
6306 xmlNsListDump(buf, cur->nsDef);
6307 if (cur->properties != NULL)
6308 xmlAttrListDump(buf, doc, cur->properties);
6309
Daniel Veillard7db37732001-07-12 01:20:08 +00006310 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6311 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006312 (!xmlSaveNoEmptyTags)) {
6313 xmlBufferWriteChar(buf, "/>");
6314 return;
6315 }
6316 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006317 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006318 xmlChar *buffer;
6319
Owen Taylor3473f882001-02-23 17:55:21 +00006320 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006321 if (buffer != NULL) {
6322 xmlBufferWriteCHAR(buf, buffer);
6323 xmlFree(buffer);
6324 }
6325 }
6326 if (cur->children != NULL) {
6327 if (format) xmlBufferWriteChar(buf, "\n");
6328 xmlNodeListDump(buf, doc, cur->children,
6329 (level >= 0?level+1:-1), format);
6330 if ((xmlIndentTreeOutput) && (format))
6331 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006332 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006333 }
6334 xmlBufferWriteChar(buf, "</");
6335 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6336 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6337 xmlBufferWriteChar(buf, ":");
6338 }
6339
6340 xmlBufferWriteCHAR(buf, cur->name);
6341 xmlBufferWriteChar(buf, ">");
6342}
6343
6344/**
6345 * xmlElemDump:
6346 * @f: the FILE * for the output
6347 * @doc: the document
6348 * @cur: the current node
6349 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006350 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006351 */
6352void
6353xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6354 xmlBufferPtr buf;
6355
6356 if (cur == NULL) {
6357#ifdef DEBUG_TREE
6358 xmlGenericError(xmlGenericErrorContext,
6359 "xmlElemDump : cur == NULL\n");
6360#endif
6361 return;
6362 }
Owen Taylor3473f882001-02-23 17:55:21 +00006363#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006364 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006365 xmlGenericError(xmlGenericErrorContext,
6366 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006367 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006368#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006369
Owen Taylor3473f882001-02-23 17:55:21 +00006370 buf = xmlBufferCreate();
6371 if (buf == NULL) return;
6372 if ((doc != NULL) &&
6373 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6374#ifdef LIBXML_HTML_ENABLED
6375 htmlNodeDump(buf, doc, cur);
6376#else
6377 xmlGenericError(xmlGenericErrorContext,
6378 "HTML support not compiled in\n");
6379#endif /* LIBXML_HTML_ENABLED */
6380 } else
6381 xmlNodeDump(buf, doc, cur, 0, 1);
6382 xmlBufferDump(f, buf);
6383 xmlBufferFree(buf);
6384}
6385
6386/************************************************************************
6387 * *
6388 * Dumping XML tree content to an I/O output buffer *
6389 * *
6390 ************************************************************************/
6391
Owen Taylor3473f882001-02-23 17:55:21 +00006392static void
6393xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6394 int level, int format, const char *encoding);
6395/**
6396 * xmlNsDumpOutput:
6397 * @buf: the XML buffer output
6398 * @cur: a namespace
6399 *
6400 * Dump a local Namespace definition.
6401 * Should be called in the context of attributes dumps.
6402 */
6403static void
6404xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6405 if (cur == NULL) {
6406#ifdef DEBUG_TREE
6407 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006408 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006409#endif
6410 return;
6411 }
6412 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006413 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6414 return;
6415
Owen Taylor3473f882001-02-23 17:55:21 +00006416 /* Within the context of an element attributes */
6417 if (cur->prefix != NULL) {
6418 xmlOutputBufferWriteString(buf, " xmlns:");
6419 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6420 } else
6421 xmlOutputBufferWriteString(buf, " xmlns");
6422 xmlOutputBufferWriteString(buf, "=");
6423 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6424 }
6425}
6426
6427/**
6428 * xmlNsListDumpOutput:
6429 * @buf: the XML buffer output
6430 * @cur: the first namespace
6431 *
6432 * Dump a list of local Namespace definitions.
6433 * Should be called in the context of attributes dumps.
6434 */
6435static void
6436xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6437 while (cur != NULL) {
6438 xmlNsDumpOutput(buf, cur);
6439 cur = cur->next;
6440 }
6441}
6442
6443/**
6444 * xmlDtdDumpOutput:
6445 * @buf: the XML buffer output
6446 * @doc: the document
6447 * @encoding: an optional encoding string
6448 *
6449 * Dump the XML document DTD, if any.
6450 */
6451static void
6452xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6453 if (dtd == NULL) {
6454#ifdef DEBUG_TREE
6455 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006456 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006457#endif
6458 return;
6459 }
6460 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6461 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6462 if (dtd->ExternalID != NULL) {
6463 xmlOutputBufferWriteString(buf, " PUBLIC ");
6464 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6465 xmlOutputBufferWriteString(buf, " ");
6466 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6467 } else if (dtd->SystemID != NULL) {
6468 xmlOutputBufferWriteString(buf, " SYSTEM ");
6469 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6470 }
6471 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6472 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6473 xmlOutputBufferWriteString(buf, ">");
6474 return;
6475 }
6476 xmlOutputBufferWriteString(buf, " [\n");
6477 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6478 xmlOutputBufferWriteString(buf, "]>");
6479}
6480
6481/**
6482 * xmlAttrDumpOutput:
6483 * @buf: the XML buffer output
6484 * @doc: the document
6485 * @cur: the attribute pointer
6486 * @encoding: an optional encoding string
6487 *
6488 * Dump an XML attribute
6489 */
6490static void
6491xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006492 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006493 if (cur == NULL) {
6494#ifdef DEBUG_TREE
6495 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006496 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006497#endif
6498 return;
6499 }
6500 xmlOutputBufferWriteString(buf, " ");
6501 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6502 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6503 xmlOutputBufferWriteString(buf, ":");
6504 }
6505 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006506 xmlOutputBufferWriteString(buf, "=\"");
6507 xmlAttrSerializeContent(buf->buffer, doc, cur);
6508 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006509}
6510
6511/**
6512 * xmlAttrListDumpOutput:
6513 * @buf: the XML buffer output
6514 * @doc: the document
6515 * @cur: the first attribute pointer
6516 * @encoding: an optional encoding string
6517 *
6518 * Dump a list of XML attributes
6519 */
6520static void
6521xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6522 xmlAttrPtr cur, const char *encoding) {
6523 if (cur == NULL) {
6524#ifdef DEBUG_TREE
6525 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006526 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006527#endif
6528 return;
6529 }
6530 while (cur != NULL) {
6531 xmlAttrDumpOutput(buf, doc, cur, encoding);
6532 cur = cur->next;
6533 }
6534}
6535
6536
6537
6538/**
6539 * xmlNodeListDumpOutput:
6540 * @buf: the XML buffer output
6541 * @doc: the document
6542 * @cur: the first node
6543 * @level: the imbrication level for indenting
6544 * @format: is formatting allowed
6545 * @encoding: an optional encoding string
6546 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006547 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006548 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6549 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006550 */
6551static void
6552xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6553 xmlNodePtr cur, int level, int format, const char *encoding) {
6554 int i;
6555
6556 if (cur == NULL) {
6557#ifdef DEBUG_TREE
6558 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006559 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006560#endif
6561 return;
6562 }
6563 while (cur != NULL) {
6564 if ((format) && (xmlIndentTreeOutput) &&
6565 (cur->type == XML_ELEMENT_NODE))
6566 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006567 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006568 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6569 if (format) {
6570 xmlOutputBufferWriteString(buf, "\n");
6571 }
6572 cur = cur->next;
6573 }
6574}
6575
6576/**
6577 * xmlNodeDumpOutput:
6578 * @buf: the XML buffer output
6579 * @doc: the document
6580 * @cur: the current node
6581 * @level: the imbrication level for indenting
6582 * @format: is formatting allowed
6583 * @encoding: an optional encoding string
6584 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006585 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006586 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6587 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006588 */
6589void
6590xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6591 int level, int format, const char *encoding) {
6592 int i;
6593 xmlNodePtr tmp;
6594
6595 if (cur == NULL) {
6596#ifdef DEBUG_TREE
6597 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006598 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006599#endif
6600 return;
6601 }
6602 if (cur->type == XML_XINCLUDE_START)
6603 return;
6604 if (cur->type == XML_XINCLUDE_END)
6605 return;
6606 if (cur->type == XML_DTD_NODE) {
6607 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6608 return;
6609 }
6610 if (cur->type == XML_ELEMENT_DECL) {
6611 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6612 return;
6613 }
6614 if (cur->type == XML_ATTRIBUTE_DECL) {
6615 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6616 return;
6617 }
6618 if (cur->type == XML_ENTITY_DECL) {
6619 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6620 return;
6621 }
6622 if (cur->type == XML_TEXT_NODE) {
6623 if (cur->content != NULL) {
6624 if ((cur->name == xmlStringText) ||
6625 (cur->name != xmlStringTextNoenc)) {
6626 xmlChar *buffer;
6627
Owen Taylor3473f882001-02-23 17:55:21 +00006628 if (encoding == NULL)
6629 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6630 else
6631 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006632 if (buffer != NULL) {
6633 xmlOutputBufferWriteString(buf, (const char *)buffer);
6634 xmlFree(buffer);
6635 }
6636 } else {
6637 /*
6638 * Disable escaping, needed for XSLT
6639 */
Owen Taylor3473f882001-02-23 17:55:21 +00006640 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006641 }
6642 }
6643
6644 return;
6645 }
6646 if (cur->type == XML_PI_NODE) {
6647 if (cur->content != NULL) {
6648 xmlOutputBufferWriteString(buf, "<?");
6649 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6650 if (cur->content != NULL) {
6651 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006652 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006653 }
6654 xmlOutputBufferWriteString(buf, "?>");
6655 } else {
6656 xmlOutputBufferWriteString(buf, "<?");
6657 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6658 xmlOutputBufferWriteString(buf, "?>");
6659 }
6660 return;
6661 }
6662 if (cur->type == XML_COMMENT_NODE) {
6663 if (cur->content != NULL) {
6664 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006665 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006666 xmlOutputBufferWriteString(buf, "-->");
6667 }
6668 return;
6669 }
6670 if (cur->type == XML_ENTITY_REF_NODE) {
6671 xmlOutputBufferWriteString(buf, "&");
6672 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6673 xmlOutputBufferWriteString(buf, ";");
6674 return;
6675 }
6676 if (cur->type == XML_CDATA_SECTION_NODE) {
6677 xmlOutputBufferWriteString(buf, "<![CDATA[");
6678 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006679 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006680 xmlOutputBufferWriteString(buf, "]]>");
6681 return;
6682 }
6683
6684 if (format == 1) {
6685 tmp = cur->children;
6686 while (tmp != NULL) {
6687 if ((tmp->type == XML_TEXT_NODE) ||
6688 (tmp->type == XML_ENTITY_REF_NODE)) {
6689 format = 0;
6690 break;
6691 }
6692 tmp = tmp->next;
6693 }
6694 }
6695 xmlOutputBufferWriteString(buf, "<");
6696 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6697 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6698 xmlOutputBufferWriteString(buf, ":");
6699 }
6700
6701 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6702 if (cur->nsDef)
6703 xmlNsListDumpOutput(buf, cur->nsDef);
6704 if (cur->properties != NULL)
6705 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6706
Daniel Veillard7db37732001-07-12 01:20:08 +00006707 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6708 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006709 xmlOutputBufferWriteString(buf, "/>");
6710 return;
6711 }
6712 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006713 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006714 xmlChar *buffer;
6715
Owen Taylor3473f882001-02-23 17:55:21 +00006716 if (encoding == NULL)
6717 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6718 else
6719 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006720 if (buffer != NULL) {
6721 xmlOutputBufferWriteString(buf, (const char *)buffer);
6722 xmlFree(buffer);
6723 }
6724 }
6725 if (cur->children != NULL) {
6726 if (format) xmlOutputBufferWriteString(buf, "\n");
6727 xmlNodeListDumpOutput(buf, doc, cur->children,
6728 (level >= 0?level+1:-1), format, encoding);
6729 if ((xmlIndentTreeOutput) && (format))
6730 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006731 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006732 }
6733 xmlOutputBufferWriteString(buf, "</");
6734 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6735 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6736 xmlOutputBufferWriteString(buf, ":");
6737 }
6738
6739 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6740 xmlOutputBufferWriteString(buf, ">");
6741}
6742
6743/**
6744 * xmlDocContentDumpOutput:
6745 * @buf: the XML buffer output
6746 * @cur: the document
6747 * @encoding: an optional encoding string
6748 * @format: should formatting spaces been added
6749 *
6750 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006751 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6752 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006753 */
6754static void
6755xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6756 const char *encoding, int format) {
6757 xmlOutputBufferWriteString(buf, "<?xml version=");
6758 if (cur->version != NULL)
6759 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6760 else
6761 xmlOutputBufferWriteString(buf, "\"1.0\"");
6762 if (encoding == NULL) {
6763 if (cur->encoding != NULL)
6764 encoding = (const char *) cur->encoding;
6765 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6766 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6767 }
6768 if (encoding != NULL) {
6769 xmlOutputBufferWriteString(buf, " encoding=");
6770 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6771 }
6772 switch (cur->standalone) {
6773 case 0:
6774 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6775 break;
6776 case 1:
6777 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6778 break;
6779 }
6780 xmlOutputBufferWriteString(buf, "?>\n");
6781 if (cur->children != NULL) {
6782 xmlNodePtr child = cur->children;
6783
6784 while (child != NULL) {
6785 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6786 xmlOutputBufferWriteString(buf, "\n");
6787 child = child->next;
6788 }
6789 }
6790}
6791
6792/************************************************************************
6793 * *
6794 * Saving functions front-ends *
6795 * *
6796 ************************************************************************/
6797
6798/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006799 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006800 * @out_doc: Document to generate XML text from
6801 * @doc_txt_ptr: Memory pointer for allocated XML text
6802 * @doc_txt_len: Length of the generated XML text
6803 * @txt_encoding: Character encoding to use when generating XML text
6804 * @format: should formatting spaces been added
6805 *
6806 * Dump the current DOM tree into memory using the character encoding specified
6807 * by the caller. Note it is up to the caller of this function to free the
6808 * allocated memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006809 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6810 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006811 */
6812
6813void
6814xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006815 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006816 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006817 int dummy = 0;
6818
6819 xmlCharEncoding doc_charset;
6820 xmlOutputBufferPtr out_buff = NULL;
6821 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6822
6823 if (doc_txt_len == NULL) {
6824 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6825 }
6826
6827 if (doc_txt_ptr == NULL) {
6828 *doc_txt_len = 0;
6829 xmlGenericError(xmlGenericErrorContext,
6830 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6831 return;
6832 }
6833
6834 *doc_txt_ptr = NULL;
6835 *doc_txt_len = 0;
6836
6837 if (out_doc == NULL) {
6838 /* No document, no output */
6839 xmlGenericError(xmlGenericErrorContext,
6840 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6841 return;
6842 }
6843
6844 /*
6845 * Validate the encoding value, if provided.
6846 * This logic is copied from xmlSaveFileEnc.
6847 */
6848
6849 if (txt_encoding == NULL)
6850 txt_encoding = (const char *) out_doc->encoding;
6851 if (txt_encoding != NULL) {
6852 doc_charset = xmlParseCharEncoding(txt_encoding);
6853
6854 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6855 xmlGenericError(xmlGenericErrorContext,
6856 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6857 return;
6858
6859 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6860 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6861 if ( conv_hdlr == NULL ) {
6862 xmlGenericError(xmlGenericErrorContext,
6863 "%s: %s %s '%s'\n",
6864 "xmlDocDumpFormatMemoryEnc",
6865 "Failed to identify encoding handler for",
6866 "character set",
6867 txt_encoding);
6868 return;
6869 }
6870 }
6871 }
6872
6873 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6874 xmlGenericError(xmlGenericErrorContext,
6875 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6876 return;
6877 }
6878
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006879 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006880 xmlOutputBufferFlush(out_buff);
6881 if (out_buff->conv != NULL) {
6882 *doc_txt_len = out_buff->conv->use;
6883 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6884 } else {
6885 *doc_txt_len = out_buff->buffer->use;
6886 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6887 }
6888 (void)xmlOutputBufferClose(out_buff);
6889
6890 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6891 *doc_txt_len = 0;
6892 xmlGenericError(xmlGenericErrorContext,
6893 "xmlDocDumpFormatMemoryEnc: %s\n",
6894 "Failed to allocate memory for document text representation.");
6895 }
6896
6897 return;
6898}
6899
6900/**
6901 * xmlDocDumpMemory:
6902 * @cur: the document
6903 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006904 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006905 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006906 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006907 * It's up to the caller to free the memory.
6908 */
6909void
6910xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6911 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6912}
6913
6914/**
6915 * xmlDocDumpFormatMemory:
6916 * @cur: the document
6917 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006918 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006919 * @format: should formatting spaces been added
6920 *
6921 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006922 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006923 * It's up to the caller to free the memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006924 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6925 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006926 */
6927void
6928xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6929 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6930}
6931
6932/**
6933 * xmlDocDumpMemoryEnc:
6934 * @out_doc: Document to generate XML text from
6935 * @doc_txt_ptr: Memory pointer for allocated XML text
6936 * @doc_txt_len: Length of the generated XML text
6937 * @txt_encoding: Character encoding to use when generating XML text
6938 *
6939 * Dump the current DOM tree into memory using the character encoding specified
6940 * by the caller. Note it is up to the caller of this function to free the
6941 * allocated memory.
6942 */
6943
6944void
6945xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6946 int * doc_txt_len, const char * txt_encoding) {
6947 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006948 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006949}
6950
6951/**
6952 * xmlGetDocCompressMode:
6953 * @doc: the document
6954 *
6955 * get the compression ratio for a document, ZLIB based
6956 * Returns 0 (uncompressed) to 9 (max compression)
6957 */
6958int
6959xmlGetDocCompressMode (xmlDocPtr doc) {
6960 if (doc == NULL) return(-1);
6961 return(doc->compression);
6962}
6963
6964/**
6965 * xmlSetDocCompressMode:
6966 * @doc: the document
6967 * @mode: the compression ratio
6968 *
6969 * set the compression ratio for a document, ZLIB based
6970 * Correct values: 0 (uncompressed) to 9 (max compression)
6971 */
6972void
6973xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6974 if (doc == NULL) return;
6975 if (mode < 0) doc->compression = 0;
6976 else if (mode > 9) doc->compression = 9;
6977 else doc->compression = mode;
6978}
6979
6980/**
6981 * xmlGetCompressMode:
6982 *
6983 * get the default compression mode used, ZLIB based.
6984 * Returns 0 (uncompressed) to 9 (max compression)
6985 */
6986int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006987xmlGetCompressMode(void)
6988{
6989 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006990}
6991
6992/**
6993 * xmlSetCompressMode:
6994 * @mode: the compression ratio
6995 *
6996 * set the default compression mode used, ZLIB based
6997 * Correct values: 0 (uncompressed) to 9 (max compression)
6998 */
6999void
7000xmlSetCompressMode(int mode) {
7001 if (mode < 0) xmlCompressMode = 0;
7002 else if (mode > 9) xmlCompressMode = 9;
7003 else xmlCompressMode = mode;
7004}
7005
7006/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007007 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007008 * @f: the FILE*
7009 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007010 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007011 *
7012 * Dump an XML document to an open FILE.
7013 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007014 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007015 */
7016int
Daniel Veillard9e412302002-06-10 15:59:44 +00007017xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007018 xmlOutputBufferPtr buf;
7019 const char * encoding;
7020 xmlCharEncodingHandlerPtr handler = NULL;
7021 int ret;
7022
7023 if (cur == NULL) {
7024#ifdef DEBUG_TREE
7025 xmlGenericError(xmlGenericErrorContext,
7026 "xmlDocDump : document == NULL\n");
7027#endif
7028 return(-1);
7029 }
7030 encoding = (const char *) cur->encoding;
7031
7032 if (encoding != NULL) {
7033 xmlCharEncoding enc;
7034
7035 enc = xmlParseCharEncoding(encoding);
7036
7037 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7038 xmlGenericError(xmlGenericErrorContext,
7039 "xmlDocDump: document not in UTF8\n");
7040 return(-1);
7041 }
7042 if (enc != XML_CHAR_ENCODING_UTF8) {
7043 handler = xmlFindCharEncodingHandler(encoding);
7044 if (handler == NULL) {
7045 xmlFree((char *) cur->encoding);
7046 cur->encoding = NULL;
7047 }
7048 }
7049 }
7050 buf = xmlOutputBufferCreateFile(f, handler);
7051 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007052 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007053
7054 ret = xmlOutputBufferClose(buf);
7055 return(ret);
7056}
7057
7058/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007059 * xmlDocDump:
7060 * @f: the FILE*
7061 * @cur: the document
7062 *
7063 * Dump an XML document to an open FILE.
7064 *
7065 * returns: the number of bytes written or -1 in case of failure.
7066 */
7067int
7068xmlDocDump(FILE *f, xmlDocPtr cur) {
7069 return(xmlDocFormatDump (f, cur, 0));
7070}
7071
7072/**
Owen Taylor3473f882001-02-23 17:55:21 +00007073 * xmlSaveFileTo:
7074 * @buf: an output I/O buffer
7075 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007076 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007077 *
7078 * Dump an XML document to an I/O buffer.
7079 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007080 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007081 */
7082int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007083xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007084 int ret;
7085
7086 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007087 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007088 ret = xmlOutputBufferClose(buf);
7089 return(ret);
7090}
7091
7092/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007093 * xmlSaveFormatFileTo:
7094 * @buf: an output I/O buffer
7095 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007096 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007097 * @format: should formatting spaces been added
7098 *
7099 * Dump an XML document to an I/O buffer.
7100 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007101 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007102 */
7103int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007104xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007105 int ret;
7106
7107 if (buf == NULL) return(0);
7108 xmlDocContentDumpOutput(buf, cur, encoding, format);
7109 ret = xmlOutputBufferClose(buf);
7110 return(ret);
7111}
7112
7113/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007114 * xmlSaveFormatFileEnc
7115 * @filename: the filename or URL to output
7116 * @cur: the document being saved
7117 * @encoding: the name of the encoding to use or NULL.
7118 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007119 *
7120 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007121 */
7122int
Daniel Veillardf012a642001-07-23 19:10:52 +00007123xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7124 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007125 xmlOutputBufferPtr buf;
7126 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007127 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007128 int ret;
7129
Daniel Veillardfb25a512002-01-13 20:32:08 +00007130 if (encoding == NULL)
7131 encoding = (const char *) cur->encoding;
7132
Owen Taylor3473f882001-02-23 17:55:21 +00007133 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007134
7135 enc = xmlParseCharEncoding(encoding);
7136 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7137 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007138 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007139 return(-1);
7140 }
7141 if (enc != XML_CHAR_ENCODING_UTF8) {
7142 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007143 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007144 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007145 }
7146 }
7147
Daniel Veillardf012a642001-07-23 19:10:52 +00007148#ifdef HAVE_ZLIB_H
7149 if (cur->compression < 0) cur->compression = xmlCompressMode;
7150#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007151 /*
7152 * save the content to a temp buffer.
7153 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007154 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007155 if (buf == NULL) return(-1);
7156
Daniel Veillardf012a642001-07-23 19:10:52 +00007157 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007158
7159 ret = xmlOutputBufferClose(buf);
7160 return(ret);
7161}
7162
Daniel Veillardf012a642001-07-23 19:10:52 +00007163
7164/**
7165 * xmlSaveFileEnc:
7166 * @filename: the filename (or URL)
7167 * @cur: the document
7168 * @encoding: the name of an encoding (or NULL)
7169 *
7170 * Dump an XML document, converting it to the given encoding
7171 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007172 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007173 */
7174int
7175xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7176 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7177}
7178
Owen Taylor3473f882001-02-23 17:55:21 +00007179/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007180 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007181 * @filename: the filename (or URL)
7182 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007183 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007184 *
7185 * Dump an XML document to a file. Will use compression if
7186 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007187 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007188 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007189 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007190 */
7191int
Daniel Veillard67fee942001-04-26 18:59:03 +00007192xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007193 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007194}
7195
Daniel Veillard67fee942001-04-26 18:59:03 +00007196/**
7197 * xmlSaveFile:
7198 * @filename: the filename (or URL)
7199 * @cur: the document
7200 *
7201 * Dump an XML document to a file. Will use compression if
7202 * compiled in and enabled. If @filename is "-" the stdout file is
7203 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007204 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007205 */
7206int
7207xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007208 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007209}
7210