blob: 086cb1623fef191d1d371a5b9fe0d2c3526cdd26 [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 *
905xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
906 xmlNodePtr node = list;
907 xmlChar *ret = NULL;
908 xmlEntityPtr ent;
909
910 if (list == NULL) return(NULL);
911
912 while (node != NULL) {
913 if ((node->type == XML_TEXT_NODE) ||
914 (node->type == XML_CDATA_SECTION_NODE)) {
915 if (inLine) {
Owen Taylor3473f882001-02-23 17:55:21 +0000916 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000917 } else {
918 xmlChar *buffer;
919
Owen Taylor3473f882001-02-23 17:55:21 +0000920 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000921 if (buffer != NULL) {
922 ret = xmlStrcat(ret, buffer);
923 xmlFree(buffer);
924 }
925 }
926 } else if (node->type == XML_ENTITY_REF_NODE) {
927 if (inLine) {
928 ent = xmlGetDocEntity(doc, node->name);
929 if (ent != NULL)
930 ret = xmlStrcat(ret, ent->content);
931 else {
Owen Taylor3473f882001-02-23 17:55:21 +0000932 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000933 }
934 } else {
935 xmlChar buf[2];
936 buf[0] = '&'; buf[1] = 0;
937 ret = xmlStrncat(ret, buf, 1);
938 ret = xmlStrcat(ret, node->name);
939 buf[0] = ';'; buf[1] = 0;
940 ret = xmlStrncat(ret, buf, 1);
941 }
942 }
943#if 0
944 else {
945 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000946 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +0000947 node->type);
948 }
949#endif
950 node = node->next;
951 }
952 return(ret);
953}
954
955/**
956 * xmlNodeListGetRawString:
957 * @doc: the document
958 * @list: a Node list
959 * @inLine: should we replace entity contents or show their external form
960 *
961 * Returns the string equivalent to the text contained in the Node list
962 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
963 * this function doesn't do any character encoding handling.
964 *
Daniel Veillardd1640922001-12-17 15:30:10 +0000965 * Returns a pointer to the string copy, the caller must free it.
Owen Taylor3473f882001-02-23 17:55:21 +0000966 */
967xmlChar *
968xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
969 xmlNodePtr node = list;
970 xmlChar *ret = NULL;
971 xmlEntityPtr ent;
972
973 if (list == NULL) return(NULL);
974
975 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000976 if ((node->type == XML_TEXT_NODE) ||
977 (node->type == XML_CDATA_SECTION_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000978 if (inLine) {
Owen Taylor3473f882001-02-23 17:55:21 +0000979 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000980 } else {
981 xmlChar *buffer;
982
Owen Taylor3473f882001-02-23 17:55:21 +0000983 buffer = xmlEncodeSpecialChars(doc, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000984 if (buffer != NULL) {
985 ret = xmlStrcat(ret, buffer);
986 xmlFree(buffer);
987 }
988 }
989 } else if (node->type == XML_ENTITY_REF_NODE) {
990 if (inLine) {
991 ent = xmlGetDocEntity(doc, node->name);
992 if (ent != NULL)
993 ret = xmlStrcat(ret, ent->content);
994 else {
Owen Taylor3473f882001-02-23 17:55:21 +0000995 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000996 }
997 } else {
998 xmlChar buf[2];
999 buf[0] = '&'; buf[1] = 0;
1000 ret = xmlStrncat(ret, buf, 1);
1001 ret = xmlStrcat(ret, node->name);
1002 buf[0] = ';'; buf[1] = 0;
1003 ret = xmlStrncat(ret, buf, 1);
1004 }
1005 }
1006#if 0
1007 else {
1008 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001009 "xmlGetNodeListString : invalid node type %d\n",
Owen Taylor3473f882001-02-23 17:55:21 +00001010 node->type);
1011 }
1012#endif
1013 node = node->next;
1014 }
1015 return(ret);
1016}
1017
1018/**
1019 * xmlNewProp:
1020 * @node: the holding node
1021 * @name: the name of the attribute
1022 * @value: the value of the attribute
1023 *
1024 * Create a new property carried by a node.
1025 * Returns a pointer to the attribute
1026 */
1027xmlAttrPtr
1028xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1029 xmlAttrPtr cur;
1030 xmlDocPtr doc = NULL;
1031
1032 if (name == NULL) {
1033#ifdef DEBUG_TREE
1034 xmlGenericError(xmlGenericErrorContext,
1035 "xmlNewProp : name == NULL\n");
1036#endif
1037 return(NULL);
1038 }
1039
1040 /*
1041 * Allocate a new property and fill the fields.
1042 */
1043 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1044 if (cur == NULL) {
1045 xmlGenericError(xmlGenericErrorContext,
1046 "xmlNewProp : malloc failed\n");
1047 return(NULL);
1048 }
1049 memset(cur, 0, sizeof(xmlAttr));
1050 cur->type = XML_ATTRIBUTE_NODE;
1051
1052 cur->parent = node;
1053 if (node != NULL) {
1054 doc = node->doc;
1055 cur->doc = doc;
1056 }
1057 cur->name = xmlStrdup(name);
1058 if (value != NULL) {
1059 xmlChar *buffer;
1060 xmlNodePtr tmp;
1061
1062 buffer = xmlEncodeEntitiesReentrant(doc, value);
1063 cur->children = xmlStringGetNodeList(doc, buffer);
1064 cur->last = NULL;
1065 tmp = cur->children;
1066 while (tmp != NULL) {
1067 tmp->parent = (xmlNodePtr) cur;
1068 tmp->doc = doc;
1069 if (tmp->next == NULL)
1070 cur->last = tmp;
1071 tmp = tmp->next;
1072 }
1073 xmlFree(buffer);
1074 }
1075
1076 /*
1077 * Add it at the end to preserve parsing order ...
1078 */
1079 if (node != NULL) {
1080 if (node->properties == NULL) {
1081 node->properties = cur;
1082 } else {
1083 xmlAttrPtr prev = node->properties;
1084
1085 while (prev->next != NULL) prev = prev->next;
1086 prev->next = cur;
1087 cur->prev = prev;
1088 }
1089 }
1090 return(cur);
1091}
1092
1093/**
1094 * xmlNewNsProp:
1095 * @node: the holding node
1096 * @ns: the namespace
1097 * @name: the name of the attribute
1098 * @value: the value of the attribute
1099 *
1100 * Create a new property tagged with a namespace and carried by a node.
1101 * Returns a pointer to the attribute
1102 */
1103xmlAttrPtr
1104xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1105 const xmlChar *value) {
1106 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001107 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001108
1109 if (name == NULL) {
1110#ifdef DEBUG_TREE
1111 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001112 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001113#endif
1114 return(NULL);
1115 }
1116
1117 /*
1118 * Allocate a new property and fill the fields.
1119 */
1120 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1121 if (cur == NULL) {
1122 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001123 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001124 return(NULL);
1125 }
1126 memset(cur, 0, sizeof(xmlAttr));
1127 cur->type = XML_ATTRIBUTE_NODE;
1128
1129 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001130 if (node != NULL) {
1131 doc = node->doc;
1132 cur->doc = doc;
1133 }
Owen Taylor3473f882001-02-23 17:55:21 +00001134 cur->ns = ns;
1135 cur->name = xmlStrdup(name);
1136 if (value != NULL) {
1137 xmlChar *buffer;
1138 xmlNodePtr tmp;
1139
Daniel Veillarda682b212001-06-07 19:59:42 +00001140 buffer = xmlEncodeEntitiesReentrant(doc, value);
1141 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001142 cur->last = NULL;
1143 tmp = cur->children;
1144 while (tmp != NULL) {
1145 tmp->parent = (xmlNodePtr) cur;
1146 if (tmp->next == NULL)
1147 cur->last = tmp;
1148 tmp = tmp->next;
1149 }
1150 xmlFree(buffer);
1151 }
1152
1153 /*
1154 * Add it at the end to preserve parsing order ...
1155 */
1156 if (node != NULL) {
1157 if (node->properties == NULL) {
1158 node->properties = cur;
1159 } else {
1160 xmlAttrPtr prev = node->properties;
1161
1162 while (prev->next != NULL) prev = prev->next;
1163 prev->next = cur;
1164 cur->prev = prev;
1165 }
1166 }
1167 return(cur);
1168}
1169
1170/**
1171 * xmlNewDocProp:
1172 * @doc: the document
1173 * @name: the name of the attribute
1174 * @value: the value of the attribute
1175 *
1176 * Create a new property carried by a document.
1177 * Returns a pointer to the attribute
1178 */
1179xmlAttrPtr
1180xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1181 xmlAttrPtr cur;
1182
1183 if (name == NULL) {
1184#ifdef DEBUG_TREE
1185 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001186 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001187#endif
1188 return(NULL);
1189 }
1190
1191 /*
1192 * Allocate a new property and fill the fields.
1193 */
1194 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1195 if (cur == NULL) {
1196 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001197 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001198 return(NULL);
1199 }
1200 memset(cur, 0, sizeof(xmlAttr));
1201 cur->type = XML_ATTRIBUTE_NODE;
1202
1203 cur->name = xmlStrdup(name);
1204 cur->doc = doc;
1205 if (value != NULL) {
1206 xmlNodePtr tmp;
1207
1208 cur->children = xmlStringGetNodeList(doc, value);
1209 cur->last = NULL;
1210
1211 tmp = cur->children;
1212 while (tmp != NULL) {
1213 tmp->parent = (xmlNodePtr) cur;
1214 if (tmp->next == NULL)
1215 cur->last = tmp;
1216 tmp = tmp->next;
1217 }
1218 }
1219 return(cur);
1220}
1221
1222/**
1223 * xmlFreePropList:
1224 * @cur: the first property in the list
1225 *
1226 * Free a property and all its siblings, all the children are freed too.
1227 */
1228void
1229xmlFreePropList(xmlAttrPtr cur) {
1230 xmlAttrPtr next;
1231 if (cur == NULL) {
1232#ifdef DEBUG_TREE
1233 xmlGenericError(xmlGenericErrorContext,
1234 "xmlFreePropList : property == NULL\n");
1235#endif
1236 return;
1237 }
1238 while (cur != NULL) {
1239 next = cur->next;
1240 xmlFreeProp(cur);
1241 cur = next;
1242 }
1243}
1244
1245/**
1246 * xmlFreeProp:
1247 * @cur: an attribute
1248 *
1249 * Free one attribute, all the content is freed too
1250 */
1251void
1252xmlFreeProp(xmlAttrPtr cur) {
1253 if (cur == NULL) {
1254#ifdef DEBUG_TREE
1255 xmlGenericError(xmlGenericErrorContext,
1256 "xmlFreeProp : property == NULL\n");
1257#endif
1258 return;
1259 }
1260 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001261 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1262 ((cur->parent->doc->intSubset != NULL) ||
1263 (cur->parent->doc->extSubset != NULL))) {
1264 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1265 xmlRemoveID(cur->parent->doc, cur);
1266 }
Owen Taylor3473f882001-02-23 17:55:21 +00001267 if (cur->name != NULL) xmlFree((char *) cur->name);
1268 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001269 xmlFree(cur);
1270}
1271
1272/**
1273 * xmlRemoveProp:
1274 * @cur: an attribute
1275 *
1276 * Unlink and free one attribute, all the content is freed too
1277 * Note this doesn't work for namespace definition attributes
1278 *
1279 * Returns 0 if success and -1 in case of error.
1280 */
1281int
1282xmlRemoveProp(xmlAttrPtr cur) {
1283 xmlAttrPtr tmp;
1284 if (cur == NULL) {
1285#ifdef DEBUG_TREE
1286 xmlGenericError(xmlGenericErrorContext,
1287 "xmlRemoveProp : cur == NULL\n");
1288#endif
1289 return(-1);
1290 }
1291 if (cur->parent == NULL) {
1292#ifdef DEBUG_TREE
1293 xmlGenericError(xmlGenericErrorContext,
1294 "xmlRemoveProp : cur->parent == NULL\n");
1295#endif
1296 return(-1);
1297 }
1298 tmp = cur->parent->properties;
1299 if (tmp == cur) {
1300 cur->parent->properties = cur->next;
1301 xmlFreeProp(cur);
1302 return(0);
1303 }
1304 while (tmp != NULL) {
1305 if (tmp->next == cur) {
1306 tmp->next = cur->next;
1307 if (tmp->next != NULL)
1308 tmp->next->prev = tmp;
1309 xmlFreeProp(cur);
1310 return(0);
1311 }
1312 tmp = tmp->next;
1313 }
1314#ifdef DEBUG_TREE
1315 xmlGenericError(xmlGenericErrorContext,
1316 "xmlRemoveProp : attribute not owned by its node\n");
1317#endif
1318 return(-1);
1319}
1320
1321/**
1322 * xmlNewPI:
1323 * @name: the processing instruction name
1324 * @content: the PI content
1325 *
1326 * Creation of a processing instruction element.
1327 * Returns a pointer to the new node object.
1328 */
1329xmlNodePtr
1330xmlNewPI(const xmlChar *name, const xmlChar *content) {
1331 xmlNodePtr cur;
1332
1333 if (name == NULL) {
1334#ifdef DEBUG_TREE
1335 xmlGenericError(xmlGenericErrorContext,
1336 "xmlNewPI : name == NULL\n");
1337#endif
1338 return(NULL);
1339 }
1340
1341 /*
1342 * Allocate a new node and fill the fields.
1343 */
1344 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1345 if (cur == NULL) {
1346 xmlGenericError(xmlGenericErrorContext,
1347 "xmlNewPI : malloc failed\n");
1348 return(NULL);
1349 }
1350 memset(cur, 0, sizeof(xmlNode));
1351 cur->type = XML_PI_NODE;
1352
1353 cur->name = xmlStrdup(name);
1354 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001355 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001356 }
1357 return(cur);
1358}
1359
1360/**
1361 * xmlNewNode:
1362 * @ns: namespace if any
1363 * @name: the node name
1364 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001365 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001366 *
1367 * Returns a pointer to the new node object.
1368 */
1369xmlNodePtr
1370xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1371 xmlNodePtr cur;
1372
1373 if (name == NULL) {
1374#ifdef DEBUG_TREE
1375 xmlGenericError(xmlGenericErrorContext,
1376 "xmlNewNode : name == NULL\n");
1377#endif
1378 return(NULL);
1379 }
1380
1381 /*
1382 * Allocate a new node and fill the fields.
1383 */
1384 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1385 if (cur == NULL) {
1386 xmlGenericError(xmlGenericErrorContext,
1387 "xmlNewNode : malloc failed\n");
1388 return(NULL);
1389 }
1390 memset(cur, 0, sizeof(xmlNode));
1391 cur->type = XML_ELEMENT_NODE;
1392
1393 cur->name = xmlStrdup(name);
1394 cur->ns = ns;
1395 return(cur);
1396}
1397
1398/**
1399 * xmlNewDocNode:
1400 * @doc: the document
1401 * @ns: namespace if any
1402 * @name: the node name
1403 * @content: the XML text content if any
1404 *
1405 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001406 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001407 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1408 * references, but XML special chars need to be escaped first by using
1409 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1410 * need entities support.
1411 *
1412 * Returns a pointer to the new node object.
1413 */
1414xmlNodePtr
1415xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1416 const xmlChar *name, const xmlChar *content) {
1417 xmlNodePtr cur;
1418
1419 cur = xmlNewNode(ns, name);
1420 if (cur != NULL) {
1421 cur->doc = doc;
1422 if (content != NULL) {
1423 cur->children = xmlStringGetNodeList(doc, content);
1424 UPDATE_LAST_CHILD_AND_PARENT(cur)
1425 }
1426 }
1427 return(cur);
1428}
1429
1430
1431/**
1432 * xmlNewDocRawNode:
1433 * @doc: the document
1434 * @ns: namespace if any
1435 * @name: the node name
1436 * @content: the text content if any
1437 *
1438 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001439 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001440 *
1441 * Returns a pointer to the new node object.
1442 */
1443xmlNodePtr
1444xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1445 const xmlChar *name, const xmlChar *content) {
1446 xmlNodePtr cur;
1447
1448 cur = xmlNewNode(ns, name);
1449 if (cur != NULL) {
1450 cur->doc = doc;
1451 if (content != NULL) {
1452 cur->children = xmlNewDocText(doc, content);
1453 UPDATE_LAST_CHILD_AND_PARENT(cur)
1454 }
1455 }
1456 return(cur);
1457}
1458
1459/**
1460 * xmlNewDocFragment:
1461 * @doc: the document owning the fragment
1462 *
1463 * Creation of a new Fragment node.
1464 * Returns a pointer to the new node object.
1465 */
1466xmlNodePtr
1467xmlNewDocFragment(xmlDocPtr doc) {
1468 xmlNodePtr cur;
1469
1470 /*
1471 * Allocate a new DocumentFragment node and fill the fields.
1472 */
1473 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1474 if (cur == NULL) {
1475 xmlGenericError(xmlGenericErrorContext,
1476 "xmlNewDocFragment : malloc failed\n");
1477 return(NULL);
1478 }
1479 memset(cur, 0, sizeof(xmlNode));
1480 cur->type = XML_DOCUMENT_FRAG_NODE;
1481
1482 cur->doc = doc;
1483 return(cur);
1484}
1485
1486/**
1487 * xmlNewText:
1488 * @content: the text content
1489 *
1490 * Creation of a new text node.
1491 * Returns a pointer to the new node object.
1492 */
1493xmlNodePtr
1494xmlNewText(const xmlChar *content) {
1495 xmlNodePtr cur;
1496
1497 /*
1498 * Allocate a new node and fill the fields.
1499 */
1500 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1501 if (cur == NULL) {
1502 xmlGenericError(xmlGenericErrorContext,
1503 "xmlNewText : malloc failed\n");
1504 return(NULL);
1505 }
1506 memset(cur, 0, sizeof(xmlNode));
1507 cur->type = XML_TEXT_NODE;
1508
1509 cur->name = xmlStringText;
1510 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001511 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001512 }
1513 return(cur);
1514}
1515
1516/**
1517 * xmlNewTextChild:
1518 * @parent: the parent node
1519 * @ns: a namespace if any
1520 * @name: the name of the child
1521 * @content: the text content of the child if any.
1522 *
1523 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001524 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001525 * a child TEXT node will be created containing the string content.
1526 *
1527 * Returns a pointer to the new node object.
1528 */
1529xmlNodePtr
1530xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1531 const xmlChar *name, const xmlChar *content) {
1532 xmlNodePtr cur, prev;
1533
1534 if (parent == NULL) {
1535#ifdef DEBUG_TREE
1536 xmlGenericError(xmlGenericErrorContext,
1537 "xmlNewTextChild : parent == NULL\n");
1538#endif
1539 return(NULL);
1540 }
1541
1542 if (name == NULL) {
1543#ifdef DEBUG_TREE
1544 xmlGenericError(xmlGenericErrorContext,
1545 "xmlNewTextChild : name == NULL\n");
1546#endif
1547 return(NULL);
1548 }
1549
1550 /*
1551 * Allocate a new node
1552 */
1553 if (ns == NULL)
1554 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1555 else
1556 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1557 if (cur == NULL) return(NULL);
1558
1559 /*
1560 * add the new element at the end of the children list.
1561 */
1562 cur->type = XML_ELEMENT_NODE;
1563 cur->parent = parent;
1564 cur->doc = parent->doc;
1565 if (parent->children == NULL) {
1566 parent->children = cur;
1567 parent->last = cur;
1568 } else {
1569 prev = parent->last;
1570 prev->next = cur;
1571 cur->prev = prev;
1572 parent->last = cur;
1573 }
1574
1575 return(cur);
1576}
1577
1578/**
1579 * xmlNewCharRef:
1580 * @doc: the document
1581 * @name: the char ref string, starting with # or "&# ... ;"
1582 *
1583 * Creation of a new character reference node.
1584 * Returns a pointer to the new node object.
1585 */
1586xmlNodePtr
1587xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1588 xmlNodePtr cur;
1589
1590 /*
1591 * Allocate a new node and fill the fields.
1592 */
1593 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1594 if (cur == NULL) {
1595 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001596 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001597 return(NULL);
1598 }
1599 memset(cur, 0, sizeof(xmlNode));
1600 cur->type = XML_ENTITY_REF_NODE;
1601
1602 cur->doc = doc;
1603 if (name[0] == '&') {
1604 int len;
1605 name++;
1606 len = xmlStrlen(name);
1607 if (name[len - 1] == ';')
1608 cur->name = xmlStrndup(name, len - 1);
1609 else
1610 cur->name = xmlStrndup(name, len);
1611 } else
1612 cur->name = xmlStrdup(name);
1613 return(cur);
1614}
1615
1616/**
1617 * xmlNewReference:
1618 * @doc: the document
1619 * @name: the reference name, or the reference string with & and ;
1620 *
1621 * Creation of a new reference node.
1622 * Returns a pointer to the new node object.
1623 */
1624xmlNodePtr
1625xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1626 xmlNodePtr cur;
1627 xmlEntityPtr ent;
1628
1629 /*
1630 * Allocate a new node and fill the fields.
1631 */
1632 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1633 if (cur == NULL) {
1634 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001635 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001636 return(NULL);
1637 }
1638 memset(cur, 0, sizeof(xmlNode));
1639 cur->type = XML_ENTITY_REF_NODE;
1640
1641 cur->doc = doc;
1642 if (name[0] == '&') {
1643 int len;
1644 name++;
1645 len = xmlStrlen(name);
1646 if (name[len - 1] == ';')
1647 cur->name = xmlStrndup(name, len - 1);
1648 else
1649 cur->name = xmlStrndup(name, len);
1650 } else
1651 cur->name = xmlStrdup(name);
1652
1653 ent = xmlGetDocEntity(doc, cur->name);
1654 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001655 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001656 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001657 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001658 * updated. Not sure if this is 100% correct.
1659 * -George
1660 */
1661 cur->children = (xmlNodePtr) ent;
1662 cur->last = (xmlNodePtr) ent;
1663 }
1664 return(cur);
1665}
1666
1667/**
1668 * xmlNewDocText:
1669 * @doc: the document
1670 * @content: the text content
1671 *
1672 * Creation of a new text node within a document.
1673 * Returns a pointer to the new node object.
1674 */
1675xmlNodePtr
1676xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1677 xmlNodePtr cur;
1678
1679 cur = xmlNewText(content);
1680 if (cur != NULL) cur->doc = doc;
1681 return(cur);
1682}
1683
1684/**
1685 * xmlNewTextLen:
1686 * @content: the text content
1687 * @len: the text len.
1688 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001689 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001690 * Returns a pointer to the new node object.
1691 */
1692xmlNodePtr
1693xmlNewTextLen(const xmlChar *content, int len) {
1694 xmlNodePtr cur;
1695
1696 /*
1697 * Allocate a new node and fill the fields.
1698 */
1699 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1700 if (cur == NULL) {
1701 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001702 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001703 return(NULL);
1704 }
1705 memset(cur, 0, sizeof(xmlNode));
1706 cur->type = XML_TEXT_NODE;
1707
1708 cur->name = xmlStringText;
1709 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001710 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001711 }
1712 return(cur);
1713}
1714
1715/**
1716 * xmlNewDocTextLen:
1717 * @doc: the document
1718 * @content: the text content
1719 * @len: the text len.
1720 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001721 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001722 * text node pertain to a given document.
1723 * Returns a pointer to the new node object.
1724 */
1725xmlNodePtr
1726xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1727 xmlNodePtr cur;
1728
1729 cur = xmlNewTextLen(content, len);
1730 if (cur != NULL) cur->doc = doc;
1731 return(cur);
1732}
1733
1734/**
1735 * xmlNewComment:
1736 * @content: the comment content
1737 *
1738 * Creation of a new node containing a comment.
1739 * Returns a pointer to the new node object.
1740 */
1741xmlNodePtr
1742xmlNewComment(const xmlChar *content) {
1743 xmlNodePtr cur;
1744
1745 /*
1746 * Allocate a new node and fill the fields.
1747 */
1748 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1749 if (cur == NULL) {
1750 xmlGenericError(xmlGenericErrorContext,
1751 "xmlNewComment : malloc failed\n");
1752 return(NULL);
1753 }
1754 memset(cur, 0, sizeof(xmlNode));
1755 cur->type = XML_COMMENT_NODE;
1756
1757 cur->name = xmlStringComment;
1758 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001759 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001760 }
1761 return(cur);
1762}
1763
1764/**
1765 * xmlNewCDataBlock:
1766 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001767 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001768 * @len: the length of the block
1769 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001770 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001771 * Returns a pointer to the new node object.
1772 */
1773xmlNodePtr
1774xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1775 xmlNodePtr cur;
1776
1777 /*
1778 * Allocate a new node and fill the fields.
1779 */
1780 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1781 if (cur == NULL) {
1782 xmlGenericError(xmlGenericErrorContext,
1783 "xmlNewCDataBlock : malloc failed\n");
1784 return(NULL);
1785 }
1786 memset(cur, 0, sizeof(xmlNode));
1787 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001788 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001789
1790 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001791 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001792 }
1793 return(cur);
1794}
1795
1796/**
1797 * xmlNewDocComment:
1798 * @doc: the document
1799 * @content: the comment content
1800 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001801 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001802 * Returns a pointer to the new node object.
1803 */
1804xmlNodePtr
1805xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1806 xmlNodePtr cur;
1807
1808 cur = xmlNewComment(content);
1809 if (cur != NULL) cur->doc = doc;
1810 return(cur);
1811}
1812
1813/**
1814 * xmlSetTreeDoc:
1815 * @tree: the top element
1816 * @doc: the document
1817 *
1818 * update all nodes under the tree to point to the right document
1819 */
1820void
1821xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00001822 xmlAttrPtr prop;
1823
Owen Taylor3473f882001-02-23 17:55:21 +00001824 if (tree == NULL)
1825 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001826 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00001827 if(tree->type == XML_ELEMENT_NODE) {
1828 prop = tree->properties;
1829 while (prop != NULL) {
1830 prop->doc = doc;
1831 xmlSetListDoc(prop->children, doc);
1832 prop = prop->next;
1833 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00001834 }
Owen Taylor3473f882001-02-23 17:55:21 +00001835 if (tree->children != NULL)
1836 xmlSetListDoc(tree->children, doc);
1837 tree->doc = doc;
1838 }
1839}
1840
1841/**
1842 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00001843 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00001844 * @doc: the document
1845 *
1846 * update all nodes in the list to point to the right document
1847 */
1848void
1849xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1850 xmlNodePtr cur;
1851
1852 if (list == NULL)
1853 return;
1854 cur = list;
1855 while (cur != NULL) {
1856 if (cur->doc != doc)
1857 xmlSetTreeDoc(cur, doc);
1858 cur = cur->next;
1859 }
1860}
1861
1862
1863/**
1864 * xmlNewChild:
1865 * @parent: the parent node
1866 * @ns: a namespace if any
1867 * @name: the name of the child
1868 * @content: the XML content of the child if any.
1869 *
1870 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001871 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001872 * a child list containing the TEXTs and ENTITY_REFs node will be created.
1873 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1874 * references, but XML special chars need to be escaped first by using
1875 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1876 * support is not needed.
1877 *
1878 * Returns a pointer to the new node object.
1879 */
1880xmlNodePtr
1881xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
1882 const xmlChar *name, const xmlChar *content) {
1883 xmlNodePtr cur, prev;
1884
1885 if (parent == NULL) {
1886#ifdef DEBUG_TREE
1887 xmlGenericError(xmlGenericErrorContext,
1888 "xmlNewChild : parent == NULL\n");
1889#endif
1890 return(NULL);
1891 }
1892
1893 if (name == NULL) {
1894#ifdef DEBUG_TREE
1895 xmlGenericError(xmlGenericErrorContext,
1896 "xmlNewChild : name == NULL\n");
1897#endif
1898 return(NULL);
1899 }
1900
1901 /*
1902 * Allocate a new node
1903 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00001904 if (parent->type == XML_ELEMENT_NODE) {
1905 if (ns == NULL)
1906 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
1907 else
1908 cur = xmlNewDocNode(parent->doc, ns, name, content);
1909 } else if ((parent->type == XML_DOCUMENT_NODE) ||
1910 (parent->type == XML_HTML_DOCUMENT_NODE)) {
1911 if (ns == NULL)
1912 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
1913 else
1914 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
1915 } else {
1916 return(NULL);
1917 }
Owen Taylor3473f882001-02-23 17:55:21 +00001918 if (cur == NULL) return(NULL);
1919
1920 /*
1921 * add the new element at the end of the children list.
1922 */
1923 cur->type = XML_ELEMENT_NODE;
1924 cur->parent = parent;
1925 cur->doc = parent->doc;
1926 if (parent->children == NULL) {
1927 parent->children = cur;
1928 parent->last = cur;
1929 } else {
1930 prev = parent->last;
1931 prev->next = cur;
1932 cur->prev = prev;
1933 parent->last = cur;
1934 }
1935
1936 return(cur);
1937}
1938
1939/**
1940 * xmlAddNextSibling:
1941 * @cur: the child node
1942 * @elem: the new node
1943 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001944 * Add a new node @elem as the next sibling of @cur
1945 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00001946 * first unlinked from its existing context.
1947 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001948 * If the new node is ATTRIBUTE, it is added into properties instead of children.
1949 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00001950 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001951 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001952 */
1953xmlNodePtr
1954xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1955 if (cur == NULL) {
1956#ifdef DEBUG_TREE
1957 xmlGenericError(xmlGenericErrorContext,
1958 "xmlAddNextSibling : cur == NULL\n");
1959#endif
1960 return(NULL);
1961 }
1962 if (elem == NULL) {
1963#ifdef DEBUG_TREE
1964 xmlGenericError(xmlGenericErrorContext,
1965 "xmlAddNextSibling : elem == NULL\n");
1966#endif
1967 return(NULL);
1968 }
1969
1970 xmlUnlinkNode(elem);
1971
1972 if (elem->type == XML_TEXT_NODE) {
1973 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00001974 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001975 xmlFreeNode(elem);
1976 return(cur);
1977 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00001978 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
1979 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001980 xmlChar *tmp;
1981
1982 tmp = xmlStrdup(elem->content);
1983 tmp = xmlStrcat(tmp, cur->next->content);
1984 xmlNodeSetContent(cur->next, tmp);
1985 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00001986 xmlFreeNode(elem);
1987 return(cur->next);
1988 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00001989 } else if (elem->type == XML_ATTRIBUTE_NODE) {
1990 /* check if an attribute with the same name exists */
1991 xmlAttrPtr attr;
1992
1993 if (elem->ns == NULL)
1994 attr = xmlHasProp(cur->parent, elem->name);
1995 else
1996 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
1997 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
1998 /* different instance, destroy it (attributes must be unique) */
1999 xmlFreeProp(attr);
2000 }
Owen Taylor3473f882001-02-23 17:55:21 +00002001 }
2002
2003 if (elem->doc != cur->doc) {
2004 xmlSetTreeDoc(elem, cur->doc);
2005 }
2006 elem->parent = cur->parent;
2007 elem->prev = cur;
2008 elem->next = cur->next;
2009 cur->next = elem;
2010 if (elem->next != NULL)
2011 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002012 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002013 elem->parent->last = elem;
2014 return(elem);
2015}
2016
2017/**
2018 * xmlAddPrevSibling:
2019 * @cur: the child node
2020 * @elem: the new node
2021 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002022 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002023 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002024 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002025 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002026 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2027 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002028 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002029 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002030 */
2031xmlNodePtr
2032xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2033 if (cur == NULL) {
2034#ifdef DEBUG_TREE
2035 xmlGenericError(xmlGenericErrorContext,
2036 "xmlAddPrevSibling : cur == NULL\n");
2037#endif
2038 return(NULL);
2039 }
2040 if (elem == NULL) {
2041#ifdef DEBUG_TREE
2042 xmlGenericError(xmlGenericErrorContext,
2043 "xmlAddPrevSibling : elem == NULL\n");
2044#endif
2045 return(NULL);
2046 }
2047
2048 xmlUnlinkNode(elem);
2049
2050 if (elem->type == XML_TEXT_NODE) {
2051 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002052 xmlChar *tmp;
2053
2054 tmp = xmlStrdup(elem->content);
2055 tmp = xmlStrcat(tmp, cur->content);
2056 xmlNodeSetContent(cur, tmp);
2057 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002058 xmlFreeNode(elem);
2059 return(cur);
2060 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002061 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2062 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002063 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002064 xmlFreeNode(elem);
2065 return(cur->prev);
2066 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002067 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2068 /* check if an attribute with the same name exists */
2069 xmlAttrPtr attr;
2070
2071 if (elem->ns == NULL)
2072 attr = xmlHasProp(cur->parent, elem->name);
2073 else
2074 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2075 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2076 /* different instance, destroy it (attributes must be unique) */
2077 xmlFreeProp(attr);
2078 }
Owen Taylor3473f882001-02-23 17:55:21 +00002079 }
2080
2081 if (elem->doc != cur->doc) {
2082 xmlSetTreeDoc(elem, cur->doc);
2083 }
2084 elem->parent = cur->parent;
2085 elem->next = cur;
2086 elem->prev = cur->prev;
2087 cur->prev = elem;
2088 if (elem->prev != NULL)
2089 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002090 if (elem->parent != NULL) {
2091 if (elem->type == XML_ATTRIBUTE_NODE) {
2092 if (elem->parent->properties == (xmlAttrPtr) cur) {
2093 elem->parent->properties = (xmlAttrPtr) elem;
2094 }
2095 } else {
2096 if (elem->parent->children == cur) {
2097 elem->parent->children = elem;
2098 }
2099 }
2100 }
Owen Taylor3473f882001-02-23 17:55:21 +00002101 return(elem);
2102}
2103
2104/**
2105 * xmlAddSibling:
2106 * @cur: the child node
2107 * @elem: the new node
2108 *
2109 * Add a new element @elem to the list of siblings of @cur
2110 * merging adjacent TEXT nodes (@elem may be freed)
2111 * If the new element was already inserted in a document it is
2112 * first unlinked from its existing context.
2113 *
2114 * Returns the new element or NULL in case of error.
2115 */
2116xmlNodePtr
2117xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2118 xmlNodePtr parent;
2119
2120 if (cur == NULL) {
2121#ifdef DEBUG_TREE
2122 xmlGenericError(xmlGenericErrorContext,
2123 "xmlAddSibling : cur == NULL\n");
2124#endif
2125 return(NULL);
2126 }
2127
2128 if (elem == NULL) {
2129#ifdef DEBUG_TREE
2130 xmlGenericError(xmlGenericErrorContext,
2131 "xmlAddSibling : elem == NULL\n");
2132#endif
2133 return(NULL);
2134 }
2135
2136 /*
2137 * Constant time is we can rely on the ->parent->last to find
2138 * the last sibling.
2139 */
2140 if ((cur->parent != NULL) &&
2141 (cur->parent->children != NULL) &&
2142 (cur->parent->last != NULL) &&
2143 (cur->parent->last->next == NULL)) {
2144 cur = cur->parent->last;
2145 } else {
2146 while (cur->next != NULL) cur = cur->next;
2147 }
2148
2149 xmlUnlinkNode(elem);
2150
2151 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002152 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002153 xmlFreeNode(elem);
2154 return(cur);
2155 }
2156
2157 if (elem->doc != cur->doc) {
2158 xmlSetTreeDoc(elem, cur->doc);
2159 }
2160 parent = cur->parent;
2161 elem->prev = cur;
2162 elem->next = NULL;
2163 elem->parent = parent;
2164 cur->next = elem;
2165 if (parent != NULL)
2166 parent->last = elem;
2167
2168 return(elem);
2169}
2170
2171/**
2172 * xmlAddChildList:
2173 * @parent: the parent node
2174 * @cur: the first node in the list
2175 *
2176 * Add a list of node at the end of the child list of the parent
2177 * merging adjacent TEXT nodes (@cur may be freed)
2178 *
2179 * Returns the last child or NULL in case of error.
2180 */
2181xmlNodePtr
2182xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2183 xmlNodePtr prev;
2184
2185 if (parent == NULL) {
2186#ifdef DEBUG_TREE
2187 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002188 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002189#endif
2190 return(NULL);
2191 }
2192
2193 if (cur == NULL) {
2194#ifdef DEBUG_TREE
2195 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002196 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002197#endif
2198 return(NULL);
2199 }
2200
2201 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2202 (cur->doc != parent->doc)) {
2203#ifdef DEBUG_TREE
2204 xmlGenericError(xmlGenericErrorContext,
2205 "Elements moved to a different document\n");
2206#endif
2207 }
2208
2209 /*
2210 * add the first element at the end of the children list.
2211 */
2212 if (parent->children == NULL) {
2213 parent->children = cur;
2214 } else {
2215 /*
2216 * If cur and parent->last both are TEXT nodes, then merge them.
2217 */
2218 if ((cur->type == XML_TEXT_NODE) &&
2219 (parent->last->type == XML_TEXT_NODE) &&
2220 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002221 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002222 /*
2223 * if it's the only child, nothing more to be done.
2224 */
2225 if (cur->next == NULL) {
2226 xmlFreeNode(cur);
2227 return(parent->last);
2228 }
2229 prev = cur;
2230 cur = cur->next;
2231 xmlFreeNode(prev);
2232 }
2233 prev = parent->last;
2234 prev->next = cur;
2235 cur->prev = prev;
2236 }
2237 while (cur->next != NULL) {
2238 cur->parent = parent;
2239 if (cur->doc != parent->doc) {
2240 xmlSetTreeDoc(cur, parent->doc);
2241 }
2242 cur = cur->next;
2243 }
2244 cur->parent = parent;
2245 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2246 parent->last = cur;
2247
2248 return(cur);
2249}
2250
2251/**
2252 * xmlAddChild:
2253 * @parent: the parent node
2254 * @cur: the child node
2255 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002256 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002257 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002258 * If the new node was already inserted in a document it is
2259 * first unlinked from its existing context.
2260 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2261 * If there is an attribute with equal name, it is first destroyed.
2262 *
Owen Taylor3473f882001-02-23 17:55:21 +00002263 * Returns the child or NULL in case of error.
2264 */
2265xmlNodePtr
2266xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2267 xmlNodePtr prev;
2268
2269 if (parent == NULL) {
2270#ifdef DEBUG_TREE
2271 xmlGenericError(xmlGenericErrorContext,
2272 "xmlAddChild : parent == NULL\n");
2273#endif
2274 return(NULL);
2275 }
2276
2277 if (cur == NULL) {
2278#ifdef DEBUG_TREE
2279 xmlGenericError(xmlGenericErrorContext,
2280 "xmlAddChild : child == NULL\n");
2281#endif
2282 return(NULL);
2283 }
2284
Owen Taylor3473f882001-02-23 17:55:21 +00002285 /*
2286 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002287 * cur is then freed.
2288 */
2289 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002290 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002291 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002292 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002293 xmlFreeNode(cur);
2294 return(parent);
2295 }
2296 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2297 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002298 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002299 xmlFreeNode(cur);
2300 return(parent->last);
2301 }
2302 }
2303
2304 /*
2305 * add the new element at the end of the children list.
2306 */
2307 cur->parent = parent;
2308 if (cur->doc != parent->doc) {
2309 xmlSetTreeDoc(cur, parent->doc);
2310 }
2311
2312 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002313 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002314 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002315 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002316 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002317 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002318 xmlFreeNode(cur);
2319 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002320 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002321 if (cur->type == XML_ATTRIBUTE_NODE) {
2322 if (parent->properties == NULL) {
2323 parent->properties = (xmlAttrPtr) cur;
2324 } else {
2325 /* check if an attribute with the same name exists */
2326 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002327
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002328 if (cur->ns == NULL)
2329 lastattr = xmlHasProp(parent, cur->name);
2330 else
2331 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2332 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2333 /* different instance, destroy it (attributes must be unique) */
2334 xmlFreeProp(lastattr);
2335 }
2336 /* find the end */
2337 lastattr = parent->properties;
2338 while (lastattr->next != NULL) {
2339 lastattr = lastattr->next;
2340 }
2341 lastattr->next = (xmlAttrPtr) cur;
2342 ((xmlAttrPtr) cur)->prev = lastattr;
2343 }
2344 } else {
2345 if (parent->children == NULL) {
2346 parent->children = cur;
2347 parent->last = cur;
2348 } else {
2349 prev = parent->last;
2350 prev->next = cur;
2351 cur->prev = prev;
2352 parent->last = cur;
2353 }
2354 }
Owen Taylor3473f882001-02-23 17:55:21 +00002355 return(cur);
2356}
2357
2358/**
2359 * xmlGetLastChild:
2360 * @parent: the parent node
2361 *
2362 * Search the last child of a node.
2363 * Returns the last child or NULL if none.
2364 */
2365xmlNodePtr
2366xmlGetLastChild(xmlNodePtr parent) {
2367 if (parent == NULL) {
2368#ifdef DEBUG_TREE
2369 xmlGenericError(xmlGenericErrorContext,
2370 "xmlGetLastChild : parent == NULL\n");
2371#endif
2372 return(NULL);
2373 }
2374 return(parent->last);
2375}
2376
2377/**
2378 * xmlFreeNodeList:
2379 * @cur: the first node in the list
2380 *
2381 * Free a node and all its siblings, this is a recursive behaviour, all
2382 * the children are freed too.
2383 */
2384void
2385xmlFreeNodeList(xmlNodePtr cur) {
2386 xmlNodePtr next;
2387 if (cur == NULL) {
2388#ifdef DEBUG_TREE
2389 xmlGenericError(xmlGenericErrorContext,
2390 "xmlFreeNodeList : node == NULL\n");
2391#endif
2392 return;
2393 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002394 if (cur->type == XML_NAMESPACE_DECL) {
2395 xmlFreeNsList((xmlNsPtr) cur);
2396 return;
2397 }
Owen Taylor3473f882001-02-23 17:55:21 +00002398 while (cur != NULL) {
2399 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002400 /* unroll to speed up freeing the document */
2401 if (cur->type != XML_DTD_NODE) {
2402 if ((cur->children != NULL) &&
2403 (cur->type != XML_ENTITY_REF_NODE))
2404 xmlFreeNodeList(cur->children);
2405 if (cur->properties != NULL)
2406 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002407 if ((cur->type != XML_ELEMENT_NODE) &&
2408 (cur->type != XML_XINCLUDE_START) &&
2409 (cur->type != XML_XINCLUDE_END) &&
2410 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002411 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002412 }
2413 if (((cur->type == XML_ELEMENT_NODE) ||
2414 (cur->type == XML_XINCLUDE_START) ||
2415 (cur->type == XML_XINCLUDE_END)) &&
2416 (cur->nsDef != NULL))
2417 xmlFreeNsList(cur->nsDef);
2418
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002419 /*
2420 * When a node is a text node or a comment, it uses a global static
2421 * variable for the name of the node.
2422 *
2423 * The xmlStrEqual comparisons need to be done when (happened with
2424 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002425 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002426 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002427 * the string addresses compare are not sufficient.
2428 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002429 if ((cur->name != NULL) &&
2430 (cur->name != xmlStringText) &&
2431 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002432 (cur->name != xmlStringComment)) {
2433 if (cur->type == XML_TEXT_NODE) {
2434 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2435 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2436 xmlFree((char *) cur->name);
2437 } else if (cur->type == XML_COMMENT_NODE) {
2438 if (!xmlStrEqual(cur->name, xmlStringComment))
2439 xmlFree((char *) cur->name);
2440 } else
2441 xmlFree((char *) cur->name);
2442 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002443 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002444 xmlFree(cur);
2445 }
Owen Taylor3473f882001-02-23 17:55:21 +00002446 cur = next;
2447 }
2448}
2449
2450/**
2451 * xmlFreeNode:
2452 * @cur: the node
2453 *
2454 * Free a node, this is a recursive behaviour, all the children are freed too.
2455 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2456 */
2457void
2458xmlFreeNode(xmlNodePtr cur) {
2459 if (cur == NULL) {
2460#ifdef DEBUG_TREE
2461 xmlGenericError(xmlGenericErrorContext,
2462 "xmlFreeNode : node == NULL\n");
2463#endif
2464 return;
2465 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002466 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002467 if (cur->type == XML_DTD_NODE) {
2468 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002469 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002470 }
2471 if (cur->type == XML_NAMESPACE_DECL) {
2472 xmlFreeNs((xmlNsPtr) cur);
2473 return;
2474 }
Owen Taylor3473f882001-02-23 17:55:21 +00002475 if ((cur->children != NULL) &&
2476 (cur->type != XML_ENTITY_REF_NODE))
2477 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002478 if (cur->properties != NULL)
2479 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002480 if ((cur->type != XML_ELEMENT_NODE) &&
2481 (cur->content != NULL) &&
2482 (cur->type != XML_ENTITY_REF_NODE) &&
2483 (cur->type != XML_XINCLUDE_END) &&
2484 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002485 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002486 }
2487
Daniel Veillardacd370f2001-06-09 17:17:51 +00002488 /*
2489 * When a node is a text node or a comment, it uses a global static
2490 * variable for the name of the node.
2491 *
2492 * The xmlStrEqual comparisons need to be done when (happened with
2493 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002494 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002495 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002496 * are not sufficient.
2497 */
Owen Taylor3473f882001-02-23 17:55:21 +00002498 if ((cur->name != NULL) &&
2499 (cur->name != xmlStringText) &&
2500 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002501 (cur->name != xmlStringComment)) {
2502 if (cur->type == XML_TEXT_NODE) {
2503 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2504 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2505 xmlFree((char *) cur->name);
2506 } else if (cur->type == XML_COMMENT_NODE) {
2507 if (!xmlStrEqual(cur->name, xmlStringComment))
2508 xmlFree((char *) cur->name);
2509 } else
2510 xmlFree((char *) cur->name);
2511 }
2512
Owen Taylor3473f882001-02-23 17:55:21 +00002513 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002514 xmlFree(cur);
2515}
2516
2517/**
2518 * xmlUnlinkNode:
2519 * @cur: the node
2520 *
2521 * Unlink a node from it's current context, the node is not freed
2522 */
2523void
2524xmlUnlinkNode(xmlNodePtr cur) {
2525 if (cur == NULL) {
2526#ifdef DEBUG_TREE
2527 xmlGenericError(xmlGenericErrorContext,
2528 "xmlUnlinkNode : node == NULL\n");
2529#endif
2530 return;
2531 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002532 if (cur->type == XML_DTD_NODE) {
2533 xmlDocPtr doc;
2534 doc = cur->doc;
2535 if (doc->intSubset == (xmlDtdPtr) cur)
2536 doc->intSubset = NULL;
2537 if (doc->extSubset == (xmlDtdPtr) cur)
2538 doc->extSubset = NULL;
2539 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002540 if (cur->parent != NULL) {
2541 xmlNodePtr parent;
2542 parent = cur->parent;
2543 if (cur->type == XML_ATTRIBUTE_NODE) {
2544 if (parent->properties == (xmlAttrPtr) cur)
2545 parent->properties = ((xmlAttrPtr) cur)->next;
2546 } else {
2547 if (parent->children == cur)
2548 parent->children = cur->next;
2549 if (parent->last == cur)
2550 parent->last = cur->prev;
2551 }
2552 cur->parent = NULL;
2553 }
Owen Taylor3473f882001-02-23 17:55:21 +00002554 if (cur->next != NULL)
2555 cur->next->prev = cur->prev;
2556 if (cur->prev != NULL)
2557 cur->prev->next = cur->next;
2558 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002559}
2560
2561/**
2562 * xmlReplaceNode:
2563 * @old: the old node
2564 * @cur: the node
2565 *
2566 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002567 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002568 * first unlinked from its existing context.
2569 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002570 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002571 */
2572xmlNodePtr
2573xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2574 if (old == NULL) {
2575#ifdef DEBUG_TREE
2576 xmlGenericError(xmlGenericErrorContext,
2577 "xmlReplaceNode : old == NULL\n");
2578#endif
2579 return(NULL);
2580 }
2581 if (cur == NULL) {
2582 xmlUnlinkNode(old);
2583 return(old);
2584 }
2585 if (cur == old) {
2586 return(old);
2587 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002588 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2589#ifdef DEBUG_TREE
2590 xmlGenericError(xmlGenericErrorContext,
2591 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2592#endif
2593 return(old);
2594 }
2595 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2596#ifdef DEBUG_TREE
2597 xmlGenericError(xmlGenericErrorContext,
2598 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2599#endif
2600 return(old);
2601 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002602 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2603#ifdef DEBUG_TREE
2604 xmlGenericError(xmlGenericErrorContext,
2605 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2606#endif
2607 return(old);
2608 }
2609 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2610#ifdef DEBUG_TREE
2611 xmlGenericError(xmlGenericErrorContext,
2612 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2613#endif
2614 return(old);
2615 }
Owen Taylor3473f882001-02-23 17:55:21 +00002616 xmlUnlinkNode(cur);
2617 cur->doc = old->doc;
2618 cur->parent = old->parent;
2619 cur->next = old->next;
2620 if (cur->next != NULL)
2621 cur->next->prev = cur;
2622 cur->prev = old->prev;
2623 if (cur->prev != NULL)
2624 cur->prev->next = cur;
2625 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002626 if (cur->type == XML_ATTRIBUTE_NODE) {
2627 if (cur->parent->properties == (xmlAttrPtr)old)
2628 cur->parent->properties = ((xmlAttrPtr) cur);
2629 } else {
2630 if (cur->parent->children == old)
2631 cur->parent->children = cur;
2632 if (cur->parent->last == old)
2633 cur->parent->last = cur;
2634 }
Owen Taylor3473f882001-02-23 17:55:21 +00002635 }
2636 old->next = old->prev = NULL;
2637 old->parent = NULL;
2638 return(old);
2639}
2640
2641/************************************************************************
2642 * *
2643 * Copy operations *
2644 * *
2645 ************************************************************************/
2646
2647/**
2648 * xmlCopyNamespace:
2649 * @cur: the namespace
2650 *
2651 * Do a copy of the namespace.
2652 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002653 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002654 */
2655xmlNsPtr
2656xmlCopyNamespace(xmlNsPtr cur) {
2657 xmlNsPtr ret;
2658
2659 if (cur == NULL) return(NULL);
2660 switch (cur->type) {
2661 case XML_LOCAL_NAMESPACE:
2662 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2663 break;
2664 default:
2665#ifdef DEBUG_TREE
2666 xmlGenericError(xmlGenericErrorContext,
2667 "xmlCopyNamespace: invalid type %d\n", cur->type);
2668#endif
2669 return(NULL);
2670 }
2671 return(ret);
2672}
2673
2674/**
2675 * xmlCopyNamespaceList:
2676 * @cur: the first namespace
2677 *
2678 * Do a copy of an namespace list.
2679 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002680 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002681 */
2682xmlNsPtr
2683xmlCopyNamespaceList(xmlNsPtr cur) {
2684 xmlNsPtr ret = NULL;
2685 xmlNsPtr p = NULL,q;
2686
2687 while (cur != NULL) {
2688 q = xmlCopyNamespace(cur);
2689 if (p == NULL) {
2690 ret = p = q;
2691 } else {
2692 p->next = q;
2693 p = q;
2694 }
2695 cur = cur->next;
2696 }
2697 return(ret);
2698}
2699
2700static xmlNodePtr
2701xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2702/**
2703 * xmlCopyProp:
2704 * @target: the element where the attribute will be grafted
2705 * @cur: the attribute
2706 *
2707 * Do a copy of the attribute.
2708 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002709 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002710 */
2711xmlAttrPtr
2712xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2713 xmlAttrPtr ret;
2714
2715 if (cur == NULL) return(NULL);
2716 if (target != NULL)
2717 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2718 else if (cur->parent != NULL)
2719 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2720 else if (cur->children != NULL)
2721 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2722 else
2723 ret = xmlNewDocProp(NULL, cur->name, NULL);
2724 if (ret == NULL) return(NULL);
2725 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002726
Owen Taylor3473f882001-02-23 17:55:21 +00002727 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002728 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002729/*
2730 * if (target->doc)
2731 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2732 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2733 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2734 * else
2735 * ns = NULL;
2736 * ret->ns = ns;
2737 */
2738 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2739 if (ns == NULL) {
2740 /*
2741 * Humm, we are copying an element whose namespace is defined
2742 * out of the new tree scope. Search it in the original tree
2743 * and add it at the top of the new tree
2744 */
2745 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2746 if (ns != NULL) {
2747 xmlNodePtr root = target;
2748 xmlNodePtr pred = NULL;
2749
2750 while (root->parent != NULL) {
2751 pred = root;
2752 root = root->parent;
2753 }
2754 if (root == (xmlNodePtr) target->doc) {
2755 /* correct possibly cycling above the document elt */
2756 root = pred;
2757 }
2758 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2759 }
2760 } else {
2761 /*
2762 * we have to find something appropriate here since
2763 * we cant be sure, that the namespce we found is identified
2764 * by the prefix
2765 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002766 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002767 /* this is the nice case */
2768 ret->ns = ns;
2769 } else {
2770 /*
2771 * we are in trouble: we need a new reconcilied namespace.
2772 * This is expensive
2773 */
2774 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2775 }
2776 }
2777
Owen Taylor3473f882001-02-23 17:55:21 +00002778 } else
2779 ret->ns = NULL;
2780
2781 if (cur->children != NULL) {
2782 xmlNodePtr tmp;
2783
2784 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2785 ret->last = NULL;
2786 tmp = ret->children;
2787 while (tmp != NULL) {
2788 /* tmp->parent = (xmlNodePtr)ret; */
2789 if (tmp->next == NULL)
2790 ret->last = tmp;
2791 tmp = tmp->next;
2792 }
2793 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002794 /*
2795 * Try to handle IDs
2796 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002797 if ((target!= NULL) && (cur!= NULL) &&
2798 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002799 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2800 if (xmlIsID(cur->doc, cur->parent, cur)) {
2801 xmlChar *id;
2802
2803 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2804 if (id != NULL) {
2805 xmlAddID(NULL, target->doc, id, ret);
2806 xmlFree(id);
2807 }
2808 }
2809 }
Owen Taylor3473f882001-02-23 17:55:21 +00002810 return(ret);
2811}
2812
2813/**
2814 * xmlCopyPropList:
2815 * @target: the element where the attributes will be grafted
2816 * @cur: the first attribute
2817 *
2818 * Do a copy of an attribute list.
2819 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002820 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002821 */
2822xmlAttrPtr
2823xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
2824 xmlAttrPtr ret = NULL;
2825 xmlAttrPtr p = NULL,q;
2826
2827 while (cur != NULL) {
2828 q = xmlCopyProp(target, cur);
2829 if (p == NULL) {
2830 ret = p = q;
2831 } else {
2832 p->next = q;
2833 q->prev = p;
2834 p = q;
2835 }
2836 cur = cur->next;
2837 }
2838 return(ret);
2839}
2840
2841/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002842 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00002843 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002844 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00002845 * tricky reason: namespaces. Doing a direct copy of a node
2846 * say RPM:Copyright without changing the namespace pointer to
2847 * something else can produce stale links. One way to do it is
2848 * to keep a reference counter but this doesn't work as soon
2849 * as one move the element or the subtree out of the scope of
2850 * the existing namespace. The actual solution seems to add
2851 * a copy of the namespace at the top of the copied tree if
2852 * not available in the subtree.
2853 * Hence two functions, the public front-end call the inner ones
2854 */
2855
2856static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00002857xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00002858 int recursive) {
2859 xmlNodePtr ret;
2860
2861 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00002862 switch (node->type) {
2863 case XML_TEXT_NODE:
2864 case XML_CDATA_SECTION_NODE:
2865 case XML_ELEMENT_NODE:
2866 case XML_ENTITY_REF_NODE:
2867 case XML_ENTITY_NODE:
2868 case XML_PI_NODE:
2869 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002870 case XML_XINCLUDE_START:
2871 case XML_XINCLUDE_END:
2872 break;
2873 case XML_ATTRIBUTE_NODE:
2874 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
2875 case XML_NAMESPACE_DECL:
2876 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
2877
Daniel Veillard39196eb2001-06-19 18:09:42 +00002878 case XML_DOCUMENT_NODE:
2879 case XML_HTML_DOCUMENT_NODE:
2880#ifdef LIBXML_DOCB_ENABLED
2881 case XML_DOCB_DOCUMENT_NODE:
2882#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002883 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00002884 case XML_DOCUMENT_TYPE_NODE:
2885 case XML_DOCUMENT_FRAG_NODE:
2886 case XML_NOTATION_NODE:
2887 case XML_DTD_NODE:
2888 case XML_ELEMENT_DECL:
2889 case XML_ATTRIBUTE_DECL:
2890 case XML_ENTITY_DECL:
2891 return(NULL);
2892 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002893
Owen Taylor3473f882001-02-23 17:55:21 +00002894 /*
2895 * Allocate a new node and fill the fields.
2896 */
2897 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2898 if (ret == NULL) {
2899 xmlGenericError(xmlGenericErrorContext,
2900 "xmlStaticCopyNode : malloc failed\n");
2901 return(NULL);
2902 }
2903 memset(ret, 0, sizeof(xmlNode));
2904 ret->type = node->type;
2905
2906 ret->doc = doc;
2907 ret->parent = parent;
2908 if (node->name == xmlStringText)
2909 ret->name = xmlStringText;
2910 else if (node->name == xmlStringTextNoenc)
2911 ret->name = xmlStringTextNoenc;
2912 else if (node->name == xmlStringComment)
2913 ret->name = xmlStringComment;
2914 else if (node->name != NULL)
2915 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00002916 if ((node->type != XML_ELEMENT_NODE) &&
2917 (node->content != NULL) &&
2918 (node->type != XML_ENTITY_REF_NODE) &&
2919 (node->type != XML_XINCLUDE_END) &&
2920 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002921 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00002922 }else{
2923 if (node->type == XML_ELEMENT_NODE)
2924 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002925 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00002926 if (parent != NULL) {
2927 xmlNodePtr tmp;
2928
2929 tmp = xmlAddChild(parent, ret);
2930 /* node could have coalesced */
2931 if (tmp != ret)
2932 return(tmp);
2933 }
Owen Taylor3473f882001-02-23 17:55:21 +00002934
2935 if (!recursive) return(ret);
2936 if (node->nsDef != NULL)
2937 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2938
2939 if (node->ns != NULL) {
2940 xmlNsPtr ns;
2941
2942 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2943 if (ns == NULL) {
2944 /*
2945 * Humm, we are copying an element whose namespace is defined
2946 * out of the new tree scope. Search it in the original tree
2947 * and add it at the top of the new tree
2948 */
2949 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2950 if (ns != NULL) {
2951 xmlNodePtr root = ret;
2952
2953 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00002954 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002955 }
2956 } else {
2957 /*
2958 * reference the existing namespace definition in our own tree.
2959 */
2960 ret->ns = ns;
2961 }
2962 }
2963 if (node->properties != NULL)
2964 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00002965 if (node->type == XML_ENTITY_REF_NODE) {
2966 if ((doc == NULL) || (node->doc != doc)) {
2967 /*
2968 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00002969 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00002970 * we cannot keep the reference. Try to find it in the
2971 * target document.
2972 */
2973 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
2974 } else {
2975 ret->children = node->children;
2976 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00002977 ret->last = ret->children;
2978 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002979 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00002980 UPDATE_LAST_CHILD_AND_PARENT(ret)
2981 }
Owen Taylor3473f882001-02-23 17:55:21 +00002982 return(ret);
2983}
2984
2985static xmlNodePtr
2986xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2987 xmlNodePtr ret = NULL;
2988 xmlNodePtr p = NULL,q;
2989
2990 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00002991 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00002992 if (doc == NULL) {
2993 node = node->next;
2994 continue;
2995 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002996 if (doc->intSubset == NULL) {
2997 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2998 q->doc = doc;
2999 q->parent = parent;
3000 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003001 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003002 } else {
3003 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003004 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003005 }
3006 } else
3007 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003008 if (ret == NULL) {
3009 q->prev = NULL;
3010 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003011 } else if (p != q) {
3012 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003013 p->next = q;
3014 q->prev = p;
3015 p = q;
3016 }
3017 node = node->next;
3018 }
3019 return(ret);
3020}
3021
3022/**
3023 * xmlCopyNode:
3024 * @node: the node
3025 * @recursive: if 1 do a recursive copy.
3026 *
3027 * Do a copy of the node.
3028 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003029 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003030 */
3031xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003032xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003033 xmlNodePtr ret;
3034
3035 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3036 return(ret);
3037}
3038
3039/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003040 * xmlDocCopyNode:
3041 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003042 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003043 * @recursive: if 1 do a recursive copy.
3044 *
3045 * Do a copy of the node to a given document.
3046 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003047 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003048 */
3049xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003050xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003051 xmlNodePtr ret;
3052
3053 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3054 return(ret);
3055}
3056
3057/**
Owen Taylor3473f882001-02-23 17:55:21 +00003058 * xmlCopyNodeList:
3059 * @node: the first node in the list.
3060 *
3061 * Do a recursive copy of the node list.
3062 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003063 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003064 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003065xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003066 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3067 return(ret);
3068}
3069
3070/**
Owen Taylor3473f882001-02-23 17:55:21 +00003071 * xmlCopyDtd:
3072 * @dtd: the dtd
3073 *
3074 * Do a copy of the dtd.
3075 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003076 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003077 */
3078xmlDtdPtr
3079xmlCopyDtd(xmlDtdPtr dtd) {
3080 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003081 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003082
3083 if (dtd == NULL) return(NULL);
3084 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3085 if (ret == NULL) return(NULL);
3086 if (dtd->entities != NULL)
3087 ret->entities = (void *) xmlCopyEntitiesTable(
3088 (xmlEntitiesTablePtr) dtd->entities);
3089 if (dtd->notations != NULL)
3090 ret->notations = (void *) xmlCopyNotationTable(
3091 (xmlNotationTablePtr) dtd->notations);
3092 if (dtd->elements != NULL)
3093 ret->elements = (void *) xmlCopyElementTable(
3094 (xmlElementTablePtr) dtd->elements);
3095 if (dtd->attributes != NULL)
3096 ret->attributes = (void *) xmlCopyAttributeTable(
3097 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003098 if (dtd->pentities != NULL)
3099 ret->pentities = (void *) xmlCopyEntitiesTable(
3100 (xmlEntitiesTablePtr) dtd->pentities);
3101
3102 cur = dtd->children;
3103 while (cur != NULL) {
3104 q = NULL;
3105
3106 if (cur->type == XML_ENTITY_DECL) {
3107 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3108 switch (tmp->etype) {
3109 case XML_INTERNAL_GENERAL_ENTITY:
3110 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3111 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3112 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3113 break;
3114 case XML_INTERNAL_PARAMETER_ENTITY:
3115 case XML_EXTERNAL_PARAMETER_ENTITY:
3116 q = (xmlNodePtr)
3117 xmlGetParameterEntityFromDtd(ret, tmp->name);
3118 break;
3119 case XML_INTERNAL_PREDEFINED_ENTITY:
3120 break;
3121 }
3122 } else if (cur->type == XML_ELEMENT_DECL) {
3123 xmlElementPtr tmp = (xmlElementPtr) cur;
3124 q = (xmlNodePtr)
3125 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3126 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3127 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3128 q = (xmlNodePtr)
3129 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3130 } else if (cur->type == XML_COMMENT_NODE) {
3131 q = xmlCopyNode(cur, 0);
3132 }
3133
3134 if (q == NULL) {
3135 cur = cur->next;
3136 continue;
3137 }
3138
3139 if (p == NULL)
3140 ret->children = q;
3141 else
3142 p->next = q;
3143
3144 q->prev = p;
3145 q->parent = (xmlNodePtr) ret;
3146 q->next = NULL;
3147 ret->last = q;
3148 p = q;
3149 cur = cur->next;
3150 }
3151
Owen Taylor3473f882001-02-23 17:55:21 +00003152 return(ret);
3153}
3154
3155/**
3156 * xmlCopyDoc:
3157 * @doc: the document
3158 * @recursive: if 1 do a recursive copy.
3159 *
3160 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003161 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003162 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003163 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003164 */
3165xmlDocPtr
3166xmlCopyDoc(xmlDocPtr doc, int recursive) {
3167 xmlDocPtr ret;
3168
3169 if (doc == NULL) return(NULL);
3170 ret = xmlNewDoc(doc->version);
3171 if (ret == NULL) return(NULL);
3172 if (doc->name != NULL)
3173 ret->name = xmlMemStrdup(doc->name);
3174 if (doc->encoding != NULL)
3175 ret->encoding = xmlStrdup(doc->encoding);
3176 ret->charset = doc->charset;
3177 ret->compression = doc->compression;
3178 ret->standalone = doc->standalone;
3179 if (!recursive) return(ret);
3180
Daniel Veillardb33c2012001-04-25 12:59:04 +00003181 ret->last = NULL;
3182 ret->children = NULL;
3183 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003184 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003185 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003186 ret->intSubset->parent = ret;
3187 }
Owen Taylor3473f882001-02-23 17:55:21 +00003188 if (doc->oldNs != NULL)
3189 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3190 if (doc->children != NULL) {
3191 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003192
3193 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3194 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003195 ret->last = NULL;
3196 tmp = ret->children;
3197 while (tmp != NULL) {
3198 if (tmp->next == NULL)
3199 ret->last = tmp;
3200 tmp = tmp->next;
3201 }
3202 }
3203 return(ret);
3204}
3205
3206/************************************************************************
3207 * *
3208 * Content access functions *
3209 * *
3210 ************************************************************************/
3211
3212/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003213 * xmlGetLineNo:
3214 * @node : valid node
3215 *
3216 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003217 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003218 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003219 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003220 */
3221long
3222xmlGetLineNo(xmlNodePtr node)
3223{
3224 long result = -1;
3225
3226 if (!node)
3227 return result;
3228 if (node->type == XML_ELEMENT_NODE)
3229 result = (long) node->content;
3230 else if ((node->prev != NULL) &&
3231 ((node->prev->type == XML_ELEMENT_NODE) ||
3232 (node->prev->type == XML_TEXT_NODE)))
3233 result = xmlGetLineNo(node->prev);
3234 else if ((node->parent != NULL) &&
3235 ((node->parent->type == XML_ELEMENT_NODE) ||
3236 (node->parent->type == XML_TEXT_NODE)))
3237 result = xmlGetLineNo(node->parent);
3238
3239 return result;
3240}
3241
3242/**
3243 * xmlGetNodePath:
3244 * @node: a node
3245 *
3246 * Build a structure based Path for the given node
3247 *
3248 * Returns the new path or NULL in case of error. The caller must free
3249 * the returned string
3250 */
3251xmlChar *
3252xmlGetNodePath(xmlNodePtr node)
3253{
3254 xmlNodePtr cur, tmp, next;
3255 xmlChar *buffer = NULL, *temp;
3256 size_t buf_len;
3257 xmlChar *buf;
3258 char sep;
3259 const char *name;
3260 char nametemp[100];
3261 int occur = 0;
3262
3263 if (node == NULL)
3264 return (NULL);
3265
3266 buf_len = 500;
3267 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3268 if (buffer == NULL)
3269 return (NULL);
3270 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3271 if (buf == NULL) {
3272 xmlFree(buffer);
3273 return (NULL);
3274 }
3275
3276 buffer[0] = 0;
3277 cur = node;
3278 do {
3279 name = "";
3280 sep = '?';
3281 occur = 0;
3282 if ((cur->type == XML_DOCUMENT_NODE) ||
3283 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3284 if (buffer[0] == '/')
3285 break;
3286 sep = '/';
3287 next = NULL;
3288 } else if (cur->type == XML_ELEMENT_NODE) {
3289 sep = '/';
3290 name = (const char *) cur->name;
3291 if (cur->ns) {
3292 snprintf(nametemp, sizeof(nametemp) - 1,
3293 "%s:%s", cur->ns->prefix, cur->name);
3294 nametemp[sizeof(nametemp) - 1] = 0;
3295 name = nametemp;
3296 }
3297 next = cur->parent;
3298
3299 /*
3300 * Thumbler index computation
3301 */
3302 tmp = cur->prev;
3303 while (tmp != NULL) {
3304 if (xmlStrEqual(cur->name, tmp->name))
3305 occur++;
3306 tmp = tmp->prev;
3307 }
3308 if (occur == 0) {
3309 tmp = cur->next;
3310 while (tmp != NULL) {
3311 if (xmlStrEqual(cur->name, tmp->name))
3312 occur++;
3313 tmp = tmp->next;
3314 }
3315 if (occur != 0)
3316 occur = 1;
3317 } else
3318 occur++;
3319 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3320 sep = '@';
3321 name = (const char *) (((xmlAttrPtr) cur)->name);
3322 next = ((xmlAttrPtr) cur)->parent;
3323 } else {
3324 next = cur->parent;
3325 }
3326
3327 /*
3328 * Make sure there is enough room
3329 */
3330 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3331 buf_len =
3332 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3333 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3334 if (temp == NULL) {
3335 xmlFree(buf);
3336 xmlFree(buffer);
3337 return (NULL);
3338 }
3339 buffer = temp;
3340 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3341 if (temp == NULL) {
3342 xmlFree(buf);
3343 xmlFree(buffer);
3344 return (NULL);
3345 }
3346 buf = temp;
3347 }
3348 if (occur == 0)
3349 snprintf((char *) buf, buf_len, "%c%s%s",
3350 sep, name, (char *) buffer);
3351 else
3352 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3353 sep, name, occur, (char *) buffer);
3354 snprintf((char *) buffer, buf_len, "%s", buf);
3355 cur = next;
3356 } while (cur != NULL);
3357 xmlFree(buf);
3358 return (buffer);
3359}
3360
3361/**
Owen Taylor3473f882001-02-23 17:55:21 +00003362 * xmlDocGetRootElement:
3363 * @doc: the document
3364 *
3365 * Get the root element of the document (doc->children is a list
3366 * containing possibly comments, PIs, etc ...).
3367 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003368 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003369 */
3370xmlNodePtr
3371xmlDocGetRootElement(xmlDocPtr doc) {
3372 xmlNodePtr ret;
3373
3374 if (doc == NULL) return(NULL);
3375 ret = doc->children;
3376 while (ret != NULL) {
3377 if (ret->type == XML_ELEMENT_NODE)
3378 return(ret);
3379 ret = ret->next;
3380 }
3381 return(ret);
3382}
3383
3384/**
3385 * xmlDocSetRootElement:
3386 * @doc: the document
3387 * @root: the new document root element
3388 *
3389 * Set the root element of the document (doc->children is a list
3390 * containing possibly comments, PIs, etc ...).
3391 *
3392 * Returns the old root element if any was found
3393 */
3394xmlNodePtr
3395xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3396 xmlNodePtr old = NULL;
3397
3398 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003399 if (root == NULL)
3400 return(NULL);
3401 xmlUnlinkNode(root);
3402 root->doc = doc;
3403 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003404 old = doc->children;
3405 while (old != NULL) {
3406 if (old->type == XML_ELEMENT_NODE)
3407 break;
3408 old = old->next;
3409 }
3410 if (old == NULL) {
3411 if (doc->children == NULL) {
3412 doc->children = root;
3413 doc->last = root;
3414 } else {
3415 xmlAddSibling(doc->children, root);
3416 }
3417 } else {
3418 xmlReplaceNode(old, root);
3419 }
3420 return(old);
3421}
3422
3423/**
3424 * xmlNodeSetLang:
3425 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003426 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003427 *
3428 * Set the language of a node, i.e. the values of the xml:lang
3429 * attribute.
3430 */
3431void
3432xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003433 xmlNsPtr ns;
3434
Owen Taylor3473f882001-02-23 17:55:21 +00003435 if (cur == NULL) return;
3436 switch(cur->type) {
3437 case XML_TEXT_NODE:
3438 case XML_CDATA_SECTION_NODE:
3439 case XML_COMMENT_NODE:
3440 case XML_DOCUMENT_NODE:
3441 case XML_DOCUMENT_TYPE_NODE:
3442 case XML_DOCUMENT_FRAG_NODE:
3443 case XML_NOTATION_NODE:
3444 case XML_HTML_DOCUMENT_NODE:
3445 case XML_DTD_NODE:
3446 case XML_ELEMENT_DECL:
3447 case XML_ATTRIBUTE_DECL:
3448 case XML_ENTITY_DECL:
3449 case XML_PI_NODE:
3450 case XML_ENTITY_REF_NODE:
3451 case XML_ENTITY_NODE:
3452 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003453#ifdef LIBXML_DOCB_ENABLED
3454 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003455#endif
3456 case XML_XINCLUDE_START:
3457 case XML_XINCLUDE_END:
3458 return;
3459 case XML_ELEMENT_NODE:
3460 case XML_ATTRIBUTE_NODE:
3461 break;
3462 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003463 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3464 if (ns == NULL)
3465 return;
3466 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003467}
3468
3469/**
3470 * xmlNodeGetLang:
3471 * @cur: the node being checked
3472 *
3473 * Searches the language of a node, i.e. the values of the xml:lang
3474 * attribute or the one carried by the nearest ancestor.
3475 *
3476 * Returns a pointer to the lang value, or NULL if not found
3477 * It's up to the caller to free the memory.
3478 */
3479xmlChar *
3480xmlNodeGetLang(xmlNodePtr cur) {
3481 xmlChar *lang;
3482
3483 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003484 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003485 if (lang != NULL)
3486 return(lang);
3487 cur = cur->parent;
3488 }
3489 return(NULL);
3490}
3491
3492
3493/**
3494 * xmlNodeSetSpacePreserve:
3495 * @cur: the node being changed
3496 * @val: the xml:space value ("0": default, 1: "preserve")
3497 *
3498 * Set (or reset) the space preserving behaviour of a node, i.e. the
3499 * value of the xml:space attribute.
3500 */
3501void
3502xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003503 xmlNsPtr ns;
3504
Owen Taylor3473f882001-02-23 17:55:21 +00003505 if (cur == NULL) return;
3506 switch(cur->type) {
3507 case XML_TEXT_NODE:
3508 case XML_CDATA_SECTION_NODE:
3509 case XML_COMMENT_NODE:
3510 case XML_DOCUMENT_NODE:
3511 case XML_DOCUMENT_TYPE_NODE:
3512 case XML_DOCUMENT_FRAG_NODE:
3513 case XML_NOTATION_NODE:
3514 case XML_HTML_DOCUMENT_NODE:
3515 case XML_DTD_NODE:
3516 case XML_ELEMENT_DECL:
3517 case XML_ATTRIBUTE_DECL:
3518 case XML_ENTITY_DECL:
3519 case XML_PI_NODE:
3520 case XML_ENTITY_REF_NODE:
3521 case XML_ENTITY_NODE:
3522 case XML_NAMESPACE_DECL:
3523 case XML_XINCLUDE_START:
3524 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003525#ifdef LIBXML_DOCB_ENABLED
3526 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003527#endif
3528 return;
3529 case XML_ELEMENT_NODE:
3530 case XML_ATTRIBUTE_NODE:
3531 break;
3532 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003533 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3534 if (ns == NULL)
3535 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003536 switch (val) {
3537 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003538 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003539 break;
3540 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003541 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003542 break;
3543 }
3544}
3545
3546/**
3547 * xmlNodeGetSpacePreserve:
3548 * @cur: the node being checked
3549 *
3550 * Searches the space preserving behaviour of a node, i.e. the values
3551 * of the xml:space attribute or the one carried by the nearest
3552 * ancestor.
3553 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003554 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003555 */
3556int
3557xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3558 xmlChar *space;
3559
3560 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003561 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003562 if (space != NULL) {
3563 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3564 xmlFree(space);
3565 return(1);
3566 }
3567 if (xmlStrEqual(space, BAD_CAST "default")) {
3568 xmlFree(space);
3569 return(0);
3570 }
3571 xmlFree(space);
3572 }
3573 cur = cur->parent;
3574 }
3575 return(-1);
3576}
3577
3578/**
3579 * xmlNodeSetName:
3580 * @cur: the node being changed
3581 * @name: the new tag name
3582 *
3583 * Set (or reset) the name of a node.
3584 */
3585void
3586xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3587 if (cur == NULL) return;
3588 if (name == NULL) return;
3589 switch(cur->type) {
3590 case XML_TEXT_NODE:
3591 case XML_CDATA_SECTION_NODE:
3592 case XML_COMMENT_NODE:
3593 case XML_DOCUMENT_TYPE_NODE:
3594 case XML_DOCUMENT_FRAG_NODE:
3595 case XML_NOTATION_NODE:
3596 case XML_HTML_DOCUMENT_NODE:
3597 case XML_NAMESPACE_DECL:
3598 case XML_XINCLUDE_START:
3599 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003600#ifdef LIBXML_DOCB_ENABLED
3601 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003602#endif
3603 return;
3604 case XML_ELEMENT_NODE:
3605 case XML_ATTRIBUTE_NODE:
3606 case XML_PI_NODE:
3607 case XML_ENTITY_REF_NODE:
3608 case XML_ENTITY_NODE:
3609 case XML_DTD_NODE:
3610 case XML_DOCUMENT_NODE:
3611 case XML_ELEMENT_DECL:
3612 case XML_ATTRIBUTE_DECL:
3613 case XML_ENTITY_DECL:
3614 break;
3615 }
3616 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3617 cur->name = xmlStrdup(name);
3618}
3619
3620/**
3621 * xmlNodeSetBase:
3622 * @cur: the node being changed
3623 * @uri: the new base URI
3624 *
3625 * Set (or reset) the base URI of a node, i.e. the value of the
3626 * xml:base attribute.
3627 */
3628void
3629xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003630 xmlNsPtr ns;
3631
Owen Taylor3473f882001-02-23 17:55:21 +00003632 if (cur == NULL) return;
3633 switch(cur->type) {
3634 case XML_TEXT_NODE:
3635 case XML_CDATA_SECTION_NODE:
3636 case XML_COMMENT_NODE:
3637 case XML_DOCUMENT_NODE:
3638 case XML_DOCUMENT_TYPE_NODE:
3639 case XML_DOCUMENT_FRAG_NODE:
3640 case XML_NOTATION_NODE:
3641 case XML_HTML_DOCUMENT_NODE:
3642 case XML_DTD_NODE:
3643 case XML_ELEMENT_DECL:
3644 case XML_ATTRIBUTE_DECL:
3645 case XML_ENTITY_DECL:
3646 case XML_PI_NODE:
3647 case XML_ENTITY_REF_NODE:
3648 case XML_ENTITY_NODE:
3649 case XML_NAMESPACE_DECL:
3650 case XML_XINCLUDE_START:
3651 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003652#ifdef LIBXML_DOCB_ENABLED
3653 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003654#endif
3655 return;
3656 case XML_ELEMENT_NODE:
3657 case XML_ATTRIBUTE_NODE:
3658 break;
3659 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003660
3661 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3662 if (ns == NULL)
3663 return;
3664 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003665}
3666
3667/**
Owen Taylor3473f882001-02-23 17:55:21 +00003668 * xmlNodeGetBase:
3669 * @doc: the document the node pertains to
3670 * @cur: the node being checked
3671 *
3672 * Searches for the BASE URL. The code should work on both XML
3673 * and HTML document even if base mechanisms are completely different.
3674 * It returns the base as defined in RFC 2396 sections
3675 * 5.1.1. Base URI within Document Content
3676 * and
3677 * 5.1.2. Base URI from the Encapsulating Entity
3678 * However it does not return the document base (5.1.3), use
3679 * xmlDocumentGetBase() for this
3680 *
3681 * Returns a pointer to the base URL, or NULL if not found
3682 * It's up to the caller to free the memory.
3683 */
3684xmlChar *
3685xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003686 xmlChar *oldbase = NULL;
3687 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003688
3689 if ((cur == NULL) && (doc == NULL))
3690 return(NULL);
3691 if (doc == NULL) doc = cur->doc;
3692 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3693 cur = doc->children;
3694 while ((cur != NULL) && (cur->name != NULL)) {
3695 if (cur->type != XML_ELEMENT_NODE) {
3696 cur = cur->next;
3697 continue;
3698 }
3699 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3700 cur = cur->children;
3701 continue;
3702 }
3703 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3704 cur = cur->children;
3705 continue;
3706 }
3707 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3708 return(xmlGetProp(cur, BAD_CAST "href"));
3709 }
3710 cur = cur->next;
3711 }
3712 return(NULL);
3713 }
3714 while (cur != NULL) {
3715 if (cur->type == XML_ENTITY_DECL) {
3716 xmlEntityPtr ent = (xmlEntityPtr) cur;
3717 return(xmlStrdup(ent->URI));
3718 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003719 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003720 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003721 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003722 if (oldbase != NULL) {
3723 newbase = xmlBuildURI(oldbase, base);
3724 if (newbase != NULL) {
3725 xmlFree(oldbase);
3726 xmlFree(base);
3727 oldbase = newbase;
3728 } else {
3729 xmlFree(oldbase);
3730 xmlFree(base);
3731 return(NULL);
3732 }
3733 } else {
3734 oldbase = base;
3735 }
3736 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3737 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3738 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3739 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003740 }
3741 }
Owen Taylor3473f882001-02-23 17:55:21 +00003742 cur = cur->parent;
3743 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003744 if ((doc != NULL) && (doc->URL != NULL)) {
3745 if (oldbase == NULL)
3746 return(xmlStrdup(doc->URL));
3747 newbase = xmlBuildURI(oldbase, doc->URL);
3748 xmlFree(oldbase);
3749 return(newbase);
3750 }
3751 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003752}
3753
3754/**
3755 * xmlNodeGetContent:
3756 * @cur: the node being read
3757 *
3758 * Read the value of a node, this can be either the text carried
3759 * directly by this node if it's a TEXT node or the aggregate string
3760 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003761 * Entity references are substituted.
3762 * Returns a new #xmlChar * or NULL if no content is available.
Owen Taylor3473f882001-02-23 17:55:21 +00003763 * It's up to the caller to free the memory.
3764 */
3765xmlChar *
3766xmlNodeGetContent(xmlNodePtr cur) {
3767 if (cur == NULL) return(NULL);
3768 switch (cur->type) {
3769 case XML_DOCUMENT_FRAG_NODE:
3770 case XML_ELEMENT_NODE: {
3771 xmlNodePtr tmp = cur;
3772 xmlBufferPtr buffer;
3773 xmlChar *ret;
3774
3775 buffer = xmlBufferCreate();
3776 if (buffer == NULL)
3777 return(NULL);
3778 while (tmp != NULL) {
3779 switch (tmp->type) {
Daniel Veillard2d703722001-05-30 18:32:34 +00003780 case XML_CDATA_SECTION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003781 case XML_TEXT_NODE:
3782 if (tmp->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00003783 xmlBufferCat(buffer, tmp->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003784 break;
3785 case XML_ENTITY_REF_NODE: {
3786 xmlEntityPtr ent;
3787
3788 ent = xmlGetDocEntity(cur->doc, tmp->name);
3789 if (ent != NULL)
3790 xmlBufferCat(buffer, ent->content);
3791 }
3792 default:
3793 break;
3794 }
3795 /*
3796 * Skip to next node
3797 */
3798 if (tmp->children != NULL) {
3799 if (tmp->children->type != XML_ENTITY_DECL) {
3800 tmp = tmp->children;
3801 continue;
3802 }
3803 }
Daniel Veillard6c831202001-03-07 15:57:53 +00003804 if (tmp == cur)
3805 break;
3806
Owen Taylor3473f882001-02-23 17:55:21 +00003807 if (tmp->next != NULL) {
3808 tmp = tmp->next;
3809 continue;
3810 }
3811
3812 do {
3813 tmp = tmp->parent;
3814 if (tmp == NULL)
3815 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00003816 if (tmp == cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00003817 tmp = NULL;
3818 break;
3819 }
3820 if (tmp->next != NULL) {
3821 tmp = tmp->next;
3822 break;
3823 }
3824 } while (tmp != NULL);
3825 }
3826 ret = buffer->content;
3827 buffer->content = NULL;
3828 xmlBufferFree(buffer);
3829 return(ret);
3830 }
3831 case XML_ATTRIBUTE_NODE: {
3832 xmlAttrPtr attr = (xmlAttrPtr) cur;
3833 if (attr->parent != NULL)
3834 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
3835 else
3836 return(xmlNodeListGetString(NULL, attr->children, 1));
3837 break;
3838 }
3839 case XML_COMMENT_NODE:
3840 case XML_PI_NODE:
3841 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00003842 return(xmlStrdup(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00003843 return(NULL);
3844 case XML_ENTITY_REF_NODE:
3845 /*
3846 * Locate the entity, and get it's content
3847 * @@@
3848 */
3849 return(NULL);
3850 case XML_ENTITY_NODE:
3851 case XML_DOCUMENT_NODE:
3852 case XML_HTML_DOCUMENT_NODE:
3853 case XML_DOCUMENT_TYPE_NODE:
3854 case XML_NOTATION_NODE:
3855 case XML_DTD_NODE:
3856 case XML_XINCLUDE_START:
3857 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003858#ifdef LIBXML_DOCB_ENABLED
3859 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003860#endif
3861 return(NULL);
3862 case XML_NAMESPACE_DECL:
3863 return(xmlStrdup(((xmlNsPtr)cur)->href));
3864 case XML_ELEMENT_DECL:
3865 /* TODO !!! */
3866 return(NULL);
3867 case XML_ATTRIBUTE_DECL:
3868 /* TODO !!! */
3869 return(NULL);
3870 case XML_ENTITY_DECL:
3871 /* TODO !!! */
3872 return(NULL);
3873 case XML_CDATA_SECTION_NODE:
3874 case XML_TEXT_NODE:
3875 if (cur->content != NULL)
Daniel Veillard9ff88172002-03-11 09:15:32 +00003876 return(xmlStrdup(cur->content));
Owen Taylor3473f882001-02-23 17:55:21 +00003877 return(NULL);
3878 }
3879 return(NULL);
3880}
3881
3882/**
3883 * xmlNodeSetContent:
3884 * @cur: the node being modified
3885 * @content: the new value of the content
3886 *
3887 * Replace the content of a node.
3888 */
3889void
3890xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
3891 if (cur == NULL) {
3892#ifdef DEBUG_TREE
3893 xmlGenericError(xmlGenericErrorContext,
3894 "xmlNodeSetContent : node == NULL\n");
3895#endif
3896 return;
3897 }
3898 switch (cur->type) {
3899 case XML_DOCUMENT_FRAG_NODE:
3900 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003901 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003902 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3903 cur->children = xmlStringGetNodeList(cur->doc, content);
3904 UPDATE_LAST_CHILD_AND_PARENT(cur)
3905 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003906 case XML_TEXT_NODE:
3907 case XML_CDATA_SECTION_NODE:
3908 case XML_ENTITY_REF_NODE:
3909 case XML_ENTITY_NODE:
3910 case XML_PI_NODE:
3911 case XML_COMMENT_NODE:
3912 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003913 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003914 }
3915 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3916 cur->last = cur->children = NULL;
3917 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003918 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00003919 } else
3920 cur->content = NULL;
3921 break;
3922 case XML_DOCUMENT_NODE:
3923 case XML_HTML_DOCUMENT_NODE:
3924 case XML_DOCUMENT_TYPE_NODE:
3925 case XML_XINCLUDE_START:
3926 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003927#ifdef LIBXML_DOCB_ENABLED
3928 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003929#endif
3930 break;
3931 case XML_NOTATION_NODE:
3932 break;
3933 case XML_DTD_NODE:
3934 break;
3935 case XML_NAMESPACE_DECL:
3936 break;
3937 case XML_ELEMENT_DECL:
3938 /* TODO !!! */
3939 break;
3940 case XML_ATTRIBUTE_DECL:
3941 /* TODO !!! */
3942 break;
3943 case XML_ENTITY_DECL:
3944 /* TODO !!! */
3945 break;
3946 }
3947}
3948
3949/**
3950 * xmlNodeSetContentLen:
3951 * @cur: the node being modified
3952 * @content: the new value of the content
3953 * @len: the size of @content
3954 *
3955 * Replace the content of a node.
3956 */
3957void
3958xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
3959 if (cur == NULL) {
3960#ifdef DEBUG_TREE
3961 xmlGenericError(xmlGenericErrorContext,
3962 "xmlNodeSetContentLen : node == NULL\n");
3963#endif
3964 return;
3965 }
3966 switch (cur->type) {
3967 case XML_DOCUMENT_FRAG_NODE:
3968 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00003969 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003970 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3971 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
3972 UPDATE_LAST_CHILD_AND_PARENT(cur)
3973 break;
Owen Taylor3473f882001-02-23 17:55:21 +00003974 case XML_TEXT_NODE:
3975 case XML_CDATA_SECTION_NODE:
3976 case XML_ENTITY_REF_NODE:
3977 case XML_ENTITY_NODE:
3978 case XML_PI_NODE:
3979 case XML_COMMENT_NODE:
3980 case XML_NOTATION_NODE:
3981 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003982 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003983 }
3984 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3985 cur->children = cur->last = NULL;
3986 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003987 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00003988 } else
3989 cur->content = NULL;
3990 break;
3991 case XML_DOCUMENT_NODE:
3992 case XML_DTD_NODE:
3993 case XML_HTML_DOCUMENT_NODE:
3994 case XML_DOCUMENT_TYPE_NODE:
3995 case XML_NAMESPACE_DECL:
3996 case XML_XINCLUDE_START:
3997 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003998#ifdef LIBXML_DOCB_ENABLED
3999 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004000#endif
4001 break;
4002 case XML_ELEMENT_DECL:
4003 /* TODO !!! */
4004 break;
4005 case XML_ATTRIBUTE_DECL:
4006 /* TODO !!! */
4007 break;
4008 case XML_ENTITY_DECL:
4009 /* TODO !!! */
4010 break;
4011 }
4012}
4013
4014/**
4015 * xmlNodeAddContentLen:
4016 * @cur: the node being modified
4017 * @content: extra content
4018 * @len: the size of @content
4019 *
4020 * Append the extra substring to the node content.
4021 */
4022void
4023xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4024 if (cur == NULL) {
4025#ifdef DEBUG_TREE
4026 xmlGenericError(xmlGenericErrorContext,
4027 "xmlNodeAddContentLen : node == NULL\n");
4028#endif
4029 return;
4030 }
4031 if (len <= 0) return;
4032 switch (cur->type) {
4033 case XML_DOCUMENT_FRAG_NODE:
4034 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004035 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004036
Daniel Veillard7db37732001-07-12 01:20:08 +00004037 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004038 newNode = xmlNewTextLen(content, len);
4039 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004040 tmp = xmlAddChild(cur, newNode);
4041 if (tmp != newNode)
4042 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004043 if ((last != NULL) && (last->next == newNode)) {
4044 xmlTextMerge(last, newNode);
4045 }
4046 }
4047 break;
4048 }
4049 case XML_ATTRIBUTE_NODE:
4050 break;
4051 case XML_TEXT_NODE:
4052 case XML_CDATA_SECTION_NODE:
4053 case XML_ENTITY_REF_NODE:
4054 case XML_ENTITY_NODE:
4055 case XML_PI_NODE:
4056 case XML_COMMENT_NODE:
4057 case XML_NOTATION_NODE:
4058 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004059 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004060 }
4061 case XML_DOCUMENT_NODE:
4062 case XML_DTD_NODE:
4063 case XML_HTML_DOCUMENT_NODE:
4064 case XML_DOCUMENT_TYPE_NODE:
4065 case XML_NAMESPACE_DECL:
4066 case XML_XINCLUDE_START:
4067 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004068#ifdef LIBXML_DOCB_ENABLED
4069 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004070#endif
4071 break;
4072 case XML_ELEMENT_DECL:
4073 case XML_ATTRIBUTE_DECL:
4074 case XML_ENTITY_DECL:
4075 break;
4076 }
4077}
4078
4079/**
4080 * xmlNodeAddContent:
4081 * @cur: the node being modified
4082 * @content: extra content
4083 *
4084 * Append the extra substring to the node content.
4085 */
4086void
4087xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4088 int len;
4089
4090 if (cur == NULL) {
4091#ifdef DEBUG_TREE
4092 xmlGenericError(xmlGenericErrorContext,
4093 "xmlNodeAddContent : node == NULL\n");
4094#endif
4095 return;
4096 }
4097 if (content == NULL) return;
4098 len = xmlStrlen(content);
4099 xmlNodeAddContentLen(cur, content, len);
4100}
4101
4102/**
4103 * xmlTextMerge:
4104 * @first: the first text node
4105 * @second: the second text node being merged
4106 *
4107 * Merge two text nodes into one
4108 * Returns the first text node augmented
4109 */
4110xmlNodePtr
4111xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4112 if (first == NULL) return(second);
4113 if (second == NULL) return(first);
4114 if (first->type != XML_TEXT_NODE) return(first);
4115 if (second->type != XML_TEXT_NODE) return(first);
4116 if (second->name != first->name)
4117 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004118 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004119 xmlUnlinkNode(second);
4120 xmlFreeNode(second);
4121 return(first);
4122}
4123
4124/**
4125 * xmlGetNsList:
4126 * @doc: the document
4127 * @node: the current node
4128 *
4129 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004130 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004131 * that need to be freed by the caller or NULL if no
4132 * namespace if defined
4133 */
4134xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004135xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4136{
Owen Taylor3473f882001-02-23 17:55:21 +00004137 xmlNsPtr cur;
4138 xmlNsPtr *ret = NULL;
4139 int nbns = 0;
4140 int maxns = 10;
4141 int i;
4142
4143 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004144 if (node->type == XML_ELEMENT_NODE) {
4145 cur = node->nsDef;
4146 while (cur != NULL) {
4147 if (ret == NULL) {
4148 ret =
4149 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4150 sizeof(xmlNsPtr));
4151 if (ret == NULL) {
4152 xmlGenericError(xmlGenericErrorContext,
4153 "xmlGetNsList : out of memory!\n");
4154 return (NULL);
4155 }
4156 ret[nbns] = NULL;
4157 }
4158 for (i = 0; i < nbns; i++) {
4159 if ((cur->prefix == ret[i]->prefix) ||
4160 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4161 break;
4162 }
4163 if (i >= nbns) {
4164 if (nbns >= maxns) {
4165 maxns *= 2;
4166 ret = (xmlNsPtr *) xmlRealloc(ret,
4167 (maxns +
4168 1) *
4169 sizeof(xmlNsPtr));
4170 if (ret == NULL) {
4171 xmlGenericError(xmlGenericErrorContext,
4172 "xmlGetNsList : realloc failed!\n");
4173 return (NULL);
4174 }
4175 }
4176 ret[nbns++] = cur;
4177 ret[nbns] = NULL;
4178 }
Owen Taylor3473f882001-02-23 17:55:21 +00004179
Daniel Veillard77044732001-06-29 21:31:07 +00004180 cur = cur->next;
4181 }
4182 }
4183 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004184 }
Daniel Veillard77044732001-06-29 21:31:07 +00004185 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004186}
4187
4188/**
4189 * xmlSearchNs:
4190 * @doc: the document
4191 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004192 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004193 *
4194 * Search a Ns registered under a given name space for a document.
4195 * recurse on the parents until it finds the defined namespace
4196 * or return NULL otherwise.
4197 * @nameSpace can be NULL, this is a search for the default namespace.
4198 * We don't allow to cross entities boundaries. If you don't declare
4199 * the namespace within those you will be in troubles !!! A warning
4200 * is generated to cover this case.
4201 *
4202 * Returns the namespace pointer or NULL.
4203 */
4204xmlNsPtr
4205xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4206 xmlNsPtr cur;
4207
4208 if (node == NULL) return(NULL);
4209 if ((nameSpace != NULL) &&
4210 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillardd2f23002002-01-21 13:36:00 +00004211 if (doc == NULL)
4212 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004213 if (doc->oldNs == NULL) {
4214 /*
4215 * Allocate a new Namespace and fill the fields.
4216 */
4217 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4218 if (doc->oldNs == NULL) {
4219 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004220 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004221 return(NULL);
4222 }
4223 memset(doc->oldNs, 0, sizeof(xmlNs));
4224 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4225
4226 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4227 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4228 }
4229 return(doc->oldNs);
4230 }
4231 while (node != NULL) {
4232 if ((node->type == XML_ENTITY_REF_NODE) ||
4233 (node->type == XML_ENTITY_NODE) ||
4234 (node->type == XML_ENTITY_DECL))
4235 return(NULL);
4236 if (node->type == XML_ELEMENT_NODE) {
4237 cur = node->nsDef;
4238 while (cur != NULL) {
4239 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4240 (cur->href != NULL))
4241 return(cur);
4242 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4243 (cur->href != NULL) &&
4244 (xmlStrEqual(cur->prefix, nameSpace)))
4245 return(cur);
4246 cur = cur->next;
4247 }
4248 }
4249 node = node->parent;
4250 }
4251 return(NULL);
4252}
4253
4254/**
4255 * xmlSearchNsByHref:
4256 * @doc: the document
4257 * @node: the current node
4258 * @href: the namespace value
4259 *
4260 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4261 * the defined namespace or return NULL otherwise.
4262 * Returns the namespace pointer or NULL.
4263 */
4264xmlNsPtr
4265xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4266 xmlNsPtr cur;
4267 xmlNodePtr orig = node;
4268
4269 if ((node == NULL) || (href == NULL)) return(NULL);
4270 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004271 /*
4272 * Only the document can hold the XML spec namespace.
4273 */
4274 if (doc == NULL)
4275 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004276 if (doc->oldNs == NULL) {
4277 /*
4278 * Allocate a new Namespace and fill the fields.
4279 */
4280 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4281 if (doc->oldNs == NULL) {
4282 xmlGenericError(xmlGenericErrorContext,
4283 "xmlSearchNsByHref : malloc failed\n");
4284 return(NULL);
4285 }
4286 memset(doc->oldNs, 0, sizeof(xmlNs));
4287 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4288
4289 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4290 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4291 }
4292 return(doc->oldNs);
4293 }
4294 while (node != NULL) {
4295 cur = node->nsDef;
4296 while (cur != NULL) {
4297 if ((cur->href != NULL) && (href != NULL) &&
4298 (xmlStrEqual(cur->href, href))) {
4299 /*
4300 * Check that the prefix is not shadowed between orig and node
4301 */
4302 xmlNodePtr check = orig;
4303 xmlNsPtr tst;
4304
4305 while (check != node) {
4306 tst = check->nsDef;
4307 while (tst != NULL) {
4308 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4309 goto shadowed;
4310 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4311 (xmlStrEqual(tst->prefix, cur->prefix)))
4312 goto shadowed;
4313 tst = tst->next;
4314 }
4315 check = check->parent;
4316 }
4317 return(cur);
4318 }
4319shadowed:
4320 cur = cur->next;
4321 }
4322 node = node->parent;
4323 }
4324 return(NULL);
4325}
4326
4327/**
4328 * xmlNewReconciliedNs
4329 * @doc: the document
4330 * @tree: a node expected to hold the new namespace
4331 * @ns: the original namespace
4332 *
4333 * This function tries to locate a namespace definition in a tree
4334 * ancestors, or create a new namespace definition node similar to
4335 * @ns trying to reuse the same prefix. However if the given prefix is
4336 * null (default namespace) or reused within the subtree defined by
4337 * @tree or on one of its ancestors then a new prefix is generated.
4338 * Returns the (new) namespace definition or NULL in case of error
4339 */
4340xmlNsPtr
4341xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4342 xmlNsPtr def;
4343 xmlChar prefix[50];
4344 int counter = 1;
4345
4346 if (tree == NULL) {
4347#ifdef DEBUG_TREE
4348 xmlGenericError(xmlGenericErrorContext,
4349 "xmlNewReconciliedNs : tree == NULL\n");
4350#endif
4351 return(NULL);
4352 }
4353 if (ns == NULL) {
4354#ifdef DEBUG_TREE
4355 xmlGenericError(xmlGenericErrorContext,
4356 "xmlNewReconciliedNs : ns == NULL\n");
4357#endif
4358 return(NULL);
4359 }
4360 /*
4361 * Search an existing namespace definition inherited.
4362 */
4363 def = xmlSearchNsByHref(doc, tree, ns->href);
4364 if (def != NULL)
4365 return(def);
4366
4367 /*
4368 * Find a close prefix which is not already in use.
4369 * Let's strip namespace prefixes longer than 20 chars !
4370 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004371 if (ns->prefix == NULL)
4372 sprintf((char *) prefix, "default");
4373 else
4374 sprintf((char *) prefix, "%.20s", ns->prefix);
4375
Owen Taylor3473f882001-02-23 17:55:21 +00004376 def = xmlSearchNs(doc, tree, prefix);
4377 while (def != NULL) {
4378 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004379 if (ns->prefix == NULL)
4380 sprintf((char *) prefix, "default%d", counter++);
4381 else
4382 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004383 def = xmlSearchNs(doc, tree, prefix);
4384 }
4385
4386 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004387 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004388 */
4389 def = xmlNewNs(tree, ns->href, prefix);
4390 return(def);
4391}
4392
4393/**
4394 * xmlReconciliateNs
4395 * @doc: the document
4396 * @tree: a node defining the subtree to reconciliate
4397 *
4398 * This function checks that all the namespaces declared within the given
4399 * tree are properly declared. This is needed for example after Copy or Cut
4400 * and then paste operations. The subtree may still hold pointers to
4401 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004402 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004403 * the new environment. If not possible the new namespaces are redeclared
4404 * on @tree at the top of the given subtree.
4405 * Returns the number of namespace declarations created or -1 in case of error.
4406 */
4407int
4408xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4409 xmlNsPtr *oldNs = NULL;
4410 xmlNsPtr *newNs = NULL;
4411 int sizeCache = 0;
4412 int nbCache = 0;
4413
4414 xmlNsPtr n;
4415 xmlNodePtr node = tree;
4416 xmlAttrPtr attr;
4417 int ret = 0, i;
4418
4419 while (node != NULL) {
4420 /*
4421 * Reconciliate the node namespace
4422 */
4423 if (node->ns != NULL) {
4424 /*
4425 * initialize the cache if needed
4426 */
4427 if (sizeCache == 0) {
4428 sizeCache = 10;
4429 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4430 sizeof(xmlNsPtr));
4431 if (oldNs == NULL) {
4432 xmlGenericError(xmlGenericErrorContext,
4433 "xmlReconciliateNs : memory pbm\n");
4434 return(-1);
4435 }
4436 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4437 sizeof(xmlNsPtr));
4438 if (newNs == NULL) {
4439 xmlGenericError(xmlGenericErrorContext,
4440 "xmlReconciliateNs : memory pbm\n");
4441 xmlFree(oldNs);
4442 return(-1);
4443 }
4444 }
4445 for (i = 0;i < nbCache;i++) {
4446 if (oldNs[i] == node->ns) {
4447 node->ns = newNs[i];
4448 break;
4449 }
4450 }
4451 if (i == nbCache) {
4452 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004453 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004454 */
4455 n = xmlNewReconciliedNs(doc, tree, node->ns);
4456 if (n != NULL) { /* :-( what if else ??? */
4457 /*
4458 * check if we need to grow the cache buffers.
4459 */
4460 if (sizeCache <= nbCache) {
4461 sizeCache *= 2;
4462 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4463 sizeof(xmlNsPtr));
4464 if (oldNs == NULL) {
4465 xmlGenericError(xmlGenericErrorContext,
4466 "xmlReconciliateNs : memory pbm\n");
4467 xmlFree(newNs);
4468 return(-1);
4469 }
4470 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4471 sizeof(xmlNsPtr));
4472 if (newNs == NULL) {
4473 xmlGenericError(xmlGenericErrorContext,
4474 "xmlReconciliateNs : memory pbm\n");
4475 xmlFree(oldNs);
4476 return(-1);
4477 }
4478 }
4479 newNs[nbCache] = n;
4480 oldNs[nbCache++] = node->ns;
4481 node->ns = n;
4482 }
4483 }
4484 }
4485 /*
4486 * now check for namespace hold by attributes on the node.
4487 */
4488 attr = node->properties;
4489 while (attr != NULL) {
4490 if (attr->ns != NULL) {
4491 /*
4492 * initialize the cache if needed
4493 */
4494 if (sizeCache == 0) {
4495 sizeCache = 10;
4496 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4497 sizeof(xmlNsPtr));
4498 if (oldNs == NULL) {
4499 xmlGenericError(xmlGenericErrorContext,
4500 "xmlReconciliateNs : memory pbm\n");
4501 return(-1);
4502 }
4503 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4504 sizeof(xmlNsPtr));
4505 if (newNs == NULL) {
4506 xmlGenericError(xmlGenericErrorContext,
4507 "xmlReconciliateNs : memory pbm\n");
4508 xmlFree(oldNs);
4509 return(-1);
4510 }
4511 }
4512 for (i = 0;i < nbCache;i++) {
4513 if (oldNs[i] == attr->ns) {
4514 node->ns = newNs[i];
4515 break;
4516 }
4517 }
4518 if (i == nbCache) {
4519 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004520 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004521 */
4522 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4523 if (n != NULL) { /* :-( what if else ??? */
4524 /*
4525 * check if we need to grow the cache buffers.
4526 */
4527 if (sizeCache <= nbCache) {
4528 sizeCache *= 2;
4529 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4530 sizeof(xmlNsPtr));
4531 if (oldNs == NULL) {
4532 xmlGenericError(xmlGenericErrorContext,
4533 "xmlReconciliateNs : memory pbm\n");
4534 xmlFree(newNs);
4535 return(-1);
4536 }
4537 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4538 sizeof(xmlNsPtr));
4539 if (newNs == NULL) {
4540 xmlGenericError(xmlGenericErrorContext,
4541 "xmlReconciliateNs : memory pbm\n");
4542 xmlFree(oldNs);
4543 return(-1);
4544 }
4545 }
4546 newNs[nbCache] = n;
4547 oldNs[nbCache++] = attr->ns;
4548 attr->ns = n;
4549 }
4550 }
4551 }
4552 attr = attr->next;
4553 }
4554
4555 /*
4556 * Browse the full subtree, deep first
4557 */
4558 if (node->children != NULL) {
4559 /* deep first */
4560 node = node->children;
4561 } else if ((node != tree) && (node->next != NULL)) {
4562 /* then siblings */
4563 node = node->next;
4564 } else if (node != tree) {
4565 /* go up to parents->next if needed */
4566 while (node != tree) {
4567 if (node->parent != NULL)
4568 node = node->parent;
4569 if ((node != tree) && (node->next != NULL)) {
4570 node = node->next;
4571 break;
4572 }
4573 if (node->parent == NULL) {
4574 node = NULL;
4575 break;
4576 }
4577 }
4578 /* exit condition */
4579 if (node == tree)
4580 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004581 } else
4582 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004583 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004584 if (oldNs != NULL)
4585 xmlFree(oldNs);
4586 if (newNs != NULL)
4587 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004588 return(ret);
4589}
4590
4591/**
4592 * xmlHasProp:
4593 * @node: the node
4594 * @name: the attribute name
4595 *
4596 * Search an attribute associated to a node
4597 * This function also looks in DTD attribute declaration for #FIXED or
4598 * default declaration values unless DTD use has been turned off.
4599 *
4600 * Returns the attribute or the attribute declaration or NULL if
4601 * neither was found.
4602 */
4603xmlAttrPtr
4604xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4605 xmlAttrPtr prop;
4606 xmlDocPtr doc;
4607
4608 if ((node == NULL) || (name == NULL)) return(NULL);
4609 /*
4610 * Check on the properties attached to the node
4611 */
4612 prop = node->properties;
4613 while (prop != NULL) {
4614 if (xmlStrEqual(prop->name, name)) {
4615 return(prop);
4616 }
4617 prop = prop->next;
4618 }
4619 if (!xmlCheckDTD) return(NULL);
4620
4621 /*
4622 * Check if there is a default declaration in the internal
4623 * or external subsets
4624 */
4625 doc = node->doc;
4626 if (doc != NULL) {
4627 xmlAttributePtr attrDecl;
4628 if (doc->intSubset != NULL) {
4629 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4630 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4631 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4632 if (attrDecl != NULL)
4633 return((xmlAttrPtr) attrDecl);
4634 }
4635 }
4636 return(NULL);
4637}
4638
4639/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004640 * xmlHasNsProp:
4641 * @node: the node
4642 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004643 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004644 *
4645 * Search for an attribute associated to a node
4646 * This attribute has to be anchored in the namespace specified.
4647 * This does the entity substitution.
4648 * This function looks in DTD attribute declaration for #FIXED or
4649 * default declaration values unless DTD use has been turned off.
4650 *
4651 * Returns the attribute or the attribute declaration or NULL
4652 * if neither was found.
4653 */
4654xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004655xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004656 xmlAttrPtr prop;
4657 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004658
4659 if (node == NULL)
4660 return(NULL);
4661
4662 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004663 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004664 return(xmlHasProp(node, name));
4665 while (prop != NULL) {
4666 /*
4667 * One need to have
4668 * - same attribute names
4669 * - and the attribute carrying that namespace
4670 * or
4671 * no namespace on the attribute and the element carrying it
4672 */
4673 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004674 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4675 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004676 }
4677 prop = prop->next;
4678 }
4679 if (!xmlCheckDTD) return(NULL);
4680
4681 /*
4682 * Check if there is a default declaration in the internal
4683 * or external subsets
4684 */
4685 doc = node->doc;
4686 if (doc != NULL) {
4687 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004688 xmlAttributePtr attrDecl = NULL;
4689 xmlNsPtr *nsList, *cur;
4690 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004691
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004692 nsList = xmlGetNsList(node->doc, node);
4693 if (nsList == NULL)
4694 return(NULL);
4695 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4696 ename = xmlStrdup(node->ns->prefix);
4697 ename = xmlStrcat(ename, BAD_CAST ":");
4698 ename = xmlStrcat(ename, node->name);
4699 } else {
4700 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004701 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004702 if (ename == NULL) {
4703 xmlFree(nsList);
4704 return(NULL);
4705 }
4706
4707 cur = nsList;
4708 while (*cur != NULL) {
4709 if (xmlStrEqual((*cur)->href, nameSpace)) {
4710 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4711 name, (*cur)->prefix);
4712 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4713 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4714 name, (*cur)->prefix);
4715 }
4716 cur++;
4717 }
4718 xmlFree(nsList);
4719 xmlFree(ename);
4720 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004721 }
4722 }
4723 return(NULL);
4724}
4725
4726/**
Owen Taylor3473f882001-02-23 17:55:21 +00004727 * xmlGetProp:
4728 * @node: the node
4729 * @name: the attribute name
4730 *
4731 * Search and get the value of an attribute associated to a node
4732 * This does the entity substitution.
4733 * This function looks in DTD attribute declaration for #FIXED or
4734 * default declaration values unless DTD use has been turned off.
4735 *
4736 * Returns the attribute value or NULL if not found.
4737 * It's up to the caller to free the memory.
4738 */
4739xmlChar *
4740xmlGetProp(xmlNodePtr node, const xmlChar *name) {
4741 xmlAttrPtr prop;
4742 xmlDocPtr doc;
4743
4744 if ((node == NULL) || (name == NULL)) return(NULL);
4745 /*
4746 * Check on the properties attached to the node
4747 */
4748 prop = node->properties;
4749 while (prop != NULL) {
4750 if (xmlStrEqual(prop->name, name)) {
4751 xmlChar *ret;
4752
4753 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4754 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4755 return(ret);
4756 }
4757 prop = prop->next;
4758 }
4759 if (!xmlCheckDTD) return(NULL);
4760
4761 /*
4762 * Check if there is a default declaration in the internal
4763 * or external subsets
4764 */
4765 doc = node->doc;
4766 if (doc != NULL) {
4767 xmlAttributePtr attrDecl;
4768 if (doc->intSubset != NULL) {
4769 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4770 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4771 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4772 if (attrDecl != NULL)
4773 return(xmlStrdup(attrDecl->defaultValue));
4774 }
4775 }
4776 return(NULL);
4777}
4778
4779/**
4780 * xmlGetNsProp:
4781 * @node: the node
4782 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004783 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004784 *
4785 * Search and get the value of an attribute associated to a node
4786 * This attribute has to be anchored in the namespace specified.
4787 * This does the entity substitution.
4788 * This function looks in DTD attribute declaration for #FIXED or
4789 * default declaration values unless DTD use has been turned off.
4790 *
4791 * Returns the attribute value or NULL if not found.
4792 * It's up to the caller to free the memory.
4793 */
4794xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00004795xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00004796 xmlAttrPtr prop;
4797 xmlDocPtr doc;
4798 xmlNsPtr ns;
4799
4800 if (node == NULL)
4801 return(NULL);
4802
4803 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004804 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00004805 return(xmlGetProp(node, name));
4806 while (prop != NULL) {
4807 /*
4808 * One need to have
4809 * - same attribute names
4810 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00004811 */
4812 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00004813 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00004814 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00004815 xmlChar *ret;
4816
4817 ret = xmlNodeListGetString(node->doc, prop->children, 1);
4818 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4819 return(ret);
4820 }
4821 prop = prop->next;
4822 }
4823 if (!xmlCheckDTD) return(NULL);
4824
4825 /*
4826 * Check if there is a default declaration in the internal
4827 * or external subsets
4828 */
4829 doc = node->doc;
4830 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004831 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00004832 xmlAttributePtr attrDecl;
4833
Owen Taylor3473f882001-02-23 17:55:21 +00004834 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4835 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4836 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4837
4838 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
4839 /*
4840 * The DTD declaration only allows a prefix search
4841 */
4842 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00004843 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00004844 return(xmlStrdup(attrDecl->defaultValue));
4845 }
4846 }
4847 }
4848 return(NULL);
4849}
4850
4851/**
4852 * xmlSetProp:
4853 * @node: the node
4854 * @name: the attribute name
4855 * @value: the attribute value
4856 *
4857 * Set (or reset) an attribute carried by a node.
4858 * Returns the attribute pointer.
4859 */
4860xmlAttrPtr
4861xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004862 xmlAttrPtr prop;
4863 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004864
4865 if ((node == NULL) || (name == NULL))
4866 return(NULL);
4867 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004868 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00004869 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00004870 if ((xmlStrEqual(prop->name, name)) &&
4871 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004872 xmlNodePtr oldprop = prop->children;
4873
Owen Taylor3473f882001-02-23 17:55:21 +00004874 prop->children = NULL;
4875 prop->last = NULL;
4876 if (value != NULL) {
4877 xmlChar *buffer;
4878 xmlNodePtr tmp;
4879
4880 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4881 prop->children = xmlStringGetNodeList(node->doc, buffer);
4882 prop->last = NULL;
4883 prop->doc = doc;
4884 tmp = prop->children;
4885 while (tmp != NULL) {
4886 tmp->parent = (xmlNodePtr) prop;
4887 tmp->doc = doc;
4888 if (tmp->next == NULL)
4889 prop->last = tmp;
4890 tmp = tmp->next;
4891 }
4892 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00004893 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00004894 if (oldprop != NULL)
4895 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00004896 return(prop);
4897 }
4898 prop = prop->next;
4899 }
4900 prop = xmlNewProp(node, name, value);
4901 return(prop);
4902}
4903
4904/**
Daniel Veillard75bea542001-05-11 17:41:21 +00004905 * xmlUnsetProp:
4906 * @node: the node
4907 * @name: the attribute name
4908 *
4909 * Remove an attribute carried by a node.
4910 * Returns 0 if successful, -1 if not found
4911 */
4912int
4913xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
4914 xmlAttrPtr prop = node->properties, prev = NULL;;
4915
4916 if ((node == NULL) || (name == NULL))
4917 return(-1);
4918 while (prop != NULL) {
4919 if ((xmlStrEqual(prop->name, name)) &&
4920 (prop->ns == NULL)) {
4921 if (prev == NULL)
4922 node->properties = prop->next;
4923 else
4924 prev->next = prop->next;
4925 xmlFreeProp(prop);
4926 return(0);
4927 }
4928 prev = prop;
4929 prop = prop->next;
4930 }
4931 return(-1);
4932}
4933
4934/**
Owen Taylor3473f882001-02-23 17:55:21 +00004935 * xmlSetNsProp:
4936 * @node: the node
4937 * @ns: the namespace definition
4938 * @name: the attribute name
4939 * @value: the attribute value
4940 *
4941 * Set (or reset) an attribute carried by a node.
4942 * The ns structure must be in scope, this is not checked.
4943 *
4944 * Returns the attribute pointer.
4945 */
4946xmlAttrPtr
4947xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4948 const xmlChar *value) {
4949 xmlAttrPtr prop;
4950
4951 if ((node == NULL) || (name == NULL))
4952 return(NULL);
4953
4954 if (ns == NULL)
4955 return(xmlSetProp(node, name, value));
4956 if (ns->href == NULL)
4957 return(NULL);
4958 prop = node->properties;
4959
4960 while (prop != NULL) {
4961 /*
4962 * One need to have
4963 * - same attribute names
4964 * - and the attribute carrying that namespace
4965 * or
4966 * no namespace on the attribute and the element carrying it
4967 */
4968 if ((xmlStrEqual(prop->name, name)) &&
4969 (((prop->ns == NULL) && (node->ns != NULL) &&
4970 (xmlStrEqual(node->ns->href, ns->href))) ||
4971 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4972 if (prop->children != NULL)
4973 xmlFreeNodeList(prop->children);
4974 prop->children = NULL;
4975 prop->last = NULL;
4976 prop->ns = ns;
4977 if (value != NULL) {
4978 xmlChar *buffer;
4979 xmlNodePtr tmp;
4980
4981 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4982 prop->children = xmlStringGetNodeList(node->doc, buffer);
4983 prop->last = NULL;
4984 tmp = prop->children;
4985 while (tmp != NULL) {
4986 tmp->parent = (xmlNodePtr) prop;
4987 if (tmp->next == NULL)
4988 prop->last = tmp;
4989 tmp = tmp->next;
4990 }
4991 xmlFree(buffer);
4992 }
4993 return(prop);
4994 }
4995 prop = prop->next;
4996 }
4997 prop = xmlNewNsProp(node, ns, name, value);
4998 return(prop);
4999}
5000
5001/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005002 * xmlUnsetNsProp:
5003 * @node: the node
5004 * @ns: the namespace definition
5005 * @name: the attribute name
5006 *
5007 * Remove an attribute carried by a node.
5008 * Returns 0 if successful, -1 if not found
5009 */
5010int
5011xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5012 xmlAttrPtr prop = node->properties, prev = NULL;;
5013
5014 if ((node == NULL) || (name == NULL))
5015 return(-1);
5016 if (ns == NULL)
5017 return(xmlUnsetProp(node, name));
5018 if (ns->href == NULL)
5019 return(-1);
5020 while (prop != NULL) {
5021 if ((xmlStrEqual(prop->name, name)) &&
5022 (((prop->ns == NULL) && (node->ns != NULL) &&
5023 (xmlStrEqual(node->ns->href, ns->href))) ||
5024 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
5025 if (prev == NULL)
5026 node->properties = prop->next;
5027 else
5028 prev->next = prop->next;
5029 xmlFreeProp(prop);
5030 return(0);
5031 }
5032 prev = prop;
5033 prop = prop->next;
5034 }
5035 return(-1);
5036}
5037
5038/**
Owen Taylor3473f882001-02-23 17:55:21 +00005039 * xmlNodeIsText:
5040 * @node: the node
5041 *
5042 * Is this node a Text node ?
5043 * Returns 1 yes, 0 no
5044 */
5045int
5046xmlNodeIsText(xmlNodePtr node) {
5047 if (node == NULL) return(0);
5048
5049 if (node->type == XML_TEXT_NODE) return(1);
5050 return(0);
5051}
5052
5053/**
5054 * xmlIsBlankNode:
5055 * @node: the node
5056 *
5057 * Checks whether this node is an empty or whitespace only
5058 * (and possibly ignorable) text-node.
5059 *
5060 * Returns 1 yes, 0 no
5061 */
5062int
5063xmlIsBlankNode(xmlNodePtr node) {
5064 const xmlChar *cur;
5065 if (node == NULL) return(0);
5066
Daniel Veillard7db37732001-07-12 01:20:08 +00005067 if ((node->type != XML_TEXT_NODE) &&
5068 (node->type != XML_CDATA_SECTION_NODE))
5069 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005070 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005071 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005072 while (*cur != 0) {
5073 if (!IS_BLANK(*cur)) return(0);
5074 cur++;
5075 }
5076
5077 return(1);
5078}
5079
5080/**
5081 * xmlTextConcat:
5082 * @node: the node
5083 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005084 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005085 *
5086 * Concat the given string at the end of the existing node content
5087 */
5088
5089void
5090xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5091 if (node == NULL) return;
5092
5093 if ((node->type != XML_TEXT_NODE) &&
5094 (node->type != XML_CDATA_SECTION_NODE)) {
5095#ifdef DEBUG_TREE
5096 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005097 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005098#endif
5099 return;
5100 }
Owen Taylor3473f882001-02-23 17:55:21 +00005101 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005102}
5103
5104/************************************************************************
5105 * *
5106 * Output : to a FILE or in memory *
5107 * *
5108 ************************************************************************/
5109
Owen Taylor3473f882001-02-23 17:55:21 +00005110/**
5111 * xmlBufferCreate:
5112 *
5113 * routine to create an XML buffer.
5114 * returns the new structure.
5115 */
5116xmlBufferPtr
5117xmlBufferCreate(void) {
5118 xmlBufferPtr ret;
5119
5120 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5121 if (ret == NULL) {
5122 xmlGenericError(xmlGenericErrorContext,
5123 "xmlBufferCreate : out of memory!\n");
5124 return(NULL);
5125 }
5126 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005127 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005128 ret->alloc = xmlBufferAllocScheme;
5129 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5130 if (ret->content == NULL) {
5131 xmlGenericError(xmlGenericErrorContext,
5132 "xmlBufferCreate : out of memory!\n");
5133 xmlFree(ret);
5134 return(NULL);
5135 }
5136 ret->content[0] = 0;
5137 return(ret);
5138}
5139
5140/**
5141 * xmlBufferCreateSize:
5142 * @size: initial size of buffer
5143 *
5144 * routine to create an XML buffer.
5145 * returns the new structure.
5146 */
5147xmlBufferPtr
5148xmlBufferCreateSize(size_t size) {
5149 xmlBufferPtr ret;
5150
5151 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5152 if (ret == NULL) {
5153 xmlGenericError(xmlGenericErrorContext,
5154 "xmlBufferCreate : out of memory!\n");
5155 return(NULL);
5156 }
5157 ret->use = 0;
5158 ret->alloc = xmlBufferAllocScheme;
5159 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5160 if (ret->size){
5161 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5162 if (ret->content == NULL) {
5163 xmlGenericError(xmlGenericErrorContext,
5164 "xmlBufferCreate : out of memory!\n");
5165 xmlFree(ret);
5166 return(NULL);
5167 }
5168 ret->content[0] = 0;
5169 } else
5170 ret->content = NULL;
5171 return(ret);
5172}
5173
5174/**
5175 * xmlBufferSetAllocationScheme:
5176 * @buf: the buffer to free
5177 * @scheme: allocation scheme to use
5178 *
5179 * Sets the allocation scheme for this buffer
5180 */
5181void
5182xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5183 xmlBufferAllocationScheme scheme) {
5184 if (buf == NULL) {
5185#ifdef DEBUG_BUFFER
5186 xmlGenericError(xmlGenericErrorContext,
5187 "xmlBufferSetAllocationScheme: buf == NULL\n");
5188#endif
5189 return;
5190 }
5191
5192 buf->alloc = scheme;
5193}
5194
5195/**
5196 * xmlBufferFree:
5197 * @buf: the buffer to free
5198 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005199 * Frees an XML buffer. It frees both the content and the structure which
5200 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005201 */
5202void
5203xmlBufferFree(xmlBufferPtr buf) {
5204 if (buf == NULL) {
5205#ifdef DEBUG_BUFFER
5206 xmlGenericError(xmlGenericErrorContext,
5207 "xmlBufferFree: buf == NULL\n");
5208#endif
5209 return;
5210 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005211 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005212 xmlFree(buf->content);
5213 }
Owen Taylor3473f882001-02-23 17:55:21 +00005214 xmlFree(buf);
5215}
5216
5217/**
5218 * xmlBufferEmpty:
5219 * @buf: the buffer
5220 *
5221 * empty a buffer.
5222 */
5223void
5224xmlBufferEmpty(xmlBufferPtr buf) {
5225 if (buf->content == NULL) return;
5226 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005227 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005228}
5229
5230/**
5231 * xmlBufferShrink:
5232 * @buf: the buffer to dump
5233 * @len: the number of xmlChar to remove
5234 *
5235 * Remove the beginning of an XML buffer.
5236 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005237 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005238 */
5239int
5240xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5241 if (len == 0) return(0);
5242 if (len > buf->use) return(-1);
5243
5244 buf->use -= len;
5245 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5246
5247 buf->content[buf->use] = 0;
5248 return(len);
5249}
5250
5251/**
5252 * xmlBufferGrow:
5253 * @buf: the buffer
5254 * @len: the minimum free size to allocate
5255 *
5256 * Grow the available space of an XML buffer.
5257 *
5258 * Returns the new available space or -1 in case of error
5259 */
5260int
5261xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5262 int size;
5263 xmlChar *newbuf;
5264
5265 if (len + buf->use < buf->size) return(0);
5266
5267 size = buf->use + len + 100;
5268
5269 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5270 if (newbuf == NULL) return(-1);
5271 buf->content = newbuf;
5272 buf->size = size;
5273 return(buf->size - buf->use);
5274}
5275
5276/**
5277 * xmlBufferDump:
5278 * @file: the file output
5279 * @buf: the buffer to dump
5280 *
5281 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005282 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005283 */
5284int
5285xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5286 int ret;
5287
5288 if (buf == NULL) {
5289#ifdef DEBUG_BUFFER
5290 xmlGenericError(xmlGenericErrorContext,
5291 "xmlBufferDump: buf == NULL\n");
5292#endif
5293 return(0);
5294 }
5295 if (buf->content == NULL) {
5296#ifdef DEBUG_BUFFER
5297 xmlGenericError(xmlGenericErrorContext,
5298 "xmlBufferDump: buf->content == NULL\n");
5299#endif
5300 return(0);
5301 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005302 if (file == NULL)
5303 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005304 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5305 return(ret);
5306}
5307
5308/**
5309 * xmlBufferContent:
5310 * @buf: the buffer
5311 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005312 * Function to extract the content of a buffer
5313 *
Owen Taylor3473f882001-02-23 17:55:21 +00005314 * Returns the internal content
5315 */
5316
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005317const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005318xmlBufferContent(const xmlBufferPtr buf)
5319{
5320 if(!buf)
5321 return NULL;
5322
5323 return buf->content;
5324}
5325
5326/**
5327 * xmlBufferLength:
5328 * @buf: the buffer
5329 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005330 * Function to get the length of a buffer
5331 *
Owen Taylor3473f882001-02-23 17:55:21 +00005332 * Returns the length of data in the internal content
5333 */
5334
5335int
5336xmlBufferLength(const xmlBufferPtr buf)
5337{
5338 if(!buf)
5339 return 0;
5340
5341 return buf->use;
5342}
5343
5344/**
5345 * xmlBufferResize:
5346 * @buf: the buffer to resize
5347 * @size: the desired size
5348 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005349 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005350 *
5351 * Returns 0 in case of problems, 1 otherwise
5352 */
5353int
5354xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5355{
5356 unsigned int newSize;
5357 xmlChar* rebuf = NULL;
5358
5359 /*take care of empty case*/
5360 newSize = (buf->size ? buf->size*2 : size);
5361
5362 /* Don't resize if we don't have to */
5363 if (size < buf->size)
5364 return 1;
5365
5366 /* figure out new size */
5367 switch (buf->alloc){
5368 case XML_BUFFER_ALLOC_DOUBLEIT:
5369 while (size > newSize) newSize *= 2;
5370 break;
5371 case XML_BUFFER_ALLOC_EXACT:
5372 newSize = size+10;
5373 break;
5374 default:
5375 newSize = size+10;
5376 break;
5377 }
5378
5379 if (buf->content == NULL)
5380 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5381 else
5382 rebuf = (xmlChar *) xmlRealloc(buf->content,
5383 newSize * sizeof(xmlChar));
5384 if (rebuf == NULL) {
5385 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005386 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005387 return 0;
5388 }
5389 buf->content = rebuf;
5390 buf->size = newSize;
5391
5392 return 1;
5393}
5394
5395/**
5396 * xmlBufferAdd:
5397 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005398 * @str: the #xmlChar string
5399 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005400 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005401 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005402 * str is recomputed.
5403 */
5404void
5405xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5406 unsigned int needSize;
5407
5408 if (str == NULL) {
5409#ifdef DEBUG_BUFFER
5410 xmlGenericError(xmlGenericErrorContext,
5411 "xmlBufferAdd: str == NULL\n");
5412#endif
5413 return;
5414 }
5415 if (len < -1) {
5416#ifdef DEBUG_BUFFER
5417 xmlGenericError(xmlGenericErrorContext,
5418 "xmlBufferAdd: len < 0\n");
5419#endif
5420 return;
5421 }
5422 if (len == 0) return;
5423
5424 if (len < 0)
5425 len = xmlStrlen(str);
5426
5427 if (len <= 0) return;
5428
5429 needSize = buf->use + len + 2;
5430 if (needSize > buf->size){
5431 if (!xmlBufferResize(buf, needSize)){
5432 xmlGenericError(xmlGenericErrorContext,
5433 "xmlBufferAdd : out of memory!\n");
5434 return;
5435 }
5436 }
5437
5438 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5439 buf->use += len;
5440 buf->content[buf->use] = 0;
5441}
5442
5443/**
5444 * xmlBufferAddHead:
5445 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005446 * @str: the #xmlChar string
5447 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005448 *
5449 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005450 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005451 */
5452void
5453xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5454 unsigned int needSize;
5455
5456 if (str == NULL) {
5457#ifdef DEBUG_BUFFER
5458 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005459 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005460#endif
5461 return;
5462 }
5463 if (len < -1) {
5464#ifdef DEBUG_BUFFER
5465 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005466 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005467#endif
5468 return;
5469 }
5470 if (len == 0) return;
5471
5472 if (len < 0)
5473 len = xmlStrlen(str);
5474
5475 if (len <= 0) return;
5476
5477 needSize = buf->use + len + 2;
5478 if (needSize > buf->size){
5479 if (!xmlBufferResize(buf, needSize)){
5480 xmlGenericError(xmlGenericErrorContext,
5481 "xmlBufferAddHead : out of memory!\n");
5482 return;
5483 }
5484 }
5485
5486 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5487 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5488 buf->use += len;
5489 buf->content[buf->use] = 0;
5490}
5491
5492/**
5493 * xmlBufferCat:
5494 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005495 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005496 *
5497 * Append a zero terminated string to an XML buffer.
5498 */
5499void
5500xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5501 if (str != NULL)
5502 xmlBufferAdd(buf, str, -1);
5503}
5504
5505/**
5506 * xmlBufferCCat:
5507 * @buf: the buffer to dump
5508 * @str: the C char string
5509 *
5510 * Append a zero terminated C string to an XML buffer.
5511 */
5512void
5513xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5514 const char *cur;
5515
5516 if (str == NULL) {
5517#ifdef DEBUG_BUFFER
5518 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005519 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005520#endif
5521 return;
5522 }
5523 for (cur = str;*cur != 0;cur++) {
5524 if (buf->use + 10 >= buf->size) {
5525 if (!xmlBufferResize(buf, buf->use+10)){
5526 xmlGenericError(xmlGenericErrorContext,
5527 "xmlBufferCCat : out of memory!\n");
5528 return;
5529 }
5530 }
5531 buf->content[buf->use++] = *cur;
5532 }
5533 buf->content[buf->use] = 0;
5534}
5535
5536/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005537 * xmlBufferWriteXmlCHAR:
5538 * @buf: the XML buffer
5539 * @string: the string to add
5540 *
5541 * For VMS only.
5542 * routine which manages and grows an output buffer. This one adds
5543 * xmlChars at the end of the buffer.
5544 */
5545/**
Owen Taylor3473f882001-02-23 17:55:21 +00005546 * xmlBufferWriteCHAR:
5547 * @buf: the XML buffer
5548 * @string: the string to add
5549 *
5550 * routine which manages and grows an output buffer. This one adds
5551 * xmlChars at the end of the buffer.
5552 */
5553void
5554#ifdef VMS
5555xmlBufferWriteXmlCHAR
5556#else
5557xmlBufferWriteCHAR
5558#endif
5559(xmlBufferPtr buf, const xmlChar *string) {
5560 xmlBufferCat(buf, string);
5561}
5562
5563/**
5564 * xmlBufferWriteChar:
5565 * @buf: the XML buffer output
5566 * @string: the string to add
5567 *
5568 * routine which manage and grows an output buffer. This one add
5569 * C chars at the end of the array.
5570 */
5571void
5572xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5573 xmlBufferCCat(buf, string);
5574}
5575
5576
5577/**
5578 * xmlBufferWriteQuotedString:
5579 * @buf: the XML buffer output
5580 * @string: the string to add
5581 *
5582 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005583 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005584 * quote or double-quotes internally
5585 */
5586void
5587xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5588 if (xmlStrchr(string, '"')) {
5589 if (xmlStrchr(string, '\'')) {
5590#ifdef DEBUG_BUFFER
5591 xmlGenericError(xmlGenericErrorContext,
5592 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5593#endif
5594 }
5595 xmlBufferCCat(buf, "'");
5596 xmlBufferCat(buf, string);
5597 xmlBufferCCat(buf, "'");
5598 } else {
5599 xmlBufferCCat(buf, "\"");
5600 xmlBufferCat(buf, string);
5601 xmlBufferCCat(buf, "\"");
5602 }
5603}
5604
5605
5606/************************************************************************
5607 * *
5608 * Dumping XML tree content to a simple buffer *
5609 * *
5610 ************************************************************************/
5611
Owen Taylor3473f882001-02-23 17:55:21 +00005612static void
5613xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5614 int format);
5615void
5616htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5617
5618/**
5619 * xmlNsDump:
5620 * @buf: the XML buffer output
5621 * @cur: a namespace
5622 *
5623 * Dump a local Namespace definition.
5624 * Should be called in the context of attributes dumps.
5625 */
5626static void
5627xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5628 if (cur == NULL) {
5629#ifdef DEBUG_TREE
5630 xmlGenericError(xmlGenericErrorContext,
5631 "xmlNsDump : Ns == NULL\n");
5632#endif
5633 return;
5634 }
5635 if (cur->type == XML_LOCAL_NAMESPACE) {
5636 /* Within the context of an element attributes */
5637 if (cur->prefix != NULL) {
5638 xmlBufferWriteChar(buf, " xmlns:");
5639 xmlBufferWriteCHAR(buf, cur->prefix);
5640 } else
5641 xmlBufferWriteChar(buf, " xmlns");
5642 xmlBufferWriteChar(buf, "=");
5643 xmlBufferWriteQuotedString(buf, cur->href);
5644 }
5645}
5646
5647/**
5648 * xmlNsListDump:
5649 * @buf: the XML buffer output
5650 * @cur: the first namespace
5651 *
5652 * Dump a list of local Namespace definitions.
5653 * Should be called in the context of attributes dumps.
5654 */
5655static void
5656xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5657 while (cur != NULL) {
5658 xmlNsDump(buf, cur);
5659 cur = cur->next;
5660 }
5661}
5662
5663/**
5664 * xmlDtdDump:
5665 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005666 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005667 *
5668 * Dump the XML document DTD, if any.
5669 */
5670static void
5671xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5672 if (dtd == NULL) {
5673#ifdef DEBUG_TREE
5674 xmlGenericError(xmlGenericErrorContext,
5675 "xmlDtdDump : no internal subset\n");
5676#endif
5677 return;
5678 }
5679 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5680 xmlBufferWriteCHAR(buf, dtd->name);
5681 if (dtd->ExternalID != NULL) {
5682 xmlBufferWriteChar(buf, " PUBLIC ");
5683 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5684 xmlBufferWriteChar(buf, " ");
5685 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5686 } else if (dtd->SystemID != NULL) {
5687 xmlBufferWriteChar(buf, " SYSTEM ");
5688 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5689 }
5690 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5691 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5692 xmlBufferWriteChar(buf, ">");
5693 return;
5694 }
5695 xmlBufferWriteChar(buf, " [\n");
5696 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5697#if 0
5698 if (dtd->entities != NULL)
5699 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5700 if (dtd->notations != NULL)
5701 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5702 if (dtd->elements != NULL)
5703 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5704 if (dtd->attributes != NULL)
5705 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5706#endif
5707 xmlBufferWriteChar(buf, "]>");
5708}
5709
5710/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005711 * xmlAttrSerializeContent:
5712 * @buf: the XML buffer output
5713 * @doc: the document
5714 * @attr: the attribute pointer
5715 *
5716 * Serialize the attribute in the buffer
5717 */
5718static void
5719xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5720 const xmlChar *cur, *base;
5721 xmlNodePtr children;
5722
5723 children = attr->children;
5724 while (children != NULL) {
5725 switch (children->type) {
5726 case XML_TEXT_NODE:
5727 base = cur = children->content;
5728 while (*cur != 0) {
5729 if (*cur == '\n') {
5730 if (base != cur)
5731 xmlBufferAdd(buf, base, cur - base);
5732 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5733 cur++;
5734 base = cur;
5735#if 0
5736 } else if (*cur == '\'') {
5737 if (base != cur)
5738 xmlBufferAdd(buf, base, cur - base);
5739 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5740 cur++;
5741 base = cur;
5742#endif
5743 } else if (*cur == '"') {
5744 if (base != cur)
5745 xmlBufferAdd(buf, base, cur - base);
5746 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
5747 cur++;
5748 base = cur;
5749 } else if (*cur == '<') {
5750 if (base != cur)
5751 xmlBufferAdd(buf, base, cur - base);
5752 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
5753 cur++;
5754 base = cur;
5755 } else if (*cur == '>') {
5756 if (base != cur)
5757 xmlBufferAdd(buf, base, cur - base);
5758 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
5759 cur++;
5760 base = cur;
5761 } else if (*cur == '&') {
5762 if (base != cur)
5763 xmlBufferAdd(buf, base, cur - base);
5764 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
5765 cur++;
5766 base = cur;
5767 } else if ((*cur >= 0x80) && ((doc == NULL) ||
5768 (doc->encoding == NULL))) {
5769 /*
5770 * We assume we have UTF-8 content.
5771 */
5772 char tmp[10];
5773 int val = 0, l = 1;
5774
5775 if (base != cur)
5776 xmlBufferAdd(buf, base, cur - base);
5777 if (*cur < 0xC0) {
5778 xmlGenericError(xmlGenericErrorContext,
5779 "xmlAttrSerializeContent : input not UTF-8\n");
5780 if (doc != NULL)
5781 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5782 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5783 tmp[sizeof(tmp) - 1] = 0;
5784 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5785 cur++;
5786 base = cur;
5787 continue;
5788 } else if (*cur < 0xE0) {
5789 val = (cur[0]) & 0x1F;
5790 val <<= 6;
5791 val |= (cur[1]) & 0x3F;
5792 l = 2;
5793 } else if (*cur < 0xF0) {
5794 val = (cur[0]) & 0x0F;
5795 val <<= 6;
5796 val |= (cur[1]) & 0x3F;
5797 val <<= 6;
5798 val |= (cur[2]) & 0x3F;
5799 l = 3;
5800 } else if (*cur < 0xF8) {
5801 val = (cur[0]) & 0x07;
5802 val <<= 6;
5803 val |= (cur[1]) & 0x3F;
5804 val <<= 6;
5805 val |= (cur[2]) & 0x3F;
5806 val <<= 6;
5807 val |= (cur[3]) & 0x3F;
5808 l = 4;
5809 }
5810 if ((l == 1) || (!IS_CHAR(val))) {
5811 xmlGenericError(xmlGenericErrorContext,
5812 "xmlAttrSerializeContent : char out of range\n");
5813 if (doc != NULL)
5814 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
5815 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
5816 tmp[sizeof(tmp) - 1] = 0;
5817 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5818 cur++;
5819 base = cur;
5820 continue;
5821 }
5822 /*
5823 * We could do multiple things here. Just save
5824 * as a char ref
5825 */
5826 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
5827 tmp[sizeof(tmp) - 1] = 0;
5828 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
5829 cur += l;
5830 base = cur;
5831 } else {
5832 cur++;
5833 }
5834 }
5835 if (base != cur)
5836 xmlBufferAdd(buf, base, cur - base);
5837 break;
5838 case XML_ENTITY_REF_NODE:
5839 xmlBufferAdd(buf, BAD_CAST "&", 1);
5840 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
5841 xmlBufferAdd(buf, BAD_CAST ";", 1);
5842 break;
5843 default:
5844 /* should not happen unless we have a badly built tree */
5845 break;
5846 }
5847 children = children->next;
5848 }
5849}
5850
5851/**
Owen Taylor3473f882001-02-23 17:55:21 +00005852 * xmlAttrDump:
5853 * @buf: the XML buffer output
5854 * @doc: the document
5855 * @cur: the attribute pointer
5856 *
5857 * Dump an XML attribute
5858 */
5859static void
5860xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00005861 if (cur == NULL) {
5862#ifdef DEBUG_TREE
5863 xmlGenericError(xmlGenericErrorContext,
5864 "xmlAttrDump : property == NULL\n");
5865#endif
5866 return;
5867 }
5868 xmlBufferWriteChar(buf, " ");
5869 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5870 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5871 xmlBufferWriteChar(buf, ":");
5872 }
5873 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00005874 xmlBufferWriteChar(buf, "=\"");
5875 xmlAttrSerializeContent(buf, doc, cur);
5876 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00005877}
5878
5879/**
5880 * xmlAttrListDump:
5881 * @buf: the XML buffer output
5882 * @doc: the document
5883 * @cur: the first attribute pointer
5884 *
5885 * Dump a list of XML attributes
5886 */
5887static void
5888xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
5889 if (cur == NULL) {
5890#ifdef DEBUG_TREE
5891 xmlGenericError(xmlGenericErrorContext,
5892 "xmlAttrListDump : property == NULL\n");
5893#endif
5894 return;
5895 }
5896 while (cur != NULL) {
5897 xmlAttrDump(buf, doc, cur);
5898 cur = cur->next;
5899 }
5900}
5901
5902
5903
5904/**
5905 * xmlNodeListDump:
5906 * @buf: the XML buffer output
5907 * @doc: the document
5908 * @cur: the first node
5909 * @level: the imbrication level for indenting
5910 * @format: is formatting allowed
5911 *
5912 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005913 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
5914 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00005915 */
5916static void
5917xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5918 int format) {
5919 int i;
5920
5921 if (cur == NULL) {
5922#ifdef DEBUG_TREE
5923 xmlGenericError(xmlGenericErrorContext,
5924 "xmlNodeListDump : node == NULL\n");
5925#endif
5926 return;
5927 }
5928 while (cur != NULL) {
5929 if ((format) && (xmlIndentTreeOutput) &&
5930 (cur->type == XML_ELEMENT_NODE))
5931 for (i = 0;i < level;i++)
5932 xmlBufferWriteChar(buf, " ");
5933 xmlNodeDump(buf, doc, cur, level, format);
5934 if (format) {
5935 xmlBufferWriteChar(buf, "\n");
5936 }
5937 cur = cur->next;
5938 }
5939}
5940
5941/**
5942 * xmlNodeDump:
5943 * @buf: the XML buffer output
5944 * @doc: the document
5945 * @cur: the current node
5946 * @level: the imbrication level for indenting
5947 * @format: is formatting allowed
5948 *
5949 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005950 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
5951 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00005952 */
5953void
5954xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5955 int format) {
5956 int i;
5957 xmlNodePtr tmp;
5958
5959 if (cur == NULL) {
5960#ifdef DEBUG_TREE
5961 xmlGenericError(xmlGenericErrorContext,
5962 "xmlNodeDump : node == NULL\n");
5963#endif
5964 return;
5965 }
5966 if (cur->type == XML_XINCLUDE_START)
5967 return;
5968 if (cur->type == XML_XINCLUDE_END)
5969 return;
5970 if (cur->type == XML_DTD_NODE) {
5971 xmlDtdDump(buf, (xmlDtdPtr) cur);
5972 return;
5973 }
5974 if (cur->type == XML_ELEMENT_DECL) {
5975 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5976 return;
5977 }
Daniel Veillard78d12092001-10-11 09:12:24 +00005978 if (cur->type == XML_ATTRIBUTE_NODE){
5979 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
5980 return;
5981 }
Owen Taylor3473f882001-02-23 17:55:21 +00005982 if (cur->type == XML_ATTRIBUTE_DECL) {
5983 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5984 return;
5985 }
5986 if (cur->type == XML_ENTITY_DECL) {
5987 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5988 return;
5989 }
5990 if (cur->type == XML_TEXT_NODE) {
5991 if (cur->content != NULL) {
5992 if ((cur->name == xmlStringText) ||
5993 (cur->name != xmlStringTextNoenc)) {
5994 xmlChar *buffer;
5995
Owen Taylor3473f882001-02-23 17:55:21 +00005996 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005997 if (buffer != NULL) {
5998 xmlBufferWriteCHAR(buf, buffer);
5999 xmlFree(buffer);
6000 }
6001 } else {
6002 /*
6003 * Disable escaping, needed for XSLT
6004 */
Owen Taylor3473f882001-02-23 17:55:21 +00006005 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006006 }
6007 }
6008 return;
6009 }
6010 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006011 xmlBufferWriteChar(buf, "<?");
6012 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006013 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006014 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006015 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006016 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006017 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006018 return;
6019 }
6020 if (cur->type == XML_COMMENT_NODE) {
6021 if (cur->content != NULL) {
6022 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006023 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006024 xmlBufferWriteChar(buf, "-->");
6025 }
6026 return;
6027 }
6028 if (cur->type == XML_ENTITY_REF_NODE) {
6029 xmlBufferWriteChar(buf, "&");
6030 xmlBufferWriteCHAR(buf, cur->name);
6031 xmlBufferWriteChar(buf, ";");
6032 return;
6033 }
6034 if (cur->type == XML_CDATA_SECTION_NODE) {
6035 xmlBufferWriteChar(buf, "<![CDATA[");
6036 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006037 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006038 xmlBufferWriteChar(buf, "]]>");
6039 return;
6040 }
6041
6042 if (format == 1) {
6043 tmp = cur->children;
6044 while (tmp != NULL) {
6045 if ((tmp->type == XML_TEXT_NODE) ||
6046 (tmp->type == XML_ENTITY_REF_NODE)) {
6047 format = 0;
6048 break;
6049 }
6050 tmp = tmp->next;
6051 }
6052 }
6053 xmlBufferWriteChar(buf, "<");
6054 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6055 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6056 xmlBufferWriteChar(buf, ":");
6057 }
6058
6059 xmlBufferWriteCHAR(buf, cur->name);
6060 if (cur->nsDef)
6061 xmlNsListDump(buf, cur->nsDef);
6062 if (cur->properties != NULL)
6063 xmlAttrListDump(buf, doc, cur->properties);
6064
Daniel Veillard7db37732001-07-12 01:20:08 +00006065 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6066 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006067 (!xmlSaveNoEmptyTags)) {
6068 xmlBufferWriteChar(buf, "/>");
6069 return;
6070 }
6071 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006072 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006073 xmlChar *buffer;
6074
Owen Taylor3473f882001-02-23 17:55:21 +00006075 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006076 if (buffer != NULL) {
6077 xmlBufferWriteCHAR(buf, buffer);
6078 xmlFree(buffer);
6079 }
6080 }
6081 if (cur->children != NULL) {
6082 if (format) xmlBufferWriteChar(buf, "\n");
6083 xmlNodeListDump(buf, doc, cur->children,
6084 (level >= 0?level+1:-1), format);
6085 if ((xmlIndentTreeOutput) && (format))
6086 for (i = 0;i < level;i++)
6087 xmlBufferWriteChar(buf, " ");
6088 }
6089 xmlBufferWriteChar(buf, "</");
6090 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6091 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6092 xmlBufferWriteChar(buf, ":");
6093 }
6094
6095 xmlBufferWriteCHAR(buf, cur->name);
6096 xmlBufferWriteChar(buf, ">");
6097}
6098
6099/**
6100 * xmlElemDump:
6101 * @f: the FILE * for the output
6102 * @doc: the document
6103 * @cur: the current node
6104 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006105 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006106 */
6107void
6108xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6109 xmlBufferPtr buf;
6110
6111 if (cur == NULL) {
6112#ifdef DEBUG_TREE
6113 xmlGenericError(xmlGenericErrorContext,
6114 "xmlElemDump : cur == NULL\n");
6115#endif
6116 return;
6117 }
Owen Taylor3473f882001-02-23 17:55:21 +00006118#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006119 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006120 xmlGenericError(xmlGenericErrorContext,
6121 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006122 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006123#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006124
Owen Taylor3473f882001-02-23 17:55:21 +00006125 buf = xmlBufferCreate();
6126 if (buf == NULL) return;
6127 if ((doc != NULL) &&
6128 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6129#ifdef LIBXML_HTML_ENABLED
6130 htmlNodeDump(buf, doc, cur);
6131#else
6132 xmlGenericError(xmlGenericErrorContext,
6133 "HTML support not compiled in\n");
6134#endif /* LIBXML_HTML_ENABLED */
6135 } else
6136 xmlNodeDump(buf, doc, cur, 0, 1);
6137 xmlBufferDump(f, buf);
6138 xmlBufferFree(buf);
6139}
6140
6141/************************************************************************
6142 * *
6143 * Dumping XML tree content to an I/O output buffer *
6144 * *
6145 ************************************************************************/
6146
Owen Taylor3473f882001-02-23 17:55:21 +00006147static void
6148xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6149 int level, int format, const char *encoding);
6150/**
6151 * xmlNsDumpOutput:
6152 * @buf: the XML buffer output
6153 * @cur: a namespace
6154 *
6155 * Dump a local Namespace definition.
6156 * Should be called in the context of attributes dumps.
6157 */
6158static void
6159xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6160 if (cur == NULL) {
6161#ifdef DEBUG_TREE
6162 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006163 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006164#endif
6165 return;
6166 }
6167 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
6168 /* Within the context of an element attributes */
6169 if (cur->prefix != NULL) {
6170 xmlOutputBufferWriteString(buf, " xmlns:");
6171 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6172 } else
6173 xmlOutputBufferWriteString(buf, " xmlns");
6174 xmlOutputBufferWriteString(buf, "=");
6175 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6176 }
6177}
6178
6179/**
6180 * xmlNsListDumpOutput:
6181 * @buf: the XML buffer output
6182 * @cur: the first namespace
6183 *
6184 * Dump a list of local Namespace definitions.
6185 * Should be called in the context of attributes dumps.
6186 */
6187static void
6188xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6189 while (cur != NULL) {
6190 xmlNsDumpOutput(buf, cur);
6191 cur = cur->next;
6192 }
6193}
6194
6195/**
6196 * xmlDtdDumpOutput:
6197 * @buf: the XML buffer output
6198 * @doc: the document
6199 * @encoding: an optional encoding string
6200 *
6201 * Dump the XML document DTD, if any.
6202 */
6203static void
6204xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6205 if (dtd == NULL) {
6206#ifdef DEBUG_TREE
6207 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006208 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006209#endif
6210 return;
6211 }
6212 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6213 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6214 if (dtd->ExternalID != NULL) {
6215 xmlOutputBufferWriteString(buf, " PUBLIC ");
6216 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6217 xmlOutputBufferWriteString(buf, " ");
6218 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6219 } else if (dtd->SystemID != NULL) {
6220 xmlOutputBufferWriteString(buf, " SYSTEM ");
6221 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6222 }
6223 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6224 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6225 xmlOutputBufferWriteString(buf, ">");
6226 return;
6227 }
6228 xmlOutputBufferWriteString(buf, " [\n");
6229 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6230 xmlOutputBufferWriteString(buf, "]>");
6231}
6232
6233/**
6234 * xmlAttrDumpOutput:
6235 * @buf: the XML buffer output
6236 * @doc: the document
6237 * @cur: the attribute pointer
6238 * @encoding: an optional encoding string
6239 *
6240 * Dump an XML attribute
6241 */
6242static void
6243xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006244 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006245 if (cur == NULL) {
6246#ifdef DEBUG_TREE
6247 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006248 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006249#endif
6250 return;
6251 }
6252 xmlOutputBufferWriteString(buf, " ");
6253 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6254 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6255 xmlOutputBufferWriteString(buf, ":");
6256 }
6257 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006258 xmlOutputBufferWriteString(buf, "=\"");
6259 xmlAttrSerializeContent(buf->buffer, doc, cur);
6260 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006261}
6262
6263/**
6264 * xmlAttrListDumpOutput:
6265 * @buf: the XML buffer output
6266 * @doc: the document
6267 * @cur: the first attribute pointer
6268 * @encoding: an optional encoding string
6269 *
6270 * Dump a list of XML attributes
6271 */
6272static void
6273xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6274 xmlAttrPtr cur, const char *encoding) {
6275 if (cur == NULL) {
6276#ifdef DEBUG_TREE
6277 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006278 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006279#endif
6280 return;
6281 }
6282 while (cur != NULL) {
6283 xmlAttrDumpOutput(buf, doc, cur, encoding);
6284 cur = cur->next;
6285 }
6286}
6287
6288
6289
6290/**
6291 * xmlNodeListDumpOutput:
6292 * @buf: the XML buffer output
6293 * @doc: the document
6294 * @cur: the first node
6295 * @level: the imbrication level for indenting
6296 * @format: is formatting allowed
6297 * @encoding: an optional encoding string
6298 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006299 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006300 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6301 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006302 */
6303static void
6304xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6305 xmlNodePtr cur, int level, int format, const char *encoding) {
6306 int i;
6307
6308 if (cur == NULL) {
6309#ifdef DEBUG_TREE
6310 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006311 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006312#endif
6313 return;
6314 }
6315 while (cur != NULL) {
6316 if ((format) && (xmlIndentTreeOutput) &&
6317 (cur->type == XML_ELEMENT_NODE))
6318 for (i = 0;i < level;i++)
6319 xmlOutputBufferWriteString(buf, " ");
6320 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6321 if (format) {
6322 xmlOutputBufferWriteString(buf, "\n");
6323 }
6324 cur = cur->next;
6325 }
6326}
6327
6328/**
6329 * xmlNodeDumpOutput:
6330 * @buf: the XML buffer output
6331 * @doc: the document
6332 * @cur: the current node
6333 * @level: the imbrication level for indenting
6334 * @format: is formatting allowed
6335 * @encoding: an optional encoding string
6336 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006337 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006338 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6339 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006340 */
6341void
6342xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6343 int level, int format, const char *encoding) {
6344 int i;
6345 xmlNodePtr tmp;
6346
6347 if (cur == NULL) {
6348#ifdef DEBUG_TREE
6349 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006350 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006351#endif
6352 return;
6353 }
6354 if (cur->type == XML_XINCLUDE_START)
6355 return;
6356 if (cur->type == XML_XINCLUDE_END)
6357 return;
6358 if (cur->type == XML_DTD_NODE) {
6359 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6360 return;
6361 }
6362 if (cur->type == XML_ELEMENT_DECL) {
6363 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6364 return;
6365 }
6366 if (cur->type == XML_ATTRIBUTE_DECL) {
6367 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6368 return;
6369 }
6370 if (cur->type == XML_ENTITY_DECL) {
6371 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6372 return;
6373 }
6374 if (cur->type == XML_TEXT_NODE) {
6375 if (cur->content != NULL) {
6376 if ((cur->name == xmlStringText) ||
6377 (cur->name != xmlStringTextNoenc)) {
6378 xmlChar *buffer;
6379
Owen Taylor3473f882001-02-23 17:55:21 +00006380 if (encoding == NULL)
6381 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6382 else
6383 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006384 if (buffer != NULL) {
6385 xmlOutputBufferWriteString(buf, (const char *)buffer);
6386 xmlFree(buffer);
6387 }
6388 } else {
6389 /*
6390 * Disable escaping, needed for XSLT
6391 */
Owen Taylor3473f882001-02-23 17:55:21 +00006392 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006393 }
6394 }
6395
6396 return;
6397 }
6398 if (cur->type == XML_PI_NODE) {
6399 if (cur->content != NULL) {
6400 xmlOutputBufferWriteString(buf, "<?");
6401 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6402 if (cur->content != NULL) {
6403 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006404 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006405 }
6406 xmlOutputBufferWriteString(buf, "?>");
6407 } else {
6408 xmlOutputBufferWriteString(buf, "<?");
6409 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6410 xmlOutputBufferWriteString(buf, "?>");
6411 }
6412 return;
6413 }
6414 if (cur->type == XML_COMMENT_NODE) {
6415 if (cur->content != NULL) {
6416 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006417 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006418 xmlOutputBufferWriteString(buf, "-->");
6419 }
6420 return;
6421 }
6422 if (cur->type == XML_ENTITY_REF_NODE) {
6423 xmlOutputBufferWriteString(buf, "&");
6424 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6425 xmlOutputBufferWriteString(buf, ";");
6426 return;
6427 }
6428 if (cur->type == XML_CDATA_SECTION_NODE) {
6429 xmlOutputBufferWriteString(buf, "<![CDATA[");
6430 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006431 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006432 xmlOutputBufferWriteString(buf, "]]>");
6433 return;
6434 }
6435
6436 if (format == 1) {
6437 tmp = cur->children;
6438 while (tmp != NULL) {
6439 if ((tmp->type == XML_TEXT_NODE) ||
6440 (tmp->type == XML_ENTITY_REF_NODE)) {
6441 format = 0;
6442 break;
6443 }
6444 tmp = tmp->next;
6445 }
6446 }
6447 xmlOutputBufferWriteString(buf, "<");
6448 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6449 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6450 xmlOutputBufferWriteString(buf, ":");
6451 }
6452
6453 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6454 if (cur->nsDef)
6455 xmlNsListDumpOutput(buf, cur->nsDef);
6456 if (cur->properties != NULL)
6457 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6458
Daniel Veillard7db37732001-07-12 01:20:08 +00006459 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6460 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006461 xmlOutputBufferWriteString(buf, "/>");
6462 return;
6463 }
6464 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006465 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006466 xmlChar *buffer;
6467
Owen Taylor3473f882001-02-23 17:55:21 +00006468 if (encoding == NULL)
6469 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6470 else
6471 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006472 if (buffer != NULL) {
6473 xmlOutputBufferWriteString(buf, (const char *)buffer);
6474 xmlFree(buffer);
6475 }
6476 }
6477 if (cur->children != NULL) {
6478 if (format) xmlOutputBufferWriteString(buf, "\n");
6479 xmlNodeListDumpOutput(buf, doc, cur->children,
6480 (level >= 0?level+1:-1), format, encoding);
6481 if ((xmlIndentTreeOutput) && (format))
6482 for (i = 0;i < level;i++)
6483 xmlOutputBufferWriteString(buf, " ");
6484 }
6485 xmlOutputBufferWriteString(buf, "</");
6486 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6487 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6488 xmlOutputBufferWriteString(buf, ":");
6489 }
6490
6491 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6492 xmlOutputBufferWriteString(buf, ">");
6493}
6494
6495/**
6496 * xmlDocContentDumpOutput:
6497 * @buf: the XML buffer output
6498 * @cur: the document
6499 * @encoding: an optional encoding string
6500 * @format: should formatting spaces been added
6501 *
6502 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006503 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6504 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006505 */
6506static void
6507xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6508 const char *encoding, int format) {
6509 xmlOutputBufferWriteString(buf, "<?xml version=");
6510 if (cur->version != NULL)
6511 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6512 else
6513 xmlOutputBufferWriteString(buf, "\"1.0\"");
6514 if (encoding == NULL) {
6515 if (cur->encoding != NULL)
6516 encoding = (const char *) cur->encoding;
6517 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6518 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6519 }
6520 if (encoding != NULL) {
6521 xmlOutputBufferWriteString(buf, " encoding=");
6522 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6523 }
6524 switch (cur->standalone) {
6525 case 0:
6526 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6527 break;
6528 case 1:
6529 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6530 break;
6531 }
6532 xmlOutputBufferWriteString(buf, "?>\n");
6533 if (cur->children != NULL) {
6534 xmlNodePtr child = cur->children;
6535
6536 while (child != NULL) {
6537 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6538 xmlOutputBufferWriteString(buf, "\n");
6539 child = child->next;
6540 }
6541 }
6542}
6543
6544/************************************************************************
6545 * *
6546 * Saving functions front-ends *
6547 * *
6548 ************************************************************************/
6549
6550/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006551 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006552 * @out_doc: Document to generate XML text from
6553 * @doc_txt_ptr: Memory pointer for allocated XML text
6554 * @doc_txt_len: Length of the generated XML text
6555 * @txt_encoding: Character encoding to use when generating XML text
6556 * @format: should formatting spaces been added
6557 *
6558 * Dump the current DOM tree into memory using the character encoding specified
6559 * by the caller. Note it is up to the caller of this function to free the
6560 * allocated memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006561 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6562 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006563 */
6564
6565void
6566xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006567 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006568 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006569 int dummy = 0;
6570
6571 xmlCharEncoding doc_charset;
6572 xmlOutputBufferPtr out_buff = NULL;
6573 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6574
6575 if (doc_txt_len == NULL) {
6576 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6577 }
6578
6579 if (doc_txt_ptr == NULL) {
6580 *doc_txt_len = 0;
6581 xmlGenericError(xmlGenericErrorContext,
6582 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6583 return;
6584 }
6585
6586 *doc_txt_ptr = NULL;
6587 *doc_txt_len = 0;
6588
6589 if (out_doc == NULL) {
6590 /* No document, no output */
6591 xmlGenericError(xmlGenericErrorContext,
6592 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6593 return;
6594 }
6595
6596 /*
6597 * Validate the encoding value, if provided.
6598 * This logic is copied from xmlSaveFileEnc.
6599 */
6600
6601 if (txt_encoding == NULL)
6602 txt_encoding = (const char *) out_doc->encoding;
6603 if (txt_encoding != NULL) {
6604 doc_charset = xmlParseCharEncoding(txt_encoding);
6605
6606 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6607 xmlGenericError(xmlGenericErrorContext,
6608 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6609 return;
6610
6611 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6612 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6613 if ( conv_hdlr == NULL ) {
6614 xmlGenericError(xmlGenericErrorContext,
6615 "%s: %s %s '%s'\n",
6616 "xmlDocDumpFormatMemoryEnc",
6617 "Failed to identify encoding handler for",
6618 "character set",
6619 txt_encoding);
6620 return;
6621 }
6622 }
6623 }
6624
6625 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6626 xmlGenericError(xmlGenericErrorContext,
6627 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6628 return;
6629 }
6630
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006631 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006632 xmlOutputBufferFlush(out_buff);
6633 if (out_buff->conv != NULL) {
6634 *doc_txt_len = out_buff->conv->use;
6635 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6636 } else {
6637 *doc_txt_len = out_buff->buffer->use;
6638 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6639 }
6640 (void)xmlOutputBufferClose(out_buff);
6641
6642 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6643 *doc_txt_len = 0;
6644 xmlGenericError(xmlGenericErrorContext,
6645 "xmlDocDumpFormatMemoryEnc: %s\n",
6646 "Failed to allocate memory for document text representation.");
6647 }
6648
6649 return;
6650}
6651
6652/**
6653 * xmlDocDumpMemory:
6654 * @cur: the document
6655 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006656 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006657 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006658 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006659 * It's up to the caller to free the memory.
6660 */
6661void
6662xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6663 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6664}
6665
6666/**
6667 * xmlDocDumpFormatMemory:
6668 * @cur: the document
6669 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006670 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006671 * @format: should formatting spaces been added
6672 *
6673 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006674 * Dump an XML document in memory and return the #xmlChar * and it's size.
Owen Taylor3473f882001-02-23 17:55:21 +00006675 * It's up to the caller to free the memory.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006676 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6677 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006678 */
6679void
6680xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6681 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6682}
6683
6684/**
6685 * xmlDocDumpMemoryEnc:
6686 * @out_doc: Document to generate XML text from
6687 * @doc_txt_ptr: Memory pointer for allocated XML text
6688 * @doc_txt_len: Length of the generated XML text
6689 * @txt_encoding: Character encoding to use when generating XML text
6690 *
6691 * Dump the current DOM tree into memory using the character encoding specified
6692 * by the caller. Note it is up to the caller of this function to free the
6693 * allocated memory.
6694 */
6695
6696void
6697xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6698 int * doc_txt_len, const char * txt_encoding) {
6699 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006700 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006701}
6702
6703/**
6704 * xmlGetDocCompressMode:
6705 * @doc: the document
6706 *
6707 * get the compression ratio for a document, ZLIB based
6708 * Returns 0 (uncompressed) to 9 (max compression)
6709 */
6710int
6711xmlGetDocCompressMode (xmlDocPtr doc) {
6712 if (doc == NULL) return(-1);
6713 return(doc->compression);
6714}
6715
6716/**
6717 * xmlSetDocCompressMode:
6718 * @doc: the document
6719 * @mode: the compression ratio
6720 *
6721 * set the compression ratio for a document, ZLIB based
6722 * Correct values: 0 (uncompressed) to 9 (max compression)
6723 */
6724void
6725xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6726 if (doc == NULL) return;
6727 if (mode < 0) doc->compression = 0;
6728 else if (mode > 9) doc->compression = 9;
6729 else doc->compression = mode;
6730}
6731
6732/**
6733 * xmlGetCompressMode:
6734 *
6735 * get the default compression mode used, ZLIB based.
6736 * Returns 0 (uncompressed) to 9 (max compression)
6737 */
6738int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006739xmlGetCompressMode(void)
6740{
6741 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00006742}
6743
6744/**
6745 * xmlSetCompressMode:
6746 * @mode: the compression ratio
6747 *
6748 * set the default compression mode used, ZLIB based
6749 * Correct values: 0 (uncompressed) to 9 (max compression)
6750 */
6751void
6752xmlSetCompressMode(int mode) {
6753 if (mode < 0) xmlCompressMode = 0;
6754 else if (mode > 9) xmlCompressMode = 9;
6755 else xmlCompressMode = mode;
6756}
6757
6758/**
6759 * xmlDocDump:
6760 * @f: the FILE*
6761 * @cur: the document
6762 *
6763 * Dump an XML document to an open FILE.
6764 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006765 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006766 */
6767int
6768xmlDocDump(FILE *f, xmlDocPtr cur) {
6769 xmlOutputBufferPtr buf;
6770 const char * encoding;
6771 xmlCharEncodingHandlerPtr handler = NULL;
6772 int ret;
6773
6774 if (cur == NULL) {
6775#ifdef DEBUG_TREE
6776 xmlGenericError(xmlGenericErrorContext,
6777 "xmlDocDump : document == NULL\n");
6778#endif
6779 return(-1);
6780 }
6781 encoding = (const char *) cur->encoding;
6782
6783 if (encoding != NULL) {
6784 xmlCharEncoding enc;
6785
6786 enc = xmlParseCharEncoding(encoding);
6787
6788 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6789 xmlGenericError(xmlGenericErrorContext,
6790 "xmlDocDump: document not in UTF8\n");
6791 return(-1);
6792 }
6793 if (enc != XML_CHAR_ENCODING_UTF8) {
6794 handler = xmlFindCharEncodingHandler(encoding);
6795 if (handler == NULL) {
6796 xmlFree((char *) cur->encoding);
6797 cur->encoding = NULL;
6798 }
6799 }
6800 }
6801 buf = xmlOutputBufferCreateFile(f, handler);
6802 if (buf == NULL) return(-1);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006803 xmlDocContentDumpOutput(buf, cur, NULL, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006804
6805 ret = xmlOutputBufferClose(buf);
6806 return(ret);
6807}
6808
6809/**
6810 * xmlSaveFileTo:
6811 * @buf: an output I/O buffer
6812 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006813 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00006814 *
6815 * Dump an XML document to an I/O buffer.
6816 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006817 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006818 */
6819int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006820xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006821 int ret;
6822
6823 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006824 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006825 ret = xmlOutputBufferClose(buf);
6826 return(ret);
6827}
6828
6829/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00006830 * xmlSaveFormatFileTo:
6831 * @buf: an output I/O buffer
6832 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00006833 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00006834 * @format: should formatting spaces been added
6835 *
6836 * Dump an XML document to an I/O buffer.
6837 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006838 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00006839 */
6840int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00006841xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00006842 int ret;
6843
6844 if (buf == NULL) return(0);
6845 xmlDocContentDumpOutput(buf, cur, encoding, format);
6846 ret = xmlOutputBufferClose(buf);
6847 return(ret);
6848}
6849
6850/**
Daniel Veillardf012a642001-07-23 19:10:52 +00006851 * xmlSaveFormatFileEnc
6852 * @filename: the filename or URL to output
6853 * @cur: the document being saved
6854 * @encoding: the name of the encoding to use or NULL.
6855 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00006856 *
6857 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00006858 */
6859int
Daniel Veillardf012a642001-07-23 19:10:52 +00006860xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
6861 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00006862 xmlOutputBufferPtr buf;
6863 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00006864 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00006865 int ret;
6866
Daniel Veillardfb25a512002-01-13 20:32:08 +00006867 if (encoding == NULL)
6868 encoding = (const char *) cur->encoding;
6869
Owen Taylor3473f882001-02-23 17:55:21 +00006870 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006871
6872 enc = xmlParseCharEncoding(encoding);
6873 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
6874 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006875 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006876 return(-1);
6877 }
6878 if (enc != XML_CHAR_ENCODING_UTF8) {
6879 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00006880 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006881 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006882 }
6883 }
6884
Daniel Veillardf012a642001-07-23 19:10:52 +00006885#ifdef HAVE_ZLIB_H
6886 if (cur->compression < 0) cur->compression = xmlCompressMode;
6887#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006888 /*
6889 * save the content to a temp buffer.
6890 */
Daniel Veillardf012a642001-07-23 19:10:52 +00006891 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00006892 if (buf == NULL) return(-1);
6893
Daniel Veillardf012a642001-07-23 19:10:52 +00006894 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006895
6896 ret = xmlOutputBufferClose(buf);
6897 return(ret);
6898}
6899
Daniel Veillardf012a642001-07-23 19:10:52 +00006900
6901/**
6902 * xmlSaveFileEnc:
6903 * @filename: the filename (or URL)
6904 * @cur: the document
6905 * @encoding: the name of an encoding (or NULL)
6906 *
6907 * Dump an XML document, converting it to the given encoding
6908 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006909 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00006910 */
6911int
6912xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
6913 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
6914}
6915
Owen Taylor3473f882001-02-23 17:55:21 +00006916/**
Daniel Veillard67fee942001-04-26 18:59:03 +00006917 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00006918 * @filename: the filename (or URL)
6919 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00006920 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00006921 *
6922 * Dump an XML document to a file. Will use compression if
6923 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00006924 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00006925 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006926 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006927 */
6928int
Daniel Veillard67fee942001-04-26 18:59:03 +00006929xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006930 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00006931}
6932
Daniel Veillard67fee942001-04-26 18:59:03 +00006933/**
6934 * xmlSaveFile:
6935 * @filename: the filename (or URL)
6936 * @cur: the document
6937 *
6938 * Dump an XML document to a file. Will use compression if
6939 * compiled in and enabled. If @filename is "-" the stdout file is
6940 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00006941 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00006942 */
6943int
6944xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00006945 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00006946}
6947