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