blob: ca050f739a9ff19482ff3aa04aafbdd6de9f4c2d [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 Veillardbd9afb52002-09-25 22:25:35 +0000902 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000903 */
904xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000905xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
906{
Owen Taylor3473f882001-02-23 17:55:21 +0000907 xmlNodePtr node = list;
908 xmlChar *ret = NULL;
909 xmlEntityPtr ent;
910
Daniel Veillard7646b182002-04-20 06:41:40 +0000911 if (list == NULL)
912 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000913
914 while (node != NULL) {
915 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000916 (node->type == XML_CDATA_SECTION_NODE)) {
917 if (inLine) {
918 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000919 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000920 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000921
Daniel Veillard7646b182002-04-20 06:41:40 +0000922 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
923 if (buffer != NULL) {
924 ret = xmlStrcat(ret, buffer);
925 xmlFree(buffer);
926 }
927 }
928 } else if (node->type == XML_ENTITY_REF_NODE) {
929 if (inLine) {
930 ent = xmlGetDocEntity(doc, node->name);
931 if (ent != NULL) {
932 xmlChar *buffer;
933
934 /* an entity content can be any "well balanced chunk",
935 * i.e. the result of the content [43] production:
936 * http://www.w3.org/TR/REC-xml#NT-content.
937 * So it can contain text, CDATA section or nested
938 * entity reference nodes (among others).
939 * -> we recursive call xmlNodeListGetString()
940 * which handles these types */
941 buffer = xmlNodeListGetString(doc, ent->children, 1);
942 if (buffer != NULL) {
943 ret = xmlStrcat(ret, buffer);
944 xmlFree(buffer);
945 }
946 } else {
947 ret = xmlStrcat(ret, node->content);
948 }
949 } else {
950 xmlChar buf[2];
951
952 buf[0] = '&';
953 buf[1] = 0;
954 ret = xmlStrncat(ret, buf, 1);
955 ret = xmlStrcat(ret, node->name);
956 buf[0] = ';';
957 buf[1] = 0;
958 ret = xmlStrncat(ret, buf, 1);
959 }
960 }
961#if 0
962 else {
963 xmlGenericError(xmlGenericErrorContext,
964 "xmlGetNodeListString : invalid node type %d\n",
965 node->type);
966 }
967#endif
968 node = node->next;
969 }
970 return (ret);
971}
Owen Taylor3473f882001-02-23 17:55:21 +0000972/**
973 * xmlNodeListGetRawString:
974 * @doc: the document
975 * @list: a Node list
976 * @inLine: should we replace entity contents or show their external form
977 *
978 * Returns the string equivalent to the text contained in the Node list
979 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
980 * this function doesn't do any character encoding handling.
981 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000982 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000983 */
984xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000985xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
986{
Owen Taylor3473f882001-02-23 17:55:21 +0000987 xmlNodePtr node = list;
988 xmlChar *ret = NULL;
989 xmlEntityPtr ent;
990
Daniel Veillard7646b182002-04-20 06:41:40 +0000991 if (list == NULL)
992 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000993
994 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000995 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000996 (node->type == XML_CDATA_SECTION_NODE)) {
997 if (inLine) {
998 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001000 xmlChar *buffer;
1001
1002 buffer = xmlEncodeSpecialChars(doc, node->content);
1003 if (buffer != NULL) {
1004 ret = xmlStrcat(ret, buffer);
1005 xmlFree(buffer);
1006 }
1007 }
1008 } else if (node->type == XML_ENTITY_REF_NODE) {
1009 if (inLine) {
1010 ent = xmlGetDocEntity(doc, node->name);
1011 if (ent != NULL) {
1012 xmlChar *buffer;
1013
1014 /* an entity content can be any "well balanced chunk",
1015 * i.e. the result of the content [43] production:
1016 * http://www.w3.org/TR/REC-xml#NT-content.
1017 * So it can contain text, CDATA section or nested
1018 * entity reference nodes (among others).
1019 * -> we recursive call xmlNodeListGetRawString()
1020 * which handles these types */
1021 buffer =
1022 xmlNodeListGetRawString(doc, ent->children, 1);
1023 if (buffer != NULL) {
1024 ret = xmlStrcat(ret, buffer);
1025 xmlFree(buffer);
1026 }
1027 } else {
1028 ret = xmlStrcat(ret, node->content);
1029 }
1030 } else {
1031 xmlChar buf[2];
1032
1033 buf[0] = '&';
1034 buf[1] = 0;
1035 ret = xmlStrncat(ret, buf, 1);
1036 ret = xmlStrcat(ret, node->name);
1037 buf[0] = ';';
1038 buf[1] = 0;
1039 ret = xmlStrncat(ret, buf, 1);
1040 }
1041 }
Owen Taylor3473f882001-02-23 17:55:21 +00001042#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001043 else {
1044 xmlGenericError(xmlGenericErrorContext,
1045 "xmlGetNodeListString : invalid node type %d\n",
1046 node->type);
1047 }
Owen Taylor3473f882001-02-23 17:55:21 +00001048#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001049 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001050 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001051 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001052}
1053
1054/**
1055 * xmlNewProp:
1056 * @node: the holding node
1057 * @name: the name of the attribute
1058 * @value: the value of the attribute
1059 *
1060 * Create a new property carried by a node.
1061 * Returns a pointer to the attribute
1062 */
1063xmlAttrPtr
1064xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1065 xmlAttrPtr cur;
1066 xmlDocPtr doc = NULL;
1067
1068 if (name == NULL) {
1069#ifdef DEBUG_TREE
1070 xmlGenericError(xmlGenericErrorContext,
1071 "xmlNewProp : name == NULL\n");
1072#endif
1073 return(NULL);
1074 }
1075
1076 /*
1077 * Allocate a new property and fill the fields.
1078 */
1079 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1080 if (cur == NULL) {
1081 xmlGenericError(xmlGenericErrorContext,
1082 "xmlNewProp : malloc failed\n");
1083 return(NULL);
1084 }
1085 memset(cur, 0, sizeof(xmlAttr));
1086 cur->type = XML_ATTRIBUTE_NODE;
1087
1088 cur->parent = node;
1089 if (node != NULL) {
1090 doc = node->doc;
1091 cur->doc = doc;
1092 }
1093 cur->name = xmlStrdup(name);
1094 if (value != NULL) {
1095 xmlChar *buffer;
1096 xmlNodePtr tmp;
1097
1098 buffer = xmlEncodeEntitiesReentrant(doc, value);
1099 cur->children = xmlStringGetNodeList(doc, buffer);
1100 cur->last = NULL;
1101 tmp = cur->children;
1102 while (tmp != NULL) {
1103 tmp->parent = (xmlNodePtr) cur;
1104 tmp->doc = doc;
1105 if (tmp->next == NULL)
1106 cur->last = tmp;
1107 tmp = tmp->next;
1108 }
1109 xmlFree(buffer);
1110 }
1111
1112 /*
1113 * Add it at the end to preserve parsing order ...
1114 */
1115 if (node != NULL) {
1116 if (node->properties == NULL) {
1117 node->properties = cur;
1118 } else {
1119 xmlAttrPtr prev = node->properties;
1120
1121 while (prev->next != NULL) prev = prev->next;
1122 prev->next = cur;
1123 cur->prev = prev;
1124 }
1125 }
1126 return(cur);
1127}
1128
1129/**
1130 * xmlNewNsProp:
1131 * @node: the holding node
1132 * @ns: the namespace
1133 * @name: the name of the attribute
1134 * @value: the value of the attribute
1135 *
1136 * Create a new property tagged with a namespace and carried by a node.
1137 * Returns a pointer to the attribute
1138 */
1139xmlAttrPtr
1140xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1141 const xmlChar *value) {
1142 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001143 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001144
1145 if (name == NULL) {
1146#ifdef DEBUG_TREE
1147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001148 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001149#endif
1150 return(NULL);
1151 }
1152
1153 /*
1154 * Allocate a new property and fill the fields.
1155 */
1156 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1157 if (cur == NULL) {
1158 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001159 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001160 return(NULL);
1161 }
1162 memset(cur, 0, sizeof(xmlAttr));
1163 cur->type = XML_ATTRIBUTE_NODE;
1164
1165 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001166 if (node != NULL) {
1167 doc = node->doc;
1168 cur->doc = doc;
1169 }
Owen Taylor3473f882001-02-23 17:55:21 +00001170 cur->ns = ns;
1171 cur->name = xmlStrdup(name);
1172 if (value != NULL) {
1173 xmlChar *buffer;
1174 xmlNodePtr tmp;
1175
Daniel Veillarda682b212001-06-07 19:59:42 +00001176 buffer = xmlEncodeEntitiesReentrant(doc, value);
1177 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001178 cur->last = NULL;
1179 tmp = cur->children;
1180 while (tmp != NULL) {
1181 tmp->parent = (xmlNodePtr) cur;
1182 if (tmp->next == NULL)
1183 cur->last = tmp;
1184 tmp = tmp->next;
1185 }
1186 xmlFree(buffer);
1187 }
1188
1189 /*
1190 * Add it at the end to preserve parsing order ...
1191 */
1192 if (node != NULL) {
1193 if (node->properties == NULL) {
1194 node->properties = cur;
1195 } else {
1196 xmlAttrPtr prev = node->properties;
1197
1198 while (prev->next != NULL) prev = prev->next;
1199 prev->next = cur;
1200 cur->prev = prev;
1201 }
1202 }
1203 return(cur);
1204}
1205
1206/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001207 * xmlNewNsPropEatName:
1208 * @node: the holding node
1209 * @ns: the namespace
1210 * @name: the name of the attribute
1211 * @value: the value of the attribute
1212 *
1213 * Create a new property tagged with a namespace and carried by a node.
1214 * Returns a pointer to the attribute
1215 */
1216xmlAttrPtr
1217xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1218 const xmlChar *value) {
1219 xmlAttrPtr cur;
1220 xmlDocPtr doc = NULL;
1221
1222 if (name == NULL) {
1223#ifdef DEBUG_TREE
1224 xmlGenericError(xmlGenericErrorContext,
1225 "xmlNewNsPropEatName : name == NULL\n");
1226#endif
1227 return(NULL);
1228 }
1229
1230 /*
1231 * Allocate a new property and fill the fields.
1232 */
1233 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1234 if (cur == NULL) {
1235 xmlGenericError(xmlGenericErrorContext,
1236 "xmlNewNsPropEatName : malloc failed\n");
1237 return(NULL);
1238 }
1239 memset(cur, 0, sizeof(xmlAttr));
1240 cur->type = XML_ATTRIBUTE_NODE;
1241
1242 cur->parent = node;
1243 if (node != NULL) {
1244 doc = node->doc;
1245 cur->doc = doc;
1246 }
1247 cur->ns = ns;
1248 cur->name = name;
1249 if (value != NULL) {
1250 xmlChar *buffer;
1251 xmlNodePtr tmp;
1252
1253 buffer = xmlEncodeEntitiesReentrant(doc, value);
1254 cur->children = xmlStringGetNodeList(doc, buffer);
1255 cur->last = NULL;
1256 tmp = cur->children;
1257 while (tmp != NULL) {
1258 tmp->parent = (xmlNodePtr) cur;
1259 if (tmp->next == NULL)
1260 cur->last = tmp;
1261 tmp = tmp->next;
1262 }
1263 xmlFree(buffer);
1264 }
1265
1266 /*
1267 * Add it at the end to preserve parsing order ...
1268 */
1269 if (node != NULL) {
1270 if (node->properties == NULL) {
1271 node->properties = cur;
1272 } else {
1273 xmlAttrPtr prev = node->properties;
1274
1275 while (prev->next != NULL) prev = prev->next;
1276 prev->next = cur;
1277 cur->prev = prev;
1278 }
1279 }
1280 return(cur);
1281}
1282
1283/**
Owen Taylor3473f882001-02-23 17:55:21 +00001284 * xmlNewDocProp:
1285 * @doc: the document
1286 * @name: the name of the attribute
1287 * @value: the value of the attribute
1288 *
1289 * Create a new property carried by a document.
1290 * Returns a pointer to the attribute
1291 */
1292xmlAttrPtr
1293xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1294 xmlAttrPtr cur;
1295
1296 if (name == NULL) {
1297#ifdef DEBUG_TREE
1298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001299 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001300#endif
1301 return(NULL);
1302 }
1303
1304 /*
1305 * Allocate a new property and fill the fields.
1306 */
1307 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1308 if (cur == NULL) {
1309 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001310 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001311 return(NULL);
1312 }
1313 memset(cur, 0, sizeof(xmlAttr));
1314 cur->type = XML_ATTRIBUTE_NODE;
1315
1316 cur->name = xmlStrdup(name);
1317 cur->doc = doc;
1318 if (value != NULL) {
1319 xmlNodePtr tmp;
1320
1321 cur->children = xmlStringGetNodeList(doc, value);
1322 cur->last = NULL;
1323
1324 tmp = cur->children;
1325 while (tmp != NULL) {
1326 tmp->parent = (xmlNodePtr) cur;
1327 if (tmp->next == NULL)
1328 cur->last = tmp;
1329 tmp = tmp->next;
1330 }
1331 }
1332 return(cur);
1333}
1334
1335/**
1336 * xmlFreePropList:
1337 * @cur: the first property in the list
1338 *
1339 * Free a property and all its siblings, all the children are freed too.
1340 */
1341void
1342xmlFreePropList(xmlAttrPtr cur) {
1343 xmlAttrPtr next;
1344 if (cur == NULL) {
1345#ifdef DEBUG_TREE
1346 xmlGenericError(xmlGenericErrorContext,
1347 "xmlFreePropList : property == NULL\n");
1348#endif
1349 return;
1350 }
1351 while (cur != NULL) {
1352 next = cur->next;
1353 xmlFreeProp(cur);
1354 cur = next;
1355 }
1356}
1357
1358/**
1359 * xmlFreeProp:
1360 * @cur: an attribute
1361 *
1362 * Free one attribute, all the content is freed too
1363 */
1364void
1365xmlFreeProp(xmlAttrPtr cur) {
1366 if (cur == NULL) {
1367#ifdef DEBUG_TREE
1368 xmlGenericError(xmlGenericErrorContext,
1369 "xmlFreeProp : property == NULL\n");
1370#endif
1371 return;
1372 }
1373 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001374 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1375 ((cur->parent->doc->intSubset != NULL) ||
1376 (cur->parent->doc->extSubset != NULL))) {
1377 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1378 xmlRemoveID(cur->parent->doc, cur);
1379 }
Owen Taylor3473f882001-02-23 17:55:21 +00001380 if (cur->name != NULL) xmlFree((char *) cur->name);
1381 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001382 xmlFree(cur);
1383}
1384
1385/**
1386 * xmlRemoveProp:
1387 * @cur: an attribute
1388 *
1389 * Unlink and free one attribute, all the content is freed too
1390 * Note this doesn't work for namespace definition attributes
1391 *
1392 * Returns 0 if success and -1 in case of error.
1393 */
1394int
1395xmlRemoveProp(xmlAttrPtr cur) {
1396 xmlAttrPtr tmp;
1397 if (cur == NULL) {
1398#ifdef DEBUG_TREE
1399 xmlGenericError(xmlGenericErrorContext,
1400 "xmlRemoveProp : cur == NULL\n");
1401#endif
1402 return(-1);
1403 }
1404 if (cur->parent == NULL) {
1405#ifdef DEBUG_TREE
1406 xmlGenericError(xmlGenericErrorContext,
1407 "xmlRemoveProp : cur->parent == NULL\n");
1408#endif
1409 return(-1);
1410 }
1411 tmp = cur->parent->properties;
1412 if (tmp == cur) {
1413 cur->parent->properties = cur->next;
1414 xmlFreeProp(cur);
1415 return(0);
1416 }
1417 while (tmp != NULL) {
1418 if (tmp->next == cur) {
1419 tmp->next = cur->next;
1420 if (tmp->next != NULL)
1421 tmp->next->prev = tmp;
1422 xmlFreeProp(cur);
1423 return(0);
1424 }
1425 tmp = tmp->next;
1426 }
1427#ifdef DEBUG_TREE
1428 xmlGenericError(xmlGenericErrorContext,
1429 "xmlRemoveProp : attribute not owned by its node\n");
1430#endif
1431 return(-1);
1432}
1433
1434/**
1435 * xmlNewPI:
1436 * @name: the processing instruction name
1437 * @content: the PI content
1438 *
1439 * Creation of a processing instruction element.
1440 * Returns a pointer to the new node object.
1441 */
1442xmlNodePtr
1443xmlNewPI(const xmlChar *name, const xmlChar *content) {
1444 xmlNodePtr cur;
1445
1446 if (name == NULL) {
1447#ifdef DEBUG_TREE
1448 xmlGenericError(xmlGenericErrorContext,
1449 "xmlNewPI : name == NULL\n");
1450#endif
1451 return(NULL);
1452 }
1453
1454 /*
1455 * Allocate a new node and fill the fields.
1456 */
1457 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1458 if (cur == NULL) {
1459 xmlGenericError(xmlGenericErrorContext,
1460 "xmlNewPI : malloc failed\n");
1461 return(NULL);
1462 }
1463 memset(cur, 0, sizeof(xmlNode));
1464 cur->type = XML_PI_NODE;
1465
1466 cur->name = xmlStrdup(name);
1467 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001468 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001469 }
1470 return(cur);
1471}
1472
1473/**
1474 * xmlNewNode:
1475 * @ns: namespace if any
1476 * @name: the node name
1477 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001478 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001479 *
1480 * Returns a pointer to the new node object.
1481 */
1482xmlNodePtr
1483xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1484 xmlNodePtr cur;
1485
1486 if (name == NULL) {
1487#ifdef DEBUG_TREE
1488 xmlGenericError(xmlGenericErrorContext,
1489 "xmlNewNode : name == NULL\n");
1490#endif
1491 return(NULL);
1492 }
1493
1494 /*
1495 * Allocate a new node and fill the fields.
1496 */
1497 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1498 if (cur == NULL) {
1499 xmlGenericError(xmlGenericErrorContext,
1500 "xmlNewNode : malloc failed\n");
1501 return(NULL);
1502 }
1503 memset(cur, 0, sizeof(xmlNode));
1504 cur->type = XML_ELEMENT_NODE;
1505
1506 cur->name = xmlStrdup(name);
1507 cur->ns = ns;
1508 return(cur);
1509}
1510
1511/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001512 * xmlNewNodeEatName:
1513 * @ns: namespace if any
1514 * @name: the node name
1515 *
1516 * Creation of a new node element. @ns is optional (NULL).
1517 *
1518 * Returns a pointer to the new node object.
1519 */
1520xmlNodePtr
1521xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1522 xmlNodePtr cur;
1523
1524 if (name == NULL) {
1525#ifdef DEBUG_TREE
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlNewNode : name == NULL\n");
1528#endif
1529 return(NULL);
1530 }
1531
1532 /*
1533 * Allocate a new node and fill the fields.
1534 */
1535 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1536 if (cur == NULL) {
1537 xmlGenericError(xmlGenericErrorContext,
1538 "xmlNewNode : malloc failed\n");
1539 return(NULL);
1540 }
1541 memset(cur, 0, sizeof(xmlNode));
1542 cur->type = XML_ELEMENT_NODE;
1543
1544 cur->name = name;
1545 cur->ns = ns;
1546 return(cur);
1547}
1548
1549/**
Owen Taylor3473f882001-02-23 17:55:21 +00001550 * xmlNewDocNode:
1551 * @doc: the document
1552 * @ns: namespace if any
1553 * @name: the node name
1554 * @content: the XML text content if any
1555 *
1556 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001557 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001558 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1559 * references, but XML special chars need to be escaped first by using
1560 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1561 * need entities support.
1562 *
1563 * Returns a pointer to the new node object.
1564 */
1565xmlNodePtr
1566xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1567 const xmlChar *name, const xmlChar *content) {
1568 xmlNodePtr cur;
1569
1570 cur = xmlNewNode(ns, name);
1571 if (cur != NULL) {
1572 cur->doc = doc;
1573 if (content != NULL) {
1574 cur->children = xmlStringGetNodeList(doc, content);
1575 UPDATE_LAST_CHILD_AND_PARENT(cur)
1576 }
1577 }
1578 return(cur);
1579}
1580
Daniel Veillard46de64e2002-05-29 08:21:33 +00001581/**
1582 * xmlNewDocNodeEatName:
1583 * @doc: the document
1584 * @ns: namespace if any
1585 * @name: the node name
1586 * @content: the XML text content if any
1587 *
1588 * Creation of a new node element within a document. @ns and @content
1589 * are optional (NULL).
1590 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1591 * references, but XML special chars need to be escaped first by using
1592 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1593 * need entities support.
1594 *
1595 * Returns a pointer to the new node object.
1596 */
1597xmlNodePtr
1598xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1599 xmlChar *name, const xmlChar *content) {
1600 xmlNodePtr cur;
1601
1602 cur = xmlNewNodeEatName(ns, name);
1603 if (cur != NULL) {
1604 cur->doc = doc;
1605 if (content != NULL) {
1606 cur->children = xmlStringGetNodeList(doc, content);
1607 UPDATE_LAST_CHILD_AND_PARENT(cur)
1608 }
1609 }
1610 return(cur);
1611}
1612
Owen Taylor3473f882001-02-23 17:55:21 +00001613
1614/**
1615 * xmlNewDocRawNode:
1616 * @doc: the document
1617 * @ns: namespace if any
1618 * @name: the node name
1619 * @content: the text content if any
1620 *
1621 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001622 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001623 *
1624 * Returns a pointer to the new node object.
1625 */
1626xmlNodePtr
1627xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1628 const xmlChar *name, const xmlChar *content) {
1629 xmlNodePtr cur;
1630
1631 cur = xmlNewNode(ns, name);
1632 if (cur != NULL) {
1633 cur->doc = doc;
1634 if (content != NULL) {
1635 cur->children = xmlNewDocText(doc, content);
1636 UPDATE_LAST_CHILD_AND_PARENT(cur)
1637 }
1638 }
1639 return(cur);
1640}
1641
1642/**
1643 * xmlNewDocFragment:
1644 * @doc: the document owning the fragment
1645 *
1646 * Creation of a new Fragment node.
1647 * Returns a pointer to the new node object.
1648 */
1649xmlNodePtr
1650xmlNewDocFragment(xmlDocPtr doc) {
1651 xmlNodePtr cur;
1652
1653 /*
1654 * Allocate a new DocumentFragment node and fill the fields.
1655 */
1656 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1657 if (cur == NULL) {
1658 xmlGenericError(xmlGenericErrorContext,
1659 "xmlNewDocFragment : malloc failed\n");
1660 return(NULL);
1661 }
1662 memset(cur, 0, sizeof(xmlNode));
1663 cur->type = XML_DOCUMENT_FRAG_NODE;
1664
1665 cur->doc = doc;
1666 return(cur);
1667}
1668
1669/**
1670 * xmlNewText:
1671 * @content: the text content
1672 *
1673 * Creation of a new text node.
1674 * Returns a pointer to the new node object.
1675 */
1676xmlNodePtr
1677xmlNewText(const xmlChar *content) {
1678 xmlNodePtr cur;
1679
1680 /*
1681 * Allocate a new node and fill the fields.
1682 */
1683 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1684 if (cur == NULL) {
1685 xmlGenericError(xmlGenericErrorContext,
1686 "xmlNewText : malloc failed\n");
1687 return(NULL);
1688 }
1689 memset(cur, 0, sizeof(xmlNode));
1690 cur->type = XML_TEXT_NODE;
1691
1692 cur->name = xmlStringText;
1693 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001694 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001695 }
1696 return(cur);
1697}
1698
1699/**
1700 * xmlNewTextChild:
1701 * @parent: the parent node
1702 * @ns: a namespace if any
1703 * @name: the name of the child
1704 * @content: the text content of the child if any.
1705 *
1706 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001707 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001708 * a child TEXT node will be created containing the string content.
1709 *
1710 * Returns a pointer to the new node object.
1711 */
1712xmlNodePtr
1713xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1714 const xmlChar *name, const xmlChar *content) {
1715 xmlNodePtr cur, prev;
1716
1717 if (parent == NULL) {
1718#ifdef DEBUG_TREE
1719 xmlGenericError(xmlGenericErrorContext,
1720 "xmlNewTextChild : parent == NULL\n");
1721#endif
1722 return(NULL);
1723 }
1724
1725 if (name == NULL) {
1726#ifdef DEBUG_TREE
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlNewTextChild : name == NULL\n");
1729#endif
1730 return(NULL);
1731 }
1732
1733 /*
1734 * Allocate a new node
1735 */
1736 if (ns == NULL)
1737 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1738 else
1739 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1740 if (cur == NULL) return(NULL);
1741
1742 /*
1743 * add the new element at the end of the children list.
1744 */
1745 cur->type = XML_ELEMENT_NODE;
1746 cur->parent = parent;
1747 cur->doc = parent->doc;
1748 if (parent->children == NULL) {
1749 parent->children = cur;
1750 parent->last = cur;
1751 } else {
1752 prev = parent->last;
1753 prev->next = cur;
1754 cur->prev = prev;
1755 parent->last = cur;
1756 }
1757
1758 return(cur);
1759}
1760
1761/**
1762 * xmlNewCharRef:
1763 * @doc: the document
1764 * @name: the char ref string, starting with # or "&# ... ;"
1765 *
1766 * Creation of a new character reference node.
1767 * Returns a pointer to the new node object.
1768 */
1769xmlNodePtr
1770xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1771 xmlNodePtr cur;
1772
1773 /*
1774 * Allocate a new node and fill the fields.
1775 */
1776 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1777 if (cur == NULL) {
1778 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001779 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001780 return(NULL);
1781 }
1782 memset(cur, 0, sizeof(xmlNode));
1783 cur->type = XML_ENTITY_REF_NODE;
1784
1785 cur->doc = doc;
1786 if (name[0] == '&') {
1787 int len;
1788 name++;
1789 len = xmlStrlen(name);
1790 if (name[len - 1] == ';')
1791 cur->name = xmlStrndup(name, len - 1);
1792 else
1793 cur->name = xmlStrndup(name, len);
1794 } else
1795 cur->name = xmlStrdup(name);
1796 return(cur);
1797}
1798
1799/**
1800 * xmlNewReference:
1801 * @doc: the document
1802 * @name: the reference name, or the reference string with & and ;
1803 *
1804 * Creation of a new reference node.
1805 * Returns a pointer to the new node object.
1806 */
1807xmlNodePtr
1808xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1809 xmlNodePtr cur;
1810 xmlEntityPtr ent;
1811
1812 /*
1813 * Allocate a new node and fill the fields.
1814 */
1815 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1816 if (cur == NULL) {
1817 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001818 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001819 return(NULL);
1820 }
1821 memset(cur, 0, sizeof(xmlNode));
1822 cur->type = XML_ENTITY_REF_NODE;
1823
1824 cur->doc = doc;
1825 if (name[0] == '&') {
1826 int len;
1827 name++;
1828 len = xmlStrlen(name);
1829 if (name[len - 1] == ';')
1830 cur->name = xmlStrndup(name, len - 1);
1831 else
1832 cur->name = xmlStrndup(name, len);
1833 } else
1834 cur->name = xmlStrdup(name);
1835
1836 ent = xmlGetDocEntity(doc, cur->name);
1837 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001838 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001839 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001840 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001841 * updated. Not sure if this is 100% correct.
1842 * -George
1843 */
1844 cur->children = (xmlNodePtr) ent;
1845 cur->last = (xmlNodePtr) ent;
1846 }
1847 return(cur);
1848}
1849
1850/**
1851 * xmlNewDocText:
1852 * @doc: the document
1853 * @content: the text content
1854 *
1855 * Creation of a new text node within a document.
1856 * Returns a pointer to the new node object.
1857 */
1858xmlNodePtr
1859xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1860 xmlNodePtr cur;
1861
1862 cur = xmlNewText(content);
1863 if (cur != NULL) cur->doc = doc;
1864 return(cur);
1865}
1866
1867/**
1868 * xmlNewTextLen:
1869 * @content: the text content
1870 * @len: the text len.
1871 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001872 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001873 * Returns a pointer to the new node object.
1874 */
1875xmlNodePtr
1876xmlNewTextLen(const xmlChar *content, int len) {
1877 xmlNodePtr cur;
1878
1879 /*
1880 * Allocate a new node and fill the fields.
1881 */
1882 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1883 if (cur == NULL) {
1884 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001885 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001886 return(NULL);
1887 }
1888 memset(cur, 0, sizeof(xmlNode));
1889 cur->type = XML_TEXT_NODE;
1890
1891 cur->name = xmlStringText;
1892 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001893 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001894 }
1895 return(cur);
1896}
1897
1898/**
1899 * xmlNewDocTextLen:
1900 * @doc: the document
1901 * @content: the text content
1902 * @len: the text len.
1903 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001904 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001905 * text node pertain to a given document.
1906 * Returns a pointer to the new node object.
1907 */
1908xmlNodePtr
1909xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1910 xmlNodePtr cur;
1911
1912 cur = xmlNewTextLen(content, len);
1913 if (cur != NULL) cur->doc = doc;
1914 return(cur);
1915}
1916
1917/**
1918 * xmlNewComment:
1919 * @content: the comment content
1920 *
1921 * Creation of a new node containing a comment.
1922 * Returns a pointer to the new node object.
1923 */
1924xmlNodePtr
1925xmlNewComment(const xmlChar *content) {
1926 xmlNodePtr cur;
1927
1928 /*
1929 * Allocate a new node and fill the fields.
1930 */
1931 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1932 if (cur == NULL) {
1933 xmlGenericError(xmlGenericErrorContext,
1934 "xmlNewComment : malloc failed\n");
1935 return(NULL);
1936 }
1937 memset(cur, 0, sizeof(xmlNode));
1938 cur->type = XML_COMMENT_NODE;
1939
1940 cur->name = xmlStringComment;
1941 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001942 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 }
1944 return(cur);
1945}
1946
1947/**
1948 * xmlNewCDataBlock:
1949 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001950 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001951 * @len: the length of the block
1952 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001953 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001954 * Returns a pointer to the new node object.
1955 */
1956xmlNodePtr
1957xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1958 xmlNodePtr cur;
1959
1960 /*
1961 * Allocate a new node and fill the fields.
1962 */
1963 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1964 if (cur == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlNewCDataBlock : malloc failed\n");
1967 return(NULL);
1968 }
1969 memset(cur, 0, sizeof(xmlNode));
1970 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001971 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001972
1973 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001974 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001975 }
1976 return(cur);
1977}
1978
1979/**
1980 * xmlNewDocComment:
1981 * @doc: the document
1982 * @content: the comment content
1983 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001984 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001985 * Returns a pointer to the new node object.
1986 */
1987xmlNodePtr
1988xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1989 xmlNodePtr cur;
1990
1991 cur = xmlNewComment(content);
1992 if (cur != NULL) cur->doc = doc;
1993 return(cur);
1994}
1995
1996/**
1997 * xmlSetTreeDoc:
1998 * @tree: the top element
1999 * @doc: the document
2000 *
2001 * update all nodes under the tree to point to the right document
2002 */
2003void
2004xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002005 xmlAttrPtr prop;
2006
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (tree == NULL)
2008 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002009 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002010 if(tree->type == XML_ELEMENT_NODE) {
2011 prop = tree->properties;
2012 while (prop != NULL) {
2013 prop->doc = doc;
2014 xmlSetListDoc(prop->children, doc);
2015 prop = prop->next;
2016 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002017 }
Owen Taylor3473f882001-02-23 17:55:21 +00002018 if (tree->children != NULL)
2019 xmlSetListDoc(tree->children, doc);
2020 tree->doc = doc;
2021 }
2022}
2023
2024/**
2025 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002026 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002027 * @doc: the document
2028 *
2029 * update all nodes in the list to point to the right document
2030 */
2031void
2032xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2033 xmlNodePtr cur;
2034
2035 if (list == NULL)
2036 return;
2037 cur = list;
2038 while (cur != NULL) {
2039 if (cur->doc != doc)
2040 xmlSetTreeDoc(cur, doc);
2041 cur = cur->next;
2042 }
2043}
2044
2045
2046/**
2047 * xmlNewChild:
2048 * @parent: the parent node
2049 * @ns: a namespace if any
2050 * @name: the name of the child
2051 * @content: the XML content of the child if any.
2052 *
2053 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002054 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002055 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2056 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2057 * references, but XML special chars need to be escaped first by using
2058 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2059 * support is not needed.
2060 *
2061 * Returns a pointer to the new node object.
2062 */
2063xmlNodePtr
2064xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2065 const xmlChar *name, const xmlChar *content) {
2066 xmlNodePtr cur, prev;
2067
2068 if (parent == NULL) {
2069#ifdef DEBUG_TREE
2070 xmlGenericError(xmlGenericErrorContext,
2071 "xmlNewChild : parent == NULL\n");
2072#endif
2073 return(NULL);
2074 }
2075
2076 if (name == NULL) {
2077#ifdef DEBUG_TREE
2078 xmlGenericError(xmlGenericErrorContext,
2079 "xmlNewChild : name == NULL\n");
2080#endif
2081 return(NULL);
2082 }
2083
2084 /*
2085 * Allocate a new node
2086 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002087 if (parent->type == XML_ELEMENT_NODE) {
2088 if (ns == NULL)
2089 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2090 else
2091 cur = xmlNewDocNode(parent->doc, ns, name, content);
2092 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2093 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2094 if (ns == NULL)
2095 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2096 else
2097 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
2098 } else {
2099 return(NULL);
2100 }
Owen Taylor3473f882001-02-23 17:55:21 +00002101 if (cur == NULL) return(NULL);
2102
2103 /*
2104 * add the new element at the end of the children list.
2105 */
2106 cur->type = XML_ELEMENT_NODE;
2107 cur->parent = parent;
2108 cur->doc = parent->doc;
2109 if (parent->children == NULL) {
2110 parent->children = cur;
2111 parent->last = cur;
2112 } else {
2113 prev = parent->last;
2114 prev->next = cur;
2115 cur->prev = prev;
2116 parent->last = cur;
2117 }
2118
2119 return(cur);
2120}
2121
2122/**
2123 * xmlAddNextSibling:
2124 * @cur: the child node
2125 * @elem: the new node
2126 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002127 * Add a new node @elem as the next sibling of @cur
2128 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002129 * first unlinked from its existing context.
2130 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002131 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2132 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002133 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002134 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002135 */
2136xmlNodePtr
2137xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2138 if (cur == NULL) {
2139#ifdef DEBUG_TREE
2140 xmlGenericError(xmlGenericErrorContext,
2141 "xmlAddNextSibling : cur == NULL\n");
2142#endif
2143 return(NULL);
2144 }
2145 if (elem == NULL) {
2146#ifdef DEBUG_TREE
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlAddNextSibling : elem == NULL\n");
2149#endif
2150 return(NULL);
2151 }
2152
2153 xmlUnlinkNode(elem);
2154
2155 if (elem->type == XML_TEXT_NODE) {
2156 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002157 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002158 xmlFreeNode(elem);
2159 return(cur);
2160 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002161 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2162 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002163 xmlChar *tmp;
2164
2165 tmp = xmlStrdup(elem->content);
2166 tmp = xmlStrcat(tmp, cur->next->content);
2167 xmlNodeSetContent(cur->next, tmp);
2168 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002169 xmlFreeNode(elem);
2170 return(cur->next);
2171 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002172 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2173 /* check if an attribute with the same name exists */
2174 xmlAttrPtr attr;
2175
2176 if (elem->ns == NULL)
2177 attr = xmlHasProp(cur->parent, elem->name);
2178 else
2179 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2180 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2181 /* different instance, destroy it (attributes must be unique) */
2182 xmlFreeProp(attr);
2183 }
Owen Taylor3473f882001-02-23 17:55:21 +00002184 }
2185
2186 if (elem->doc != cur->doc) {
2187 xmlSetTreeDoc(elem, cur->doc);
2188 }
2189 elem->parent = cur->parent;
2190 elem->prev = cur;
2191 elem->next = cur->next;
2192 cur->next = elem;
2193 if (elem->next != NULL)
2194 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002195 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002196 elem->parent->last = elem;
2197 return(elem);
2198}
2199
2200/**
2201 * xmlAddPrevSibling:
2202 * @cur: the child node
2203 * @elem: the new node
2204 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002205 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002207 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002208 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002209 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2210 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002211 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002212 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002213 */
2214xmlNodePtr
2215xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2216 if (cur == NULL) {
2217#ifdef DEBUG_TREE
2218 xmlGenericError(xmlGenericErrorContext,
2219 "xmlAddPrevSibling : cur == NULL\n");
2220#endif
2221 return(NULL);
2222 }
2223 if (elem == NULL) {
2224#ifdef DEBUG_TREE
2225 xmlGenericError(xmlGenericErrorContext,
2226 "xmlAddPrevSibling : elem == NULL\n");
2227#endif
2228 return(NULL);
2229 }
2230
2231 xmlUnlinkNode(elem);
2232
2233 if (elem->type == XML_TEXT_NODE) {
2234 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002235 xmlChar *tmp;
2236
2237 tmp = xmlStrdup(elem->content);
2238 tmp = xmlStrcat(tmp, cur->content);
2239 xmlNodeSetContent(cur, tmp);
2240 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlFreeNode(elem);
2242 return(cur);
2243 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002244 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2245 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002247 xmlFreeNode(elem);
2248 return(cur->prev);
2249 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002250 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2251 /* check if an attribute with the same name exists */
2252 xmlAttrPtr attr;
2253
2254 if (elem->ns == NULL)
2255 attr = xmlHasProp(cur->parent, elem->name);
2256 else
2257 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2258 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2259 /* different instance, destroy it (attributes must be unique) */
2260 xmlFreeProp(attr);
2261 }
Owen Taylor3473f882001-02-23 17:55:21 +00002262 }
2263
2264 if (elem->doc != cur->doc) {
2265 xmlSetTreeDoc(elem, cur->doc);
2266 }
2267 elem->parent = cur->parent;
2268 elem->next = cur;
2269 elem->prev = cur->prev;
2270 cur->prev = elem;
2271 if (elem->prev != NULL)
2272 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002273 if (elem->parent != NULL) {
2274 if (elem->type == XML_ATTRIBUTE_NODE) {
2275 if (elem->parent->properties == (xmlAttrPtr) cur) {
2276 elem->parent->properties = (xmlAttrPtr) elem;
2277 }
2278 } else {
2279 if (elem->parent->children == cur) {
2280 elem->parent->children = elem;
2281 }
2282 }
2283 }
Owen Taylor3473f882001-02-23 17:55:21 +00002284 return(elem);
2285}
2286
2287/**
2288 * xmlAddSibling:
2289 * @cur: the child node
2290 * @elem: the new node
2291 *
2292 * Add a new element @elem to the list of siblings of @cur
2293 * merging adjacent TEXT nodes (@elem may be freed)
2294 * If the new element was already inserted in a document it is
2295 * first unlinked from its existing context.
2296 *
2297 * Returns the new element or NULL in case of error.
2298 */
2299xmlNodePtr
2300xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2301 xmlNodePtr parent;
2302
2303 if (cur == NULL) {
2304#ifdef DEBUG_TREE
2305 xmlGenericError(xmlGenericErrorContext,
2306 "xmlAddSibling : cur == NULL\n");
2307#endif
2308 return(NULL);
2309 }
2310
2311 if (elem == NULL) {
2312#ifdef DEBUG_TREE
2313 xmlGenericError(xmlGenericErrorContext,
2314 "xmlAddSibling : elem == NULL\n");
2315#endif
2316 return(NULL);
2317 }
2318
2319 /*
2320 * Constant time is we can rely on the ->parent->last to find
2321 * the last sibling.
2322 */
2323 if ((cur->parent != NULL) &&
2324 (cur->parent->children != NULL) &&
2325 (cur->parent->last != NULL) &&
2326 (cur->parent->last->next == NULL)) {
2327 cur = cur->parent->last;
2328 } else {
2329 while (cur->next != NULL) cur = cur->next;
2330 }
2331
2332 xmlUnlinkNode(elem);
2333
2334 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002335 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 xmlFreeNode(elem);
2337 return(cur);
2338 }
2339
2340 if (elem->doc != cur->doc) {
2341 xmlSetTreeDoc(elem, cur->doc);
2342 }
2343 parent = cur->parent;
2344 elem->prev = cur;
2345 elem->next = NULL;
2346 elem->parent = parent;
2347 cur->next = elem;
2348 if (parent != NULL)
2349 parent->last = elem;
2350
2351 return(elem);
2352}
2353
2354/**
2355 * xmlAddChildList:
2356 * @parent: the parent node
2357 * @cur: the first node in the list
2358 *
2359 * Add a list of node at the end of the child list of the parent
2360 * merging adjacent TEXT nodes (@cur may be freed)
2361 *
2362 * Returns the last child or NULL in case of error.
2363 */
2364xmlNodePtr
2365xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2366 xmlNodePtr prev;
2367
2368 if (parent == NULL) {
2369#ifdef DEBUG_TREE
2370 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002371 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002372#endif
2373 return(NULL);
2374 }
2375
2376 if (cur == NULL) {
2377#ifdef DEBUG_TREE
2378 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002379 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002380#endif
2381 return(NULL);
2382 }
2383
2384 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2385 (cur->doc != parent->doc)) {
2386#ifdef DEBUG_TREE
2387 xmlGenericError(xmlGenericErrorContext,
2388 "Elements moved to a different document\n");
2389#endif
2390 }
2391
2392 /*
2393 * add the first element at the end of the children list.
2394 */
2395 if (parent->children == NULL) {
2396 parent->children = cur;
2397 } else {
2398 /*
2399 * If cur and parent->last both are TEXT nodes, then merge them.
2400 */
2401 if ((cur->type == XML_TEXT_NODE) &&
2402 (parent->last->type == XML_TEXT_NODE) &&
2403 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002404 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002405 /*
2406 * if it's the only child, nothing more to be done.
2407 */
2408 if (cur->next == NULL) {
2409 xmlFreeNode(cur);
2410 return(parent->last);
2411 }
2412 prev = cur;
2413 cur = cur->next;
2414 xmlFreeNode(prev);
2415 }
2416 prev = parent->last;
2417 prev->next = cur;
2418 cur->prev = prev;
2419 }
2420 while (cur->next != NULL) {
2421 cur->parent = parent;
2422 if (cur->doc != parent->doc) {
2423 xmlSetTreeDoc(cur, parent->doc);
2424 }
2425 cur = cur->next;
2426 }
2427 cur->parent = parent;
2428 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2429 parent->last = cur;
2430
2431 return(cur);
2432}
2433
2434/**
2435 * xmlAddChild:
2436 * @parent: the parent node
2437 * @cur: the child node
2438 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002439 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002440 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002441 * If the new node was already inserted in a document it is
2442 * first unlinked from its existing context.
2443 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2444 * If there is an attribute with equal name, it is first destroyed.
2445 *
Owen Taylor3473f882001-02-23 17:55:21 +00002446 * Returns the child or NULL in case of error.
2447 */
2448xmlNodePtr
2449xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2450 xmlNodePtr prev;
2451
2452 if (parent == NULL) {
2453#ifdef DEBUG_TREE
2454 xmlGenericError(xmlGenericErrorContext,
2455 "xmlAddChild : parent == NULL\n");
2456#endif
2457 return(NULL);
2458 }
2459
2460 if (cur == NULL) {
2461#ifdef DEBUG_TREE
2462 xmlGenericError(xmlGenericErrorContext,
2463 "xmlAddChild : child == NULL\n");
2464#endif
2465 return(NULL);
2466 }
2467
Owen Taylor3473f882001-02-23 17:55:21 +00002468 /*
2469 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002470 * cur is then freed.
2471 */
2472 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002473 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002474 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002475 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002476 xmlFreeNode(cur);
2477 return(parent);
2478 }
2479 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2480 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002481 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002482 xmlFreeNode(cur);
2483 return(parent->last);
2484 }
2485 }
2486
2487 /*
2488 * add the new element at the end of the children list.
2489 */
2490 cur->parent = parent;
2491 if (cur->doc != parent->doc) {
2492 xmlSetTreeDoc(cur, parent->doc);
2493 }
2494
2495 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002496 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002497 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002498 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002499 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002500 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002501 xmlFreeNode(cur);
2502 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002503 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002504 if (cur->type == XML_ATTRIBUTE_NODE) {
2505 if (parent->properties == NULL) {
2506 parent->properties = (xmlAttrPtr) cur;
2507 } else {
2508 /* check if an attribute with the same name exists */
2509 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002510
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002511 if (cur->ns == NULL)
2512 lastattr = xmlHasProp(parent, cur->name);
2513 else
2514 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2515 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2516 /* different instance, destroy it (attributes must be unique) */
2517 xmlFreeProp(lastattr);
2518 }
2519 /* find the end */
2520 lastattr = parent->properties;
2521 while (lastattr->next != NULL) {
2522 lastattr = lastattr->next;
2523 }
2524 lastattr->next = (xmlAttrPtr) cur;
2525 ((xmlAttrPtr) cur)->prev = lastattr;
2526 }
2527 } else {
2528 if (parent->children == NULL) {
2529 parent->children = cur;
2530 parent->last = cur;
2531 } else {
2532 prev = parent->last;
2533 prev->next = cur;
2534 cur->prev = prev;
2535 parent->last = cur;
2536 }
2537 }
Owen Taylor3473f882001-02-23 17:55:21 +00002538 return(cur);
2539}
2540
2541/**
2542 * xmlGetLastChild:
2543 * @parent: the parent node
2544 *
2545 * Search the last child of a node.
2546 * Returns the last child or NULL if none.
2547 */
2548xmlNodePtr
2549xmlGetLastChild(xmlNodePtr parent) {
2550 if (parent == NULL) {
2551#ifdef DEBUG_TREE
2552 xmlGenericError(xmlGenericErrorContext,
2553 "xmlGetLastChild : parent == NULL\n");
2554#endif
2555 return(NULL);
2556 }
2557 return(parent->last);
2558}
2559
2560/**
2561 * xmlFreeNodeList:
2562 * @cur: the first node in the list
2563 *
2564 * Free a node and all its siblings, this is a recursive behaviour, all
2565 * the children are freed too.
2566 */
2567void
2568xmlFreeNodeList(xmlNodePtr cur) {
2569 xmlNodePtr next;
2570 if (cur == NULL) {
2571#ifdef DEBUG_TREE
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlFreeNodeList : node == NULL\n");
2574#endif
2575 return;
2576 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002577 if (cur->type == XML_NAMESPACE_DECL) {
2578 xmlFreeNsList((xmlNsPtr) cur);
2579 return;
2580 }
Owen Taylor3473f882001-02-23 17:55:21 +00002581 while (cur != NULL) {
2582 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002583 /* unroll to speed up freeing the document */
2584 if (cur->type != XML_DTD_NODE) {
2585 if ((cur->children != NULL) &&
2586 (cur->type != XML_ENTITY_REF_NODE))
2587 xmlFreeNodeList(cur->children);
2588 if (cur->properties != NULL)
2589 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002590 if ((cur->type != XML_ELEMENT_NODE) &&
2591 (cur->type != XML_XINCLUDE_START) &&
2592 (cur->type != XML_XINCLUDE_END) &&
2593 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002594 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002595 }
2596 if (((cur->type == XML_ELEMENT_NODE) ||
2597 (cur->type == XML_XINCLUDE_START) ||
2598 (cur->type == XML_XINCLUDE_END)) &&
2599 (cur->nsDef != NULL))
2600 xmlFreeNsList(cur->nsDef);
2601
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002602 /*
2603 * When a node is a text node or a comment, it uses a global static
2604 * variable for the name of the node.
2605 *
2606 * The xmlStrEqual comparisons need to be done when (happened with
2607 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002608 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002609 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002610 * the string addresses compare are not sufficient.
2611 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002612 if ((cur->name != NULL) &&
2613 (cur->name != xmlStringText) &&
2614 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002615 (cur->name != xmlStringComment)) {
2616 if (cur->type == XML_TEXT_NODE) {
2617 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2618 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2619 xmlFree((char *) cur->name);
2620 } else if (cur->type == XML_COMMENT_NODE) {
2621 if (!xmlStrEqual(cur->name, xmlStringComment))
2622 xmlFree((char *) cur->name);
2623 } else
2624 xmlFree((char *) cur->name);
2625 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002626 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002627 xmlFree(cur);
2628 }
Owen Taylor3473f882001-02-23 17:55:21 +00002629 cur = next;
2630 }
2631}
2632
2633/**
2634 * xmlFreeNode:
2635 * @cur: the node
2636 *
2637 * Free a node, this is a recursive behaviour, all the children are freed too.
2638 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2639 */
2640void
2641xmlFreeNode(xmlNodePtr cur) {
2642 if (cur == NULL) {
2643#ifdef DEBUG_TREE
2644 xmlGenericError(xmlGenericErrorContext,
2645 "xmlFreeNode : node == NULL\n");
2646#endif
2647 return;
2648 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002649 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002650 if (cur->type == XML_DTD_NODE) {
2651 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002652 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002653 }
2654 if (cur->type == XML_NAMESPACE_DECL) {
2655 xmlFreeNs((xmlNsPtr) cur);
2656 return;
2657 }
Owen Taylor3473f882001-02-23 17:55:21 +00002658 if ((cur->children != NULL) &&
2659 (cur->type != XML_ENTITY_REF_NODE))
2660 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002661 if (cur->properties != NULL)
2662 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002663 if ((cur->type != XML_ELEMENT_NODE) &&
2664 (cur->content != NULL) &&
2665 (cur->type != XML_ENTITY_REF_NODE) &&
2666 (cur->type != XML_XINCLUDE_END) &&
2667 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002668 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002669 }
2670
Daniel Veillardacd370f2001-06-09 17:17:51 +00002671 /*
2672 * When a node is a text node or a comment, it uses a global static
2673 * variable for the name of the node.
2674 *
2675 * The xmlStrEqual comparisons need to be done when (happened with
2676 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002677 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002678 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002679 * are not sufficient.
2680 */
Owen Taylor3473f882001-02-23 17:55:21 +00002681 if ((cur->name != NULL) &&
2682 (cur->name != xmlStringText) &&
2683 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002684 (cur->name != xmlStringComment)) {
2685 if (cur->type == XML_TEXT_NODE) {
2686 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2687 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2688 xmlFree((char *) cur->name);
2689 } else if (cur->type == XML_COMMENT_NODE) {
2690 if (!xmlStrEqual(cur->name, xmlStringComment))
2691 xmlFree((char *) cur->name);
2692 } else
2693 xmlFree((char *) cur->name);
2694 }
2695
Owen Taylor3473f882001-02-23 17:55:21 +00002696 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002697 xmlFree(cur);
2698}
2699
2700/**
2701 * xmlUnlinkNode:
2702 * @cur: the node
2703 *
2704 * Unlink a node from it's current context, the node is not freed
2705 */
2706void
2707xmlUnlinkNode(xmlNodePtr cur) {
2708 if (cur == NULL) {
2709#ifdef DEBUG_TREE
2710 xmlGenericError(xmlGenericErrorContext,
2711 "xmlUnlinkNode : node == NULL\n");
2712#endif
2713 return;
2714 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002715 if (cur->type == XML_DTD_NODE) {
2716 xmlDocPtr doc;
2717 doc = cur->doc;
2718 if (doc->intSubset == (xmlDtdPtr) cur)
2719 doc->intSubset = NULL;
2720 if (doc->extSubset == (xmlDtdPtr) cur)
2721 doc->extSubset = NULL;
2722 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002723 if (cur->parent != NULL) {
2724 xmlNodePtr parent;
2725 parent = cur->parent;
2726 if (cur->type == XML_ATTRIBUTE_NODE) {
2727 if (parent->properties == (xmlAttrPtr) cur)
2728 parent->properties = ((xmlAttrPtr) cur)->next;
2729 } else {
2730 if (parent->children == cur)
2731 parent->children = cur->next;
2732 if (parent->last == cur)
2733 parent->last = cur->prev;
2734 }
2735 cur->parent = NULL;
2736 }
Owen Taylor3473f882001-02-23 17:55:21 +00002737 if (cur->next != NULL)
2738 cur->next->prev = cur->prev;
2739 if (cur->prev != NULL)
2740 cur->prev->next = cur->next;
2741 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002742}
2743
2744/**
2745 * xmlReplaceNode:
2746 * @old: the old node
2747 * @cur: the node
2748 *
2749 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002750 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002751 * first unlinked from its existing context.
2752 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002753 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002754 */
2755xmlNodePtr
2756xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2757 if (old == NULL) {
2758#ifdef DEBUG_TREE
2759 xmlGenericError(xmlGenericErrorContext,
2760 "xmlReplaceNode : old == NULL\n");
2761#endif
2762 return(NULL);
2763 }
2764 if (cur == NULL) {
2765 xmlUnlinkNode(old);
2766 return(old);
2767 }
2768 if (cur == old) {
2769 return(old);
2770 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002771 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2772#ifdef DEBUG_TREE
2773 xmlGenericError(xmlGenericErrorContext,
2774 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2775#endif
2776 return(old);
2777 }
2778 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2779#ifdef DEBUG_TREE
2780 xmlGenericError(xmlGenericErrorContext,
2781 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2782#endif
2783 return(old);
2784 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002785 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2786#ifdef DEBUG_TREE
2787 xmlGenericError(xmlGenericErrorContext,
2788 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2789#endif
2790 return(old);
2791 }
2792 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2793#ifdef DEBUG_TREE
2794 xmlGenericError(xmlGenericErrorContext,
2795 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2796#endif
2797 return(old);
2798 }
Owen Taylor3473f882001-02-23 17:55:21 +00002799 xmlUnlinkNode(cur);
2800 cur->doc = old->doc;
2801 cur->parent = old->parent;
2802 cur->next = old->next;
2803 if (cur->next != NULL)
2804 cur->next->prev = cur;
2805 cur->prev = old->prev;
2806 if (cur->prev != NULL)
2807 cur->prev->next = cur;
2808 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002809 if (cur->type == XML_ATTRIBUTE_NODE) {
2810 if (cur->parent->properties == (xmlAttrPtr)old)
2811 cur->parent->properties = ((xmlAttrPtr) cur);
2812 } else {
2813 if (cur->parent->children == old)
2814 cur->parent->children = cur;
2815 if (cur->parent->last == old)
2816 cur->parent->last = cur;
2817 }
Owen Taylor3473f882001-02-23 17:55:21 +00002818 }
2819 old->next = old->prev = NULL;
2820 old->parent = NULL;
2821 return(old);
2822}
2823
2824/************************************************************************
2825 * *
2826 * Copy operations *
2827 * *
2828 ************************************************************************/
2829
2830/**
2831 * xmlCopyNamespace:
2832 * @cur: the namespace
2833 *
2834 * Do a copy of the namespace.
2835 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002836 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002837 */
2838xmlNsPtr
2839xmlCopyNamespace(xmlNsPtr cur) {
2840 xmlNsPtr ret;
2841
2842 if (cur == NULL) return(NULL);
2843 switch (cur->type) {
2844 case XML_LOCAL_NAMESPACE:
2845 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2846 break;
2847 default:
2848#ifdef DEBUG_TREE
2849 xmlGenericError(xmlGenericErrorContext,
2850 "xmlCopyNamespace: invalid type %d\n", cur->type);
2851#endif
2852 return(NULL);
2853 }
2854 return(ret);
2855}
2856
2857/**
2858 * xmlCopyNamespaceList:
2859 * @cur: the first namespace
2860 *
2861 * Do a copy of an namespace list.
2862 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002863 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002864 */
2865xmlNsPtr
2866xmlCopyNamespaceList(xmlNsPtr cur) {
2867 xmlNsPtr ret = NULL;
2868 xmlNsPtr p = NULL,q;
2869
2870 while (cur != NULL) {
2871 q = xmlCopyNamespace(cur);
2872 if (p == NULL) {
2873 ret = p = q;
2874 } else {
2875 p->next = q;
2876 p = q;
2877 }
2878 cur = cur->next;
2879 }
2880 return(ret);
2881}
2882
2883static xmlNodePtr
2884xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2885/**
2886 * xmlCopyProp:
2887 * @target: the element where the attribute will be grafted
2888 * @cur: the attribute
2889 *
2890 * Do a copy of the attribute.
2891 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002892 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002893 */
2894xmlAttrPtr
2895xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2896 xmlAttrPtr ret;
2897
2898 if (cur == NULL) return(NULL);
2899 if (target != NULL)
2900 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2901 else if (cur->parent != NULL)
2902 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2903 else if (cur->children != NULL)
2904 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2905 else
2906 ret = xmlNewDocProp(NULL, cur->name, NULL);
2907 if (ret == NULL) return(NULL);
2908 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002909
Owen Taylor3473f882001-02-23 17:55:21 +00002910 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002911 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002912/*
2913 * if (target->doc)
2914 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2915 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2916 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2917 * else
2918 * ns = NULL;
2919 * ret->ns = ns;
2920 */
2921 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2922 if (ns == NULL) {
2923 /*
2924 * Humm, we are copying an element whose namespace is defined
2925 * out of the new tree scope. Search it in the original tree
2926 * and add it at the top of the new tree
2927 */
2928 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2929 if (ns != NULL) {
2930 xmlNodePtr root = target;
2931 xmlNodePtr pred = NULL;
2932
2933 while (root->parent != NULL) {
2934 pred = root;
2935 root = root->parent;
2936 }
2937 if (root == (xmlNodePtr) target->doc) {
2938 /* correct possibly cycling above the document elt */
2939 root = pred;
2940 }
2941 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2942 }
2943 } else {
2944 /*
2945 * we have to find something appropriate here since
2946 * we cant be sure, that the namespce we found is identified
2947 * by the prefix
2948 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002949 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002950 /* this is the nice case */
2951 ret->ns = ns;
2952 } else {
2953 /*
2954 * we are in trouble: we need a new reconcilied namespace.
2955 * This is expensive
2956 */
2957 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2958 }
2959 }
2960
Owen Taylor3473f882001-02-23 17:55:21 +00002961 } else
2962 ret->ns = NULL;
2963
2964 if (cur->children != NULL) {
2965 xmlNodePtr tmp;
2966
2967 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2968 ret->last = NULL;
2969 tmp = ret->children;
2970 while (tmp != NULL) {
2971 /* tmp->parent = (xmlNodePtr)ret; */
2972 if (tmp->next == NULL)
2973 ret->last = tmp;
2974 tmp = tmp->next;
2975 }
2976 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002977 /*
2978 * Try to handle IDs
2979 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002980 if ((target!= NULL) && (cur!= NULL) &&
2981 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002982 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2983 if (xmlIsID(cur->doc, cur->parent, cur)) {
2984 xmlChar *id;
2985
2986 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2987 if (id != NULL) {
2988 xmlAddID(NULL, target->doc, id, ret);
2989 xmlFree(id);
2990 }
2991 }
2992 }
Owen Taylor3473f882001-02-23 17:55:21 +00002993 return(ret);
2994}
2995
2996/**
2997 * xmlCopyPropList:
2998 * @target: the element where the attributes will be grafted
2999 * @cur: the first attribute
3000 *
3001 * Do a copy of an attribute list.
3002 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003003 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003004 */
3005xmlAttrPtr
3006xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3007 xmlAttrPtr ret = NULL;
3008 xmlAttrPtr p = NULL,q;
3009
3010 while (cur != NULL) {
3011 q = xmlCopyProp(target, cur);
3012 if (p == NULL) {
3013 ret = p = q;
3014 } else {
3015 p->next = q;
3016 q->prev = p;
3017 p = q;
3018 }
3019 cur = cur->next;
3020 }
3021 return(ret);
3022}
3023
3024/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003025 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003026 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003027 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003028 * tricky reason: namespaces. Doing a direct copy of a node
3029 * say RPM:Copyright without changing the namespace pointer to
3030 * something else can produce stale links. One way to do it is
3031 * to keep a reference counter but this doesn't work as soon
3032 * as one move the element or the subtree out of the scope of
3033 * the existing namespace. The actual solution seems to add
3034 * a copy of the namespace at the top of the copied tree if
3035 * not available in the subtree.
3036 * Hence two functions, the public front-end call the inner ones
3037 */
3038
3039static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003040xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003041 int recursive) {
3042 xmlNodePtr ret;
3043
3044 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003045 switch (node->type) {
3046 case XML_TEXT_NODE:
3047 case XML_CDATA_SECTION_NODE:
3048 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003049 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003050 case XML_ENTITY_REF_NODE:
3051 case XML_ENTITY_NODE:
3052 case XML_PI_NODE:
3053 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003054 case XML_XINCLUDE_START:
3055 case XML_XINCLUDE_END:
3056 break;
3057 case XML_ATTRIBUTE_NODE:
3058 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3059 case XML_NAMESPACE_DECL:
3060 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3061
Daniel Veillard39196eb2001-06-19 18:09:42 +00003062 case XML_DOCUMENT_NODE:
3063 case XML_HTML_DOCUMENT_NODE:
3064#ifdef LIBXML_DOCB_ENABLED
3065 case XML_DOCB_DOCUMENT_NODE:
3066#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003067 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003068 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003069 case XML_NOTATION_NODE:
3070 case XML_DTD_NODE:
3071 case XML_ELEMENT_DECL:
3072 case XML_ATTRIBUTE_DECL:
3073 case XML_ENTITY_DECL:
3074 return(NULL);
3075 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003076
Owen Taylor3473f882001-02-23 17:55:21 +00003077 /*
3078 * Allocate a new node and fill the fields.
3079 */
3080 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3081 if (ret == NULL) {
3082 xmlGenericError(xmlGenericErrorContext,
3083 "xmlStaticCopyNode : malloc failed\n");
3084 return(NULL);
3085 }
3086 memset(ret, 0, sizeof(xmlNode));
3087 ret->type = node->type;
3088
3089 ret->doc = doc;
3090 ret->parent = parent;
3091 if (node->name == xmlStringText)
3092 ret->name = xmlStringText;
3093 else if (node->name == xmlStringTextNoenc)
3094 ret->name = xmlStringTextNoenc;
3095 else if (node->name == xmlStringComment)
3096 ret->name = xmlStringComment;
3097 else if (node->name != NULL)
3098 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003099 if ((node->type != XML_ELEMENT_NODE) &&
3100 (node->content != NULL) &&
3101 (node->type != XML_ENTITY_REF_NODE) &&
3102 (node->type != XML_XINCLUDE_END) &&
3103 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003104 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003105 }else{
3106 if (node->type == XML_ELEMENT_NODE)
3107 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003108 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003109 if (parent != NULL) {
3110 xmlNodePtr tmp;
3111
3112 tmp = xmlAddChild(parent, ret);
3113 /* node could have coalesced */
3114 if (tmp != ret)
3115 return(tmp);
3116 }
Owen Taylor3473f882001-02-23 17:55:21 +00003117
3118 if (!recursive) return(ret);
3119 if (node->nsDef != NULL)
3120 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3121
3122 if (node->ns != NULL) {
3123 xmlNsPtr ns;
3124
3125 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3126 if (ns == NULL) {
3127 /*
3128 * Humm, we are copying an element whose namespace is defined
3129 * out of the new tree scope. Search it in the original tree
3130 * and add it at the top of the new tree
3131 */
3132 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3133 if (ns != NULL) {
3134 xmlNodePtr root = ret;
3135
3136 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003137 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003138 }
3139 } else {
3140 /*
3141 * reference the existing namespace definition in our own tree.
3142 */
3143 ret->ns = ns;
3144 }
3145 }
3146 if (node->properties != NULL)
3147 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003148 if (node->type == XML_ENTITY_REF_NODE) {
3149 if ((doc == NULL) || (node->doc != doc)) {
3150 /*
3151 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003152 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003153 * we cannot keep the reference. Try to find it in the
3154 * target document.
3155 */
3156 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3157 } else {
3158 ret->children = node->children;
3159 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003160 ret->last = ret->children;
3161 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003162 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003163 UPDATE_LAST_CHILD_AND_PARENT(ret)
3164 }
Owen Taylor3473f882001-02-23 17:55:21 +00003165 return(ret);
3166}
3167
3168static xmlNodePtr
3169xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3170 xmlNodePtr ret = NULL;
3171 xmlNodePtr p = NULL,q;
3172
3173 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003174 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003175 if (doc == NULL) {
3176 node = node->next;
3177 continue;
3178 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003179 if (doc->intSubset == NULL) {
3180 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3181 q->doc = doc;
3182 q->parent = parent;
3183 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003184 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003185 } else {
3186 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003187 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003188 }
3189 } else
3190 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003191 if (ret == NULL) {
3192 q->prev = NULL;
3193 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003194 } else if (p != q) {
3195 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003196 p->next = q;
3197 q->prev = p;
3198 p = q;
3199 }
3200 node = node->next;
3201 }
3202 return(ret);
3203}
3204
3205/**
3206 * xmlCopyNode:
3207 * @node: the node
3208 * @recursive: if 1 do a recursive copy.
3209 *
3210 * Do a copy of the node.
3211 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003212 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003213 */
3214xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003215xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003216 xmlNodePtr ret;
3217
3218 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3219 return(ret);
3220}
3221
3222/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003223 * xmlDocCopyNode:
3224 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003225 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003226 * @recursive: if 1 do a recursive copy.
3227 *
3228 * Do a copy of the node to a given document.
3229 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003230 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003231 */
3232xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003233xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003234 xmlNodePtr ret;
3235
3236 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3237 return(ret);
3238}
3239
3240/**
Owen Taylor3473f882001-02-23 17:55:21 +00003241 * xmlCopyNodeList:
3242 * @node: the first node in the list.
3243 *
3244 * Do a recursive copy of the node list.
3245 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003246 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003247 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003248xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003249 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3250 return(ret);
3251}
3252
3253/**
Owen Taylor3473f882001-02-23 17:55:21 +00003254 * xmlCopyDtd:
3255 * @dtd: the dtd
3256 *
3257 * Do a copy of the dtd.
3258 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003259 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003260 */
3261xmlDtdPtr
3262xmlCopyDtd(xmlDtdPtr dtd) {
3263 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003264 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003265
3266 if (dtd == NULL) return(NULL);
3267 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3268 if (ret == NULL) return(NULL);
3269 if (dtd->entities != NULL)
3270 ret->entities = (void *) xmlCopyEntitiesTable(
3271 (xmlEntitiesTablePtr) dtd->entities);
3272 if (dtd->notations != NULL)
3273 ret->notations = (void *) xmlCopyNotationTable(
3274 (xmlNotationTablePtr) dtd->notations);
3275 if (dtd->elements != NULL)
3276 ret->elements = (void *) xmlCopyElementTable(
3277 (xmlElementTablePtr) dtd->elements);
3278 if (dtd->attributes != NULL)
3279 ret->attributes = (void *) xmlCopyAttributeTable(
3280 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003281 if (dtd->pentities != NULL)
3282 ret->pentities = (void *) xmlCopyEntitiesTable(
3283 (xmlEntitiesTablePtr) dtd->pentities);
3284
3285 cur = dtd->children;
3286 while (cur != NULL) {
3287 q = NULL;
3288
3289 if (cur->type == XML_ENTITY_DECL) {
3290 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3291 switch (tmp->etype) {
3292 case XML_INTERNAL_GENERAL_ENTITY:
3293 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3294 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3295 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3296 break;
3297 case XML_INTERNAL_PARAMETER_ENTITY:
3298 case XML_EXTERNAL_PARAMETER_ENTITY:
3299 q = (xmlNodePtr)
3300 xmlGetParameterEntityFromDtd(ret, tmp->name);
3301 break;
3302 case XML_INTERNAL_PREDEFINED_ENTITY:
3303 break;
3304 }
3305 } else if (cur->type == XML_ELEMENT_DECL) {
3306 xmlElementPtr tmp = (xmlElementPtr) cur;
3307 q = (xmlNodePtr)
3308 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3309 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3310 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3311 q = (xmlNodePtr)
3312 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3313 } else if (cur->type == XML_COMMENT_NODE) {
3314 q = xmlCopyNode(cur, 0);
3315 }
3316
3317 if (q == NULL) {
3318 cur = cur->next;
3319 continue;
3320 }
3321
3322 if (p == NULL)
3323 ret->children = q;
3324 else
3325 p->next = q;
3326
3327 q->prev = p;
3328 q->parent = (xmlNodePtr) ret;
3329 q->next = NULL;
3330 ret->last = q;
3331 p = q;
3332 cur = cur->next;
3333 }
3334
Owen Taylor3473f882001-02-23 17:55:21 +00003335 return(ret);
3336}
3337
3338/**
3339 * xmlCopyDoc:
3340 * @doc: the document
3341 * @recursive: if 1 do a recursive copy.
3342 *
3343 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003344 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003345 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003346 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003347 */
3348xmlDocPtr
3349xmlCopyDoc(xmlDocPtr doc, int recursive) {
3350 xmlDocPtr ret;
3351
3352 if (doc == NULL) return(NULL);
3353 ret = xmlNewDoc(doc->version);
3354 if (ret == NULL) return(NULL);
3355 if (doc->name != NULL)
3356 ret->name = xmlMemStrdup(doc->name);
3357 if (doc->encoding != NULL)
3358 ret->encoding = xmlStrdup(doc->encoding);
3359 ret->charset = doc->charset;
3360 ret->compression = doc->compression;
3361 ret->standalone = doc->standalone;
3362 if (!recursive) return(ret);
3363
Daniel Veillardb33c2012001-04-25 12:59:04 +00003364 ret->last = NULL;
3365 ret->children = NULL;
3366 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003367 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003368 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003369 ret->intSubset->parent = ret;
3370 }
Owen Taylor3473f882001-02-23 17:55:21 +00003371 if (doc->oldNs != NULL)
3372 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3373 if (doc->children != NULL) {
3374 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003375
3376 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3377 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003378 ret->last = NULL;
3379 tmp = ret->children;
3380 while (tmp != NULL) {
3381 if (tmp->next == NULL)
3382 ret->last = tmp;
3383 tmp = tmp->next;
3384 }
3385 }
3386 return(ret);
3387}
3388
3389/************************************************************************
3390 * *
3391 * Content access functions *
3392 * *
3393 ************************************************************************/
3394
3395/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003396 * xmlGetLineNo:
3397 * @node : valid node
3398 *
3399 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003400 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003401 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003402 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003403 */
3404long
3405xmlGetLineNo(xmlNodePtr node)
3406{
3407 long result = -1;
3408
3409 if (!node)
3410 return result;
3411 if (node->type == XML_ELEMENT_NODE)
3412 result = (long) node->content;
3413 else if ((node->prev != NULL) &&
3414 ((node->prev->type == XML_ELEMENT_NODE) ||
3415 (node->prev->type == XML_TEXT_NODE)))
3416 result = xmlGetLineNo(node->prev);
3417 else if ((node->parent != NULL) &&
3418 ((node->parent->type == XML_ELEMENT_NODE) ||
3419 (node->parent->type == XML_TEXT_NODE)))
3420 result = xmlGetLineNo(node->parent);
3421
3422 return result;
3423}
3424
3425/**
3426 * xmlGetNodePath:
3427 * @node: a node
3428 *
3429 * Build a structure based Path for the given node
3430 *
3431 * Returns the new path or NULL in case of error. The caller must free
3432 * the returned string
3433 */
3434xmlChar *
3435xmlGetNodePath(xmlNodePtr node)
3436{
3437 xmlNodePtr cur, tmp, next;
3438 xmlChar *buffer = NULL, *temp;
3439 size_t buf_len;
3440 xmlChar *buf;
3441 char sep;
3442 const char *name;
3443 char nametemp[100];
3444 int occur = 0;
3445
3446 if (node == NULL)
3447 return (NULL);
3448
3449 buf_len = 500;
3450 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3451 if (buffer == NULL)
3452 return (NULL);
3453 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3454 if (buf == NULL) {
3455 xmlFree(buffer);
3456 return (NULL);
3457 }
3458
3459 buffer[0] = 0;
3460 cur = node;
3461 do {
3462 name = "";
3463 sep = '?';
3464 occur = 0;
3465 if ((cur->type == XML_DOCUMENT_NODE) ||
3466 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3467 if (buffer[0] == '/')
3468 break;
3469 sep = '/';
3470 next = NULL;
3471 } else if (cur->type == XML_ELEMENT_NODE) {
3472 sep = '/';
3473 name = (const char *) cur->name;
3474 if (cur->ns) {
3475 snprintf(nametemp, sizeof(nametemp) - 1,
3476 "%s:%s", cur->ns->prefix, cur->name);
3477 nametemp[sizeof(nametemp) - 1] = 0;
3478 name = nametemp;
3479 }
3480 next = cur->parent;
3481
3482 /*
3483 * Thumbler index computation
3484 */
3485 tmp = cur->prev;
3486 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003487 if ((tmp->type == XML_ELEMENT_NODE) &&
3488 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003489 occur++;
3490 tmp = tmp->prev;
3491 }
3492 if (occur == 0) {
3493 tmp = cur->next;
3494 while (tmp != NULL) {
3495 if (xmlStrEqual(cur->name, tmp->name))
3496 occur++;
3497 tmp = tmp->next;
3498 }
3499 if (occur != 0)
3500 occur = 1;
3501 } else
3502 occur++;
3503 } else if (cur->type == XML_ATTRIBUTE_NODE) {
3504 sep = '@';
3505 name = (const char *) (((xmlAttrPtr) cur)->name);
3506 next = ((xmlAttrPtr) cur)->parent;
3507 } else {
3508 next = cur->parent;
3509 }
3510
3511 /*
3512 * Make sure there is enough room
3513 */
3514 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3515 buf_len =
3516 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3517 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3518 if (temp == NULL) {
3519 xmlFree(buf);
3520 xmlFree(buffer);
3521 return (NULL);
3522 }
3523 buffer = temp;
3524 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3525 if (temp == NULL) {
3526 xmlFree(buf);
3527 xmlFree(buffer);
3528 return (NULL);
3529 }
3530 buf = temp;
3531 }
3532 if (occur == 0)
3533 snprintf((char *) buf, buf_len, "%c%s%s",
3534 sep, name, (char *) buffer);
3535 else
3536 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
3537 sep, name, occur, (char *) buffer);
3538 snprintf((char *) buffer, buf_len, "%s", buf);
3539 cur = next;
3540 } while (cur != NULL);
3541 xmlFree(buf);
3542 return (buffer);
3543}
3544
3545/**
Owen Taylor3473f882001-02-23 17:55:21 +00003546 * xmlDocGetRootElement:
3547 * @doc: the document
3548 *
3549 * Get the root element of the document (doc->children is a list
3550 * containing possibly comments, PIs, etc ...).
3551 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003552 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003553 */
3554xmlNodePtr
3555xmlDocGetRootElement(xmlDocPtr doc) {
3556 xmlNodePtr ret;
3557
3558 if (doc == NULL) return(NULL);
3559 ret = doc->children;
3560 while (ret != NULL) {
3561 if (ret->type == XML_ELEMENT_NODE)
3562 return(ret);
3563 ret = ret->next;
3564 }
3565 return(ret);
3566}
3567
3568/**
3569 * xmlDocSetRootElement:
3570 * @doc: the document
3571 * @root: the new document root element
3572 *
3573 * Set the root element of the document (doc->children is a list
3574 * containing possibly comments, PIs, etc ...).
3575 *
3576 * Returns the old root element if any was found
3577 */
3578xmlNodePtr
3579xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3580 xmlNodePtr old = NULL;
3581
3582 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003583 if (root == NULL)
3584 return(NULL);
3585 xmlUnlinkNode(root);
3586 root->doc = doc;
3587 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003588 old = doc->children;
3589 while (old != NULL) {
3590 if (old->type == XML_ELEMENT_NODE)
3591 break;
3592 old = old->next;
3593 }
3594 if (old == NULL) {
3595 if (doc->children == NULL) {
3596 doc->children = root;
3597 doc->last = root;
3598 } else {
3599 xmlAddSibling(doc->children, root);
3600 }
3601 } else {
3602 xmlReplaceNode(old, root);
3603 }
3604 return(old);
3605}
3606
3607/**
3608 * xmlNodeSetLang:
3609 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003610 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003611 *
3612 * Set the language of a node, i.e. the values of the xml:lang
3613 * attribute.
3614 */
3615void
3616xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003617 xmlNsPtr ns;
3618
Owen Taylor3473f882001-02-23 17:55:21 +00003619 if (cur == NULL) return;
3620 switch(cur->type) {
3621 case XML_TEXT_NODE:
3622 case XML_CDATA_SECTION_NODE:
3623 case XML_COMMENT_NODE:
3624 case XML_DOCUMENT_NODE:
3625 case XML_DOCUMENT_TYPE_NODE:
3626 case XML_DOCUMENT_FRAG_NODE:
3627 case XML_NOTATION_NODE:
3628 case XML_HTML_DOCUMENT_NODE:
3629 case XML_DTD_NODE:
3630 case XML_ELEMENT_DECL:
3631 case XML_ATTRIBUTE_DECL:
3632 case XML_ENTITY_DECL:
3633 case XML_PI_NODE:
3634 case XML_ENTITY_REF_NODE:
3635 case XML_ENTITY_NODE:
3636 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003637#ifdef LIBXML_DOCB_ENABLED
3638 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003639#endif
3640 case XML_XINCLUDE_START:
3641 case XML_XINCLUDE_END:
3642 return;
3643 case XML_ELEMENT_NODE:
3644 case XML_ATTRIBUTE_NODE:
3645 break;
3646 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003647 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3648 if (ns == NULL)
3649 return;
3650 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003651}
3652
3653/**
3654 * xmlNodeGetLang:
3655 * @cur: the node being checked
3656 *
3657 * Searches the language of a node, i.e. the values of the xml:lang
3658 * attribute or the one carried by the nearest ancestor.
3659 *
3660 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003661 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003662 */
3663xmlChar *
3664xmlNodeGetLang(xmlNodePtr cur) {
3665 xmlChar *lang;
3666
3667 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003668 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003669 if (lang != NULL)
3670 return(lang);
3671 cur = cur->parent;
3672 }
3673 return(NULL);
3674}
3675
3676
3677/**
3678 * xmlNodeSetSpacePreserve:
3679 * @cur: the node being changed
3680 * @val: the xml:space value ("0": default, 1: "preserve")
3681 *
3682 * Set (or reset) the space preserving behaviour of a node, i.e. the
3683 * value of the xml:space attribute.
3684 */
3685void
3686xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003687 xmlNsPtr ns;
3688
Owen Taylor3473f882001-02-23 17:55:21 +00003689 if (cur == NULL) return;
3690 switch(cur->type) {
3691 case XML_TEXT_NODE:
3692 case XML_CDATA_SECTION_NODE:
3693 case XML_COMMENT_NODE:
3694 case XML_DOCUMENT_NODE:
3695 case XML_DOCUMENT_TYPE_NODE:
3696 case XML_DOCUMENT_FRAG_NODE:
3697 case XML_NOTATION_NODE:
3698 case XML_HTML_DOCUMENT_NODE:
3699 case XML_DTD_NODE:
3700 case XML_ELEMENT_DECL:
3701 case XML_ATTRIBUTE_DECL:
3702 case XML_ENTITY_DECL:
3703 case XML_PI_NODE:
3704 case XML_ENTITY_REF_NODE:
3705 case XML_ENTITY_NODE:
3706 case XML_NAMESPACE_DECL:
3707 case XML_XINCLUDE_START:
3708 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003709#ifdef LIBXML_DOCB_ENABLED
3710 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003711#endif
3712 return;
3713 case XML_ELEMENT_NODE:
3714 case XML_ATTRIBUTE_NODE:
3715 break;
3716 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003717 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3718 if (ns == NULL)
3719 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003720 switch (val) {
3721 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003722 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003723 break;
3724 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003725 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003726 break;
3727 }
3728}
3729
3730/**
3731 * xmlNodeGetSpacePreserve:
3732 * @cur: the node being checked
3733 *
3734 * Searches the space preserving behaviour of a node, i.e. the values
3735 * of the xml:space attribute or the one carried by the nearest
3736 * ancestor.
3737 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003738 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003739 */
3740int
3741xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3742 xmlChar *space;
3743
3744 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003745 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003746 if (space != NULL) {
3747 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3748 xmlFree(space);
3749 return(1);
3750 }
3751 if (xmlStrEqual(space, BAD_CAST "default")) {
3752 xmlFree(space);
3753 return(0);
3754 }
3755 xmlFree(space);
3756 }
3757 cur = cur->parent;
3758 }
3759 return(-1);
3760}
3761
3762/**
3763 * xmlNodeSetName:
3764 * @cur: the node being changed
3765 * @name: the new tag name
3766 *
3767 * Set (or reset) the name of a node.
3768 */
3769void
3770xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3771 if (cur == NULL) return;
3772 if (name == NULL) return;
3773 switch(cur->type) {
3774 case XML_TEXT_NODE:
3775 case XML_CDATA_SECTION_NODE:
3776 case XML_COMMENT_NODE:
3777 case XML_DOCUMENT_TYPE_NODE:
3778 case XML_DOCUMENT_FRAG_NODE:
3779 case XML_NOTATION_NODE:
3780 case XML_HTML_DOCUMENT_NODE:
3781 case XML_NAMESPACE_DECL:
3782 case XML_XINCLUDE_START:
3783 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003784#ifdef LIBXML_DOCB_ENABLED
3785 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003786#endif
3787 return;
3788 case XML_ELEMENT_NODE:
3789 case XML_ATTRIBUTE_NODE:
3790 case XML_PI_NODE:
3791 case XML_ENTITY_REF_NODE:
3792 case XML_ENTITY_NODE:
3793 case XML_DTD_NODE:
3794 case XML_DOCUMENT_NODE:
3795 case XML_ELEMENT_DECL:
3796 case XML_ATTRIBUTE_DECL:
3797 case XML_ENTITY_DECL:
3798 break;
3799 }
3800 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3801 cur->name = xmlStrdup(name);
3802}
3803
3804/**
3805 * xmlNodeSetBase:
3806 * @cur: the node being changed
3807 * @uri: the new base URI
3808 *
3809 * Set (or reset) the base URI of a node, i.e. the value of the
3810 * xml:base attribute.
3811 */
3812void
3813xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003814 xmlNsPtr ns;
3815
Owen Taylor3473f882001-02-23 17:55:21 +00003816 if (cur == NULL) return;
3817 switch(cur->type) {
3818 case XML_TEXT_NODE:
3819 case XML_CDATA_SECTION_NODE:
3820 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003821 case XML_DOCUMENT_TYPE_NODE:
3822 case XML_DOCUMENT_FRAG_NODE:
3823 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003824 case XML_DTD_NODE:
3825 case XML_ELEMENT_DECL:
3826 case XML_ATTRIBUTE_DECL:
3827 case XML_ENTITY_DECL:
3828 case XML_PI_NODE:
3829 case XML_ENTITY_REF_NODE:
3830 case XML_ENTITY_NODE:
3831 case XML_NAMESPACE_DECL:
3832 case XML_XINCLUDE_START:
3833 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003834 return;
3835 case XML_ELEMENT_NODE:
3836 case XML_ATTRIBUTE_NODE:
3837 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003838 case XML_DOCUMENT_NODE:
3839#ifdef LIBXML_DOCB_ENABLED
3840 case XML_DOCB_DOCUMENT_NODE:
3841#endif
3842 case XML_HTML_DOCUMENT_NODE: {
3843 xmlDocPtr doc = (xmlDocPtr) cur;
3844
3845 if (doc->URL != NULL)
3846 xmlFree((xmlChar *) doc->URL);
3847 if (uri == NULL)
3848 doc->URL = NULL;
3849 else
3850 doc->URL = xmlStrdup(uri);
3851 return;
3852 }
Owen Taylor3473f882001-02-23 17:55:21 +00003853 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003854
3855 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3856 if (ns == NULL)
3857 return;
3858 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003859}
3860
3861/**
Owen Taylor3473f882001-02-23 17:55:21 +00003862 * xmlNodeGetBase:
3863 * @doc: the document the node pertains to
3864 * @cur: the node being checked
3865 *
3866 * Searches for the BASE URL. The code should work on both XML
3867 * and HTML document even if base mechanisms are completely different.
3868 * It returns the base as defined in RFC 2396 sections
3869 * 5.1.1. Base URI within Document Content
3870 * and
3871 * 5.1.2. Base URI from the Encapsulating Entity
3872 * However it does not return the document base (5.1.3), use
3873 * xmlDocumentGetBase() for this
3874 *
3875 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003876 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003877 */
3878xmlChar *
3879xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003880 xmlChar *oldbase = NULL;
3881 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003882
3883 if ((cur == NULL) && (doc == NULL))
3884 return(NULL);
3885 if (doc == NULL) doc = cur->doc;
3886 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3887 cur = doc->children;
3888 while ((cur != NULL) && (cur->name != NULL)) {
3889 if (cur->type != XML_ELEMENT_NODE) {
3890 cur = cur->next;
3891 continue;
3892 }
3893 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3894 cur = cur->children;
3895 continue;
3896 }
3897 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3898 cur = cur->children;
3899 continue;
3900 }
3901 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3902 return(xmlGetProp(cur, BAD_CAST "href"));
3903 }
3904 cur = cur->next;
3905 }
3906 return(NULL);
3907 }
3908 while (cur != NULL) {
3909 if (cur->type == XML_ENTITY_DECL) {
3910 xmlEntityPtr ent = (xmlEntityPtr) cur;
3911 return(xmlStrdup(ent->URI));
3912 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00003913 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003914 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003915 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003916 if (oldbase != NULL) {
3917 newbase = xmlBuildURI(oldbase, base);
3918 if (newbase != NULL) {
3919 xmlFree(oldbase);
3920 xmlFree(base);
3921 oldbase = newbase;
3922 } else {
3923 xmlFree(oldbase);
3924 xmlFree(base);
3925 return(NULL);
3926 }
3927 } else {
3928 oldbase = base;
3929 }
3930 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
3931 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
3932 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
3933 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00003934 }
3935 }
Owen Taylor3473f882001-02-23 17:55:21 +00003936 cur = cur->parent;
3937 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003938 if ((doc != NULL) && (doc->URL != NULL)) {
3939 if (oldbase == NULL)
3940 return(xmlStrdup(doc->URL));
3941 newbase = xmlBuildURI(oldbase, doc->URL);
3942 xmlFree(oldbase);
3943 return(newbase);
3944 }
3945 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00003946}
3947
3948/**
3949 * xmlNodeGetContent:
3950 * @cur: the node being read
3951 *
3952 * Read the value of a node, this can be either the text carried
3953 * directly by this node if it's a TEXT node or the aggregate string
3954 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00003955 * Entity references are substituted.
3956 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003957 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003958 */
3959xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00003960xmlNodeGetContent(xmlNodePtr cur)
3961{
3962 if (cur == NULL)
3963 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003964 switch (cur->type) {
3965 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00003966 case XML_ELEMENT_NODE:{
3967 xmlNodePtr tmp = cur;
3968 xmlBufferPtr buffer;
3969 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003970
Daniel Veillard7646b182002-04-20 06:41:40 +00003971 buffer = xmlBufferCreate();
3972 if (buffer == NULL)
3973 return (NULL);
3974 while (tmp != NULL) {
3975 switch (tmp->type) {
3976 case XML_CDATA_SECTION_NODE:
3977 case XML_TEXT_NODE:
3978 if (tmp->content != NULL)
3979 xmlBufferCat(buffer, tmp->content);
3980 break;
3981 case XML_ENTITY_REF_NODE:{
3982 /* recursive substitution of entity references */
3983 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003984
Daniel Veillard7646b182002-04-20 06:41:40 +00003985 if (cont) {
3986 xmlBufferCat(buffer,
3987 (const xmlChar *) cont);
3988 xmlFree(cont);
3989 }
3990 break;
3991 }
3992 default:
3993 break;
3994 }
3995 /*
3996 * Skip to next node
3997 */
3998 if (tmp->children != NULL) {
3999 if (tmp->children->type != XML_ENTITY_DECL) {
4000 tmp = tmp->children;
4001 continue;
4002 }
4003 }
4004 if (tmp == cur)
4005 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004006
Daniel Veillard7646b182002-04-20 06:41:40 +00004007 if (tmp->next != NULL) {
4008 tmp = tmp->next;
4009 continue;
4010 }
4011
4012 do {
4013 tmp = tmp->parent;
4014 if (tmp == NULL)
4015 break;
4016 if (tmp == cur) {
4017 tmp = NULL;
4018 break;
4019 }
4020 if (tmp->next != NULL) {
4021 tmp = tmp->next;
4022 break;
4023 }
4024 } while (tmp != NULL);
4025 }
4026 ret = buffer->content;
4027 buffer->content = NULL;
4028 xmlBufferFree(buffer);
4029 return (ret);
4030 }
4031 case XML_ATTRIBUTE_NODE:{
4032 xmlAttrPtr attr = (xmlAttrPtr) cur;
4033
4034 if (attr->parent != NULL)
4035 return (xmlNodeListGetString
4036 (attr->parent->doc, attr->children, 1));
4037 else
4038 return (xmlNodeListGetString(NULL, attr->children, 1));
4039 break;
4040 }
Owen Taylor3473f882001-02-23 17:55:21 +00004041 case XML_COMMENT_NODE:
4042 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004043 if (cur->content != NULL)
4044 return (xmlStrdup(cur->content));
4045 return (NULL);
4046 case XML_ENTITY_REF_NODE:{
4047 xmlEntityPtr ent;
4048 xmlNodePtr tmp;
4049 xmlBufferPtr buffer;
4050 xmlChar *ret;
4051
4052 /* lookup entity declaration */
4053 ent = xmlGetDocEntity(cur->doc, cur->name);
4054 if (ent == NULL)
4055 return (NULL);
4056
4057 buffer = xmlBufferCreate();
4058 if (buffer == NULL)
4059 return (NULL);
4060
4061 /* an entity content can be any "well balanced chunk",
4062 * i.e. the result of the content [43] production:
4063 * http://www.w3.org/TR/REC-xml#NT-content
4064 * -> we iterate through child nodes and recursive call
4065 * xmlNodeGetContent() which handles all possible node types */
4066 tmp = ent->children;
4067 while (tmp) {
4068 xmlChar *cont = xmlNodeGetContent(tmp);
4069
4070 if (cont) {
4071 xmlBufferCat(buffer, (const xmlChar *) cont);
4072 xmlFree(cont);
4073 }
4074 tmp = tmp->next;
4075 }
4076
4077 ret = buffer->content;
4078 buffer->content = NULL;
4079 xmlBufferFree(buffer);
4080 return (ret);
4081 }
Owen Taylor3473f882001-02-23 17:55:21 +00004082 case XML_ENTITY_NODE:
4083 case XML_DOCUMENT_NODE:
4084 case XML_HTML_DOCUMENT_NODE:
4085 case XML_DOCUMENT_TYPE_NODE:
4086 case XML_NOTATION_NODE:
4087 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004088 case XML_XINCLUDE_START:
4089 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004090#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004091 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004092#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004093 return (NULL);
4094 case XML_NAMESPACE_DECL:
4095 return (xmlStrdup(((xmlNsPtr) cur)->href));
Owen Taylor3473f882001-02-23 17:55:21 +00004096 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004097 /* TODO !!! */
4098 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004099 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004100 /* TODO !!! */
4101 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004102 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004103 /* TODO !!! */
4104 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004105 case XML_CDATA_SECTION_NODE:
4106 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004107 if (cur->content != NULL)
4108 return (xmlStrdup(cur->content));
4109 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004110 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004111 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004112}
Owen Taylor3473f882001-02-23 17:55:21 +00004113/**
4114 * xmlNodeSetContent:
4115 * @cur: the node being modified
4116 * @content: the new value of the content
4117 *
4118 * Replace the content of a node.
4119 */
4120void
4121xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4122 if (cur == NULL) {
4123#ifdef DEBUG_TREE
4124 xmlGenericError(xmlGenericErrorContext,
4125 "xmlNodeSetContent : node == NULL\n");
4126#endif
4127 return;
4128 }
4129 switch (cur->type) {
4130 case XML_DOCUMENT_FRAG_NODE:
4131 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004132 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004133 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4134 cur->children = xmlStringGetNodeList(cur->doc, content);
4135 UPDATE_LAST_CHILD_AND_PARENT(cur)
4136 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004137 case XML_TEXT_NODE:
4138 case XML_CDATA_SECTION_NODE:
4139 case XML_ENTITY_REF_NODE:
4140 case XML_ENTITY_NODE:
4141 case XML_PI_NODE:
4142 case XML_COMMENT_NODE:
4143 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004144 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004145 }
4146 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4147 cur->last = cur->children = NULL;
4148 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004149 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004150 } else
4151 cur->content = NULL;
4152 break;
4153 case XML_DOCUMENT_NODE:
4154 case XML_HTML_DOCUMENT_NODE:
4155 case XML_DOCUMENT_TYPE_NODE:
4156 case XML_XINCLUDE_START:
4157 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004158#ifdef LIBXML_DOCB_ENABLED
4159 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004160#endif
4161 break;
4162 case XML_NOTATION_NODE:
4163 break;
4164 case XML_DTD_NODE:
4165 break;
4166 case XML_NAMESPACE_DECL:
4167 break;
4168 case XML_ELEMENT_DECL:
4169 /* TODO !!! */
4170 break;
4171 case XML_ATTRIBUTE_DECL:
4172 /* TODO !!! */
4173 break;
4174 case XML_ENTITY_DECL:
4175 /* TODO !!! */
4176 break;
4177 }
4178}
4179
4180/**
4181 * xmlNodeSetContentLen:
4182 * @cur: the node being modified
4183 * @content: the new value of the content
4184 * @len: the size of @content
4185 *
4186 * Replace the content of a node.
4187 */
4188void
4189xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4190 if (cur == NULL) {
4191#ifdef DEBUG_TREE
4192 xmlGenericError(xmlGenericErrorContext,
4193 "xmlNodeSetContentLen : node == NULL\n");
4194#endif
4195 return;
4196 }
4197 switch (cur->type) {
4198 case XML_DOCUMENT_FRAG_NODE:
4199 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004200 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004201 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4202 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4203 UPDATE_LAST_CHILD_AND_PARENT(cur)
4204 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004205 case XML_TEXT_NODE:
4206 case XML_CDATA_SECTION_NODE:
4207 case XML_ENTITY_REF_NODE:
4208 case XML_ENTITY_NODE:
4209 case XML_PI_NODE:
4210 case XML_COMMENT_NODE:
4211 case XML_NOTATION_NODE:
4212 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004213 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004214 }
4215 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4216 cur->children = cur->last = NULL;
4217 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004218 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004219 } else
4220 cur->content = NULL;
4221 break;
4222 case XML_DOCUMENT_NODE:
4223 case XML_DTD_NODE:
4224 case XML_HTML_DOCUMENT_NODE:
4225 case XML_DOCUMENT_TYPE_NODE:
4226 case XML_NAMESPACE_DECL:
4227 case XML_XINCLUDE_START:
4228 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004229#ifdef LIBXML_DOCB_ENABLED
4230 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004231#endif
4232 break;
4233 case XML_ELEMENT_DECL:
4234 /* TODO !!! */
4235 break;
4236 case XML_ATTRIBUTE_DECL:
4237 /* TODO !!! */
4238 break;
4239 case XML_ENTITY_DECL:
4240 /* TODO !!! */
4241 break;
4242 }
4243}
4244
4245/**
4246 * xmlNodeAddContentLen:
4247 * @cur: the node being modified
4248 * @content: extra content
4249 * @len: the size of @content
4250 *
4251 * Append the extra substring to the node content.
4252 */
4253void
4254xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4255 if (cur == NULL) {
4256#ifdef DEBUG_TREE
4257 xmlGenericError(xmlGenericErrorContext,
4258 "xmlNodeAddContentLen : node == NULL\n");
4259#endif
4260 return;
4261 }
4262 if (len <= 0) return;
4263 switch (cur->type) {
4264 case XML_DOCUMENT_FRAG_NODE:
4265 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004266 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004267
Daniel Veillard7db37732001-07-12 01:20:08 +00004268 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004269 newNode = xmlNewTextLen(content, len);
4270 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004271 tmp = xmlAddChild(cur, newNode);
4272 if (tmp != newNode)
4273 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004274 if ((last != NULL) && (last->next == newNode)) {
4275 xmlTextMerge(last, newNode);
4276 }
4277 }
4278 break;
4279 }
4280 case XML_ATTRIBUTE_NODE:
4281 break;
4282 case XML_TEXT_NODE:
4283 case XML_CDATA_SECTION_NODE:
4284 case XML_ENTITY_REF_NODE:
4285 case XML_ENTITY_NODE:
4286 case XML_PI_NODE:
4287 case XML_COMMENT_NODE:
4288 case XML_NOTATION_NODE:
4289 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004290 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004291 }
4292 case XML_DOCUMENT_NODE:
4293 case XML_DTD_NODE:
4294 case XML_HTML_DOCUMENT_NODE:
4295 case XML_DOCUMENT_TYPE_NODE:
4296 case XML_NAMESPACE_DECL:
4297 case XML_XINCLUDE_START:
4298 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004299#ifdef LIBXML_DOCB_ENABLED
4300 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004301#endif
4302 break;
4303 case XML_ELEMENT_DECL:
4304 case XML_ATTRIBUTE_DECL:
4305 case XML_ENTITY_DECL:
4306 break;
4307 }
4308}
4309
4310/**
4311 * xmlNodeAddContent:
4312 * @cur: the node being modified
4313 * @content: extra content
4314 *
4315 * Append the extra substring to the node content.
4316 */
4317void
4318xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4319 int len;
4320
4321 if (cur == NULL) {
4322#ifdef DEBUG_TREE
4323 xmlGenericError(xmlGenericErrorContext,
4324 "xmlNodeAddContent : node == NULL\n");
4325#endif
4326 return;
4327 }
4328 if (content == NULL) return;
4329 len = xmlStrlen(content);
4330 xmlNodeAddContentLen(cur, content, len);
4331}
4332
4333/**
4334 * xmlTextMerge:
4335 * @first: the first text node
4336 * @second: the second text node being merged
4337 *
4338 * Merge two text nodes into one
4339 * Returns the first text node augmented
4340 */
4341xmlNodePtr
4342xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4343 if (first == NULL) return(second);
4344 if (second == NULL) return(first);
4345 if (first->type != XML_TEXT_NODE) return(first);
4346 if (second->type != XML_TEXT_NODE) return(first);
4347 if (second->name != first->name)
4348 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004349 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004350 xmlUnlinkNode(second);
4351 xmlFreeNode(second);
4352 return(first);
4353}
4354
4355/**
4356 * xmlGetNsList:
4357 * @doc: the document
4358 * @node: the current node
4359 *
4360 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004361 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004362 * that need to be freed by the caller or NULL if no
4363 * namespace if defined
4364 */
4365xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004366xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4367{
Owen Taylor3473f882001-02-23 17:55:21 +00004368 xmlNsPtr cur;
4369 xmlNsPtr *ret = NULL;
4370 int nbns = 0;
4371 int maxns = 10;
4372 int i;
4373
4374 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004375 if (node->type == XML_ELEMENT_NODE) {
4376 cur = node->nsDef;
4377 while (cur != NULL) {
4378 if (ret == NULL) {
4379 ret =
4380 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4381 sizeof(xmlNsPtr));
4382 if (ret == NULL) {
4383 xmlGenericError(xmlGenericErrorContext,
4384 "xmlGetNsList : out of memory!\n");
4385 return (NULL);
4386 }
4387 ret[nbns] = NULL;
4388 }
4389 for (i = 0; i < nbns; i++) {
4390 if ((cur->prefix == ret[i]->prefix) ||
4391 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4392 break;
4393 }
4394 if (i >= nbns) {
4395 if (nbns >= maxns) {
4396 maxns *= 2;
4397 ret = (xmlNsPtr *) xmlRealloc(ret,
4398 (maxns +
4399 1) *
4400 sizeof(xmlNsPtr));
4401 if (ret == NULL) {
4402 xmlGenericError(xmlGenericErrorContext,
4403 "xmlGetNsList : realloc failed!\n");
4404 return (NULL);
4405 }
4406 }
4407 ret[nbns++] = cur;
4408 ret[nbns] = NULL;
4409 }
Owen Taylor3473f882001-02-23 17:55:21 +00004410
Daniel Veillard77044732001-06-29 21:31:07 +00004411 cur = cur->next;
4412 }
4413 }
4414 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004415 }
Daniel Veillard77044732001-06-29 21:31:07 +00004416 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004417}
4418
4419/**
4420 * xmlSearchNs:
4421 * @doc: the document
4422 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004423 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004424 *
4425 * Search a Ns registered under a given name space for a document.
4426 * recurse on the parents until it finds the defined namespace
4427 * or return NULL otherwise.
4428 * @nameSpace can be NULL, this is a search for the default namespace.
4429 * We don't allow to cross entities boundaries. If you don't declare
4430 * the namespace within those you will be in troubles !!! A warning
4431 * is generated to cover this case.
4432 *
4433 * Returns the namespace pointer or NULL.
4434 */
4435xmlNsPtr
4436xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4437 xmlNsPtr cur;
4438
4439 if (node == NULL) return(NULL);
4440 if ((nameSpace != NULL) &&
4441 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004442 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4443 /*
4444 * The XML-1.0 namespace is normally held on the root
4445 * element. In this case exceptionally create it on the
4446 * node element.
4447 */
4448 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4449 if (cur == NULL) {
4450 xmlGenericError(xmlGenericErrorContext,
4451 "xmlSearchNs : malloc failed\n");
4452 return(NULL);
4453 }
4454 memset(cur, 0, sizeof(xmlNs));
4455 cur->type = XML_LOCAL_NAMESPACE;
4456 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4457 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4458 cur->next = node->nsDef;
4459 node->nsDef = cur;
4460 return(cur);
4461 }
Owen Taylor3473f882001-02-23 17:55:21 +00004462 if (doc->oldNs == NULL) {
4463 /*
4464 * Allocate a new Namespace and fill the fields.
4465 */
4466 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4467 if (doc->oldNs == NULL) {
4468 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004469 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004470 return(NULL);
4471 }
4472 memset(doc->oldNs, 0, sizeof(xmlNs));
4473 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4474
4475 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4476 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4477 }
4478 return(doc->oldNs);
4479 }
4480 while (node != NULL) {
4481 if ((node->type == XML_ENTITY_REF_NODE) ||
4482 (node->type == XML_ENTITY_NODE) ||
4483 (node->type == XML_ENTITY_DECL))
4484 return(NULL);
4485 if (node->type == XML_ELEMENT_NODE) {
4486 cur = node->nsDef;
4487 while (cur != NULL) {
4488 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4489 (cur->href != NULL))
4490 return(cur);
4491 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4492 (cur->href != NULL) &&
4493 (xmlStrEqual(cur->prefix, nameSpace)))
4494 return(cur);
4495 cur = cur->next;
4496 }
4497 }
4498 node = node->parent;
4499 }
4500 return(NULL);
4501}
4502
4503/**
4504 * xmlSearchNsByHref:
4505 * @doc: the document
4506 * @node: the current node
4507 * @href: the namespace value
4508 *
4509 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4510 * the defined namespace or return NULL otherwise.
4511 * Returns the namespace pointer or NULL.
4512 */
4513xmlNsPtr
4514xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4515 xmlNsPtr cur;
4516 xmlNodePtr orig = node;
4517
4518 if ((node == NULL) || (href == NULL)) return(NULL);
4519 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004520 /*
4521 * Only the document can hold the XML spec namespace.
4522 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004523 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4524 /*
4525 * The XML-1.0 namespace is normally held on the root
4526 * element. In this case exceptionally create it on the
4527 * node element.
4528 */
4529 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4530 if (cur == NULL) {
4531 xmlGenericError(xmlGenericErrorContext,
4532 "xmlSearchNs : malloc failed\n");
4533 return(NULL);
4534 }
4535 memset(cur, 0, sizeof(xmlNs));
4536 cur->type = XML_LOCAL_NAMESPACE;
4537 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4538 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4539 cur->next = node->nsDef;
4540 node->nsDef = cur;
4541 return(cur);
4542 }
Owen Taylor3473f882001-02-23 17:55:21 +00004543 if (doc->oldNs == NULL) {
4544 /*
4545 * Allocate a new Namespace and fill the fields.
4546 */
4547 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4548 if (doc->oldNs == NULL) {
4549 xmlGenericError(xmlGenericErrorContext,
4550 "xmlSearchNsByHref : malloc failed\n");
4551 return(NULL);
4552 }
4553 memset(doc->oldNs, 0, sizeof(xmlNs));
4554 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4555
4556 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4557 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4558 }
4559 return(doc->oldNs);
4560 }
4561 while (node != NULL) {
4562 cur = node->nsDef;
4563 while (cur != NULL) {
4564 if ((cur->href != NULL) && (href != NULL) &&
4565 (xmlStrEqual(cur->href, href))) {
4566 /*
4567 * Check that the prefix is not shadowed between orig and node
4568 */
4569 xmlNodePtr check = orig;
4570 xmlNsPtr tst;
4571
4572 while (check != node) {
4573 tst = check->nsDef;
4574 while (tst != NULL) {
4575 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4576 goto shadowed;
4577 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4578 (xmlStrEqual(tst->prefix, cur->prefix)))
4579 goto shadowed;
4580 tst = tst->next;
4581 }
4582 check = check->parent;
4583 }
4584 return(cur);
4585 }
4586shadowed:
4587 cur = cur->next;
4588 }
4589 node = node->parent;
4590 }
4591 return(NULL);
4592}
4593
4594/**
4595 * xmlNewReconciliedNs
4596 * @doc: the document
4597 * @tree: a node expected to hold the new namespace
4598 * @ns: the original namespace
4599 *
4600 * This function tries to locate a namespace definition in a tree
4601 * ancestors, or create a new namespace definition node similar to
4602 * @ns trying to reuse the same prefix. However if the given prefix is
4603 * null (default namespace) or reused within the subtree defined by
4604 * @tree or on one of its ancestors then a new prefix is generated.
4605 * Returns the (new) namespace definition or NULL in case of error
4606 */
4607xmlNsPtr
4608xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4609 xmlNsPtr def;
4610 xmlChar prefix[50];
4611 int counter = 1;
4612
4613 if (tree == NULL) {
4614#ifdef DEBUG_TREE
4615 xmlGenericError(xmlGenericErrorContext,
4616 "xmlNewReconciliedNs : tree == NULL\n");
4617#endif
4618 return(NULL);
4619 }
4620 if (ns == NULL) {
4621#ifdef DEBUG_TREE
4622 xmlGenericError(xmlGenericErrorContext,
4623 "xmlNewReconciliedNs : ns == NULL\n");
4624#endif
4625 return(NULL);
4626 }
4627 /*
4628 * Search an existing namespace definition inherited.
4629 */
4630 def = xmlSearchNsByHref(doc, tree, ns->href);
4631 if (def != NULL)
4632 return(def);
4633
4634 /*
4635 * Find a close prefix which is not already in use.
4636 * Let's strip namespace prefixes longer than 20 chars !
4637 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004638 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004639 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004640 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004641 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004642
Owen Taylor3473f882001-02-23 17:55:21 +00004643 def = xmlSearchNs(doc, tree, prefix);
4644 while (def != NULL) {
4645 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004646 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004647 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004648 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004649 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004650 def = xmlSearchNs(doc, tree, prefix);
4651 }
4652
4653 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004654 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004655 */
4656 def = xmlNewNs(tree, ns->href, prefix);
4657 return(def);
4658}
4659
4660/**
4661 * xmlReconciliateNs
4662 * @doc: the document
4663 * @tree: a node defining the subtree to reconciliate
4664 *
4665 * This function checks that all the namespaces declared within the given
4666 * tree are properly declared. This is needed for example after Copy or Cut
4667 * and then paste operations. The subtree may still hold pointers to
4668 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004669 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004670 * the new environment. If not possible the new namespaces are redeclared
4671 * on @tree at the top of the given subtree.
4672 * Returns the number of namespace declarations created or -1 in case of error.
4673 */
4674int
4675xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4676 xmlNsPtr *oldNs = NULL;
4677 xmlNsPtr *newNs = NULL;
4678 int sizeCache = 0;
4679 int nbCache = 0;
4680
4681 xmlNsPtr n;
4682 xmlNodePtr node = tree;
4683 xmlAttrPtr attr;
4684 int ret = 0, i;
4685
4686 while (node != NULL) {
4687 /*
4688 * Reconciliate the node namespace
4689 */
4690 if (node->ns != NULL) {
4691 /*
4692 * initialize the cache if needed
4693 */
4694 if (sizeCache == 0) {
4695 sizeCache = 10;
4696 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4697 sizeof(xmlNsPtr));
4698 if (oldNs == NULL) {
4699 xmlGenericError(xmlGenericErrorContext,
4700 "xmlReconciliateNs : memory pbm\n");
4701 return(-1);
4702 }
4703 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4704 sizeof(xmlNsPtr));
4705 if (newNs == NULL) {
4706 xmlGenericError(xmlGenericErrorContext,
4707 "xmlReconciliateNs : memory pbm\n");
4708 xmlFree(oldNs);
4709 return(-1);
4710 }
4711 }
4712 for (i = 0;i < nbCache;i++) {
4713 if (oldNs[i] == node->ns) {
4714 node->ns = newNs[i];
4715 break;
4716 }
4717 }
4718 if (i == nbCache) {
4719 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004720 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004721 */
4722 n = xmlNewReconciliedNs(doc, tree, node->ns);
4723 if (n != NULL) { /* :-( what if else ??? */
4724 /*
4725 * check if we need to grow the cache buffers.
4726 */
4727 if (sizeCache <= nbCache) {
4728 sizeCache *= 2;
4729 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4730 sizeof(xmlNsPtr));
4731 if (oldNs == NULL) {
4732 xmlGenericError(xmlGenericErrorContext,
4733 "xmlReconciliateNs : memory pbm\n");
4734 xmlFree(newNs);
4735 return(-1);
4736 }
4737 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4738 sizeof(xmlNsPtr));
4739 if (newNs == NULL) {
4740 xmlGenericError(xmlGenericErrorContext,
4741 "xmlReconciliateNs : memory pbm\n");
4742 xmlFree(oldNs);
4743 return(-1);
4744 }
4745 }
4746 newNs[nbCache] = n;
4747 oldNs[nbCache++] = node->ns;
4748 node->ns = n;
4749 }
4750 }
4751 }
4752 /*
4753 * now check for namespace hold by attributes on the node.
4754 */
4755 attr = node->properties;
4756 while (attr != NULL) {
4757 if (attr->ns != NULL) {
4758 /*
4759 * initialize the cache if needed
4760 */
4761 if (sizeCache == 0) {
4762 sizeCache = 10;
4763 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4764 sizeof(xmlNsPtr));
4765 if (oldNs == NULL) {
4766 xmlGenericError(xmlGenericErrorContext,
4767 "xmlReconciliateNs : memory pbm\n");
4768 return(-1);
4769 }
4770 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4771 sizeof(xmlNsPtr));
4772 if (newNs == NULL) {
4773 xmlGenericError(xmlGenericErrorContext,
4774 "xmlReconciliateNs : memory pbm\n");
4775 xmlFree(oldNs);
4776 return(-1);
4777 }
4778 }
4779 for (i = 0;i < nbCache;i++) {
4780 if (oldNs[i] == attr->ns) {
4781 node->ns = newNs[i];
4782 break;
4783 }
4784 }
4785 if (i == nbCache) {
4786 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004787 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004788 */
4789 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4790 if (n != NULL) { /* :-( what if else ??? */
4791 /*
4792 * check if we need to grow the cache buffers.
4793 */
4794 if (sizeCache <= nbCache) {
4795 sizeCache *= 2;
4796 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4797 sizeof(xmlNsPtr));
4798 if (oldNs == NULL) {
4799 xmlGenericError(xmlGenericErrorContext,
4800 "xmlReconciliateNs : memory pbm\n");
4801 xmlFree(newNs);
4802 return(-1);
4803 }
4804 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4805 sizeof(xmlNsPtr));
4806 if (newNs == NULL) {
4807 xmlGenericError(xmlGenericErrorContext,
4808 "xmlReconciliateNs : memory pbm\n");
4809 xmlFree(oldNs);
4810 return(-1);
4811 }
4812 }
4813 newNs[nbCache] = n;
4814 oldNs[nbCache++] = attr->ns;
4815 attr->ns = n;
4816 }
4817 }
4818 }
4819 attr = attr->next;
4820 }
4821
4822 /*
4823 * Browse the full subtree, deep first
4824 */
4825 if (node->children != NULL) {
4826 /* deep first */
4827 node = node->children;
4828 } else if ((node != tree) && (node->next != NULL)) {
4829 /* then siblings */
4830 node = node->next;
4831 } else if (node != tree) {
4832 /* go up to parents->next if needed */
4833 while (node != tree) {
4834 if (node->parent != NULL)
4835 node = node->parent;
4836 if ((node != tree) && (node->next != NULL)) {
4837 node = node->next;
4838 break;
4839 }
4840 if (node->parent == NULL) {
4841 node = NULL;
4842 break;
4843 }
4844 }
4845 /* exit condition */
4846 if (node == tree)
4847 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004848 } else
4849 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004850 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004851 if (oldNs != NULL)
4852 xmlFree(oldNs);
4853 if (newNs != NULL)
4854 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004855 return(ret);
4856}
4857
4858/**
4859 * xmlHasProp:
4860 * @node: the node
4861 * @name: the attribute name
4862 *
4863 * Search an attribute associated to a node
4864 * This function also looks in DTD attribute declaration for #FIXED or
4865 * default declaration values unless DTD use has been turned off.
4866 *
4867 * Returns the attribute or the attribute declaration or NULL if
4868 * neither was found.
4869 */
4870xmlAttrPtr
4871xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4872 xmlAttrPtr prop;
4873 xmlDocPtr doc;
4874
4875 if ((node == NULL) || (name == NULL)) return(NULL);
4876 /*
4877 * Check on the properties attached to the node
4878 */
4879 prop = node->properties;
4880 while (prop != NULL) {
4881 if (xmlStrEqual(prop->name, name)) {
4882 return(prop);
4883 }
4884 prop = prop->next;
4885 }
4886 if (!xmlCheckDTD) return(NULL);
4887
4888 /*
4889 * Check if there is a default declaration in the internal
4890 * or external subsets
4891 */
4892 doc = node->doc;
4893 if (doc != NULL) {
4894 xmlAttributePtr attrDecl;
4895 if (doc->intSubset != NULL) {
4896 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4897 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4898 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4899 if (attrDecl != NULL)
4900 return((xmlAttrPtr) attrDecl);
4901 }
4902 }
4903 return(NULL);
4904}
4905
4906/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00004907 * xmlHasNsProp:
4908 * @node: the node
4909 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00004910 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004911 *
4912 * Search for an attribute associated to a node
4913 * This attribute has to be anchored in the namespace specified.
4914 * This does the entity substitution.
4915 * This function looks in DTD attribute declaration for #FIXED or
4916 * default declaration values unless DTD use has been turned off.
4917 *
4918 * Returns the attribute or the attribute declaration or NULL
4919 * if neither was found.
4920 */
4921xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00004922xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00004923 xmlAttrPtr prop;
4924 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004925
4926 if (node == NULL)
4927 return(NULL);
4928
4929 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00004930 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00004931 return(xmlHasProp(node, name));
4932 while (prop != NULL) {
4933 /*
4934 * One need to have
4935 * - same attribute names
4936 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00004937 */
4938 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00004939 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
4940 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004941 }
4942 prop = prop->next;
4943 }
4944 if (!xmlCheckDTD) return(NULL);
4945
4946 /*
4947 * Check if there is a default declaration in the internal
4948 * or external subsets
4949 */
4950 doc = node->doc;
4951 if (doc != NULL) {
4952 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004953 xmlAttributePtr attrDecl = NULL;
4954 xmlNsPtr *nsList, *cur;
4955 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00004956
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004957 nsList = xmlGetNsList(node->doc, node);
4958 if (nsList == NULL)
4959 return(NULL);
4960 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
4961 ename = xmlStrdup(node->ns->prefix);
4962 ename = xmlStrcat(ename, BAD_CAST ":");
4963 ename = xmlStrcat(ename, node->name);
4964 } else {
4965 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004966 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00004967 if (ename == NULL) {
4968 xmlFree(nsList);
4969 return(NULL);
4970 }
4971
4972 cur = nsList;
4973 while (*cur != NULL) {
4974 if (xmlStrEqual((*cur)->href, nameSpace)) {
4975 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
4976 name, (*cur)->prefix);
4977 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4978 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
4979 name, (*cur)->prefix);
4980 }
4981 cur++;
4982 }
4983 xmlFree(nsList);
4984 xmlFree(ename);
4985 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00004986 }
4987 }
4988 return(NULL);
4989}
4990
4991/**
Owen Taylor3473f882001-02-23 17:55:21 +00004992 * xmlGetProp:
4993 * @node: the node
4994 * @name: the attribute name
4995 *
4996 * Search and get the value of an attribute associated to a node
4997 * This does the entity substitution.
4998 * This function looks in DTD attribute declaration for #FIXED or
4999 * default declaration values unless DTD use has been turned off.
5000 *
5001 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005002 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005003 */
5004xmlChar *
5005xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5006 xmlAttrPtr prop;
5007 xmlDocPtr doc;
5008
5009 if ((node == NULL) || (name == NULL)) return(NULL);
5010 /*
5011 * Check on the properties attached to the node
5012 */
5013 prop = node->properties;
5014 while (prop != NULL) {
5015 if (xmlStrEqual(prop->name, name)) {
5016 xmlChar *ret;
5017
5018 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5019 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5020 return(ret);
5021 }
5022 prop = prop->next;
5023 }
5024 if (!xmlCheckDTD) return(NULL);
5025
5026 /*
5027 * Check if there is a default declaration in the internal
5028 * or external subsets
5029 */
5030 doc = node->doc;
5031 if (doc != NULL) {
5032 xmlAttributePtr attrDecl;
5033 if (doc->intSubset != NULL) {
5034 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5035 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5036 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5037 if (attrDecl != NULL)
5038 return(xmlStrdup(attrDecl->defaultValue));
5039 }
5040 }
5041 return(NULL);
5042}
5043
5044/**
5045 * xmlGetNsProp:
5046 * @node: the node
5047 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005048 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005049 *
5050 * Search and get the value of an attribute associated to a node
5051 * This attribute has to be anchored in the namespace specified.
5052 * This does the entity substitution.
5053 * This function looks in DTD attribute declaration for #FIXED or
5054 * default declaration values unless DTD use has been turned off.
5055 *
5056 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005057 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005058 */
5059xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005060xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005061 xmlAttrPtr prop;
5062 xmlDocPtr doc;
5063 xmlNsPtr ns;
5064
5065 if (node == NULL)
5066 return(NULL);
5067
5068 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005069 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005070 return(xmlGetProp(node, name));
5071 while (prop != NULL) {
5072 /*
5073 * One need to have
5074 * - same attribute names
5075 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005076 */
5077 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005078 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005079 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005080 xmlChar *ret;
5081
5082 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5083 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5084 return(ret);
5085 }
5086 prop = prop->next;
5087 }
5088 if (!xmlCheckDTD) return(NULL);
5089
5090 /*
5091 * Check if there is a default declaration in the internal
5092 * or external subsets
5093 */
5094 doc = node->doc;
5095 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005096 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005097 xmlAttributePtr attrDecl;
5098
Owen Taylor3473f882001-02-23 17:55:21 +00005099 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5100 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5101 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5102
5103 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5104 /*
5105 * The DTD declaration only allows a prefix search
5106 */
5107 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005108 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005109 return(xmlStrdup(attrDecl->defaultValue));
5110 }
5111 }
5112 }
5113 return(NULL);
5114}
5115
5116/**
5117 * xmlSetProp:
5118 * @node: the node
5119 * @name: the attribute name
5120 * @value: the attribute value
5121 *
5122 * Set (or reset) an attribute carried by a node.
5123 * Returns the attribute pointer.
5124 */
5125xmlAttrPtr
5126xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005127 xmlAttrPtr prop;
5128 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005129
5130 if ((node == NULL) || (name == NULL))
5131 return(NULL);
5132 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005133 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005134 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005135 if ((xmlStrEqual(prop->name, name)) &&
5136 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005137 xmlNodePtr oldprop = prop->children;
5138
Owen Taylor3473f882001-02-23 17:55:21 +00005139 prop->children = NULL;
5140 prop->last = NULL;
5141 if (value != NULL) {
5142 xmlChar *buffer;
5143 xmlNodePtr tmp;
5144
5145 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5146 prop->children = xmlStringGetNodeList(node->doc, buffer);
5147 prop->last = NULL;
5148 prop->doc = doc;
5149 tmp = prop->children;
5150 while (tmp != NULL) {
5151 tmp->parent = (xmlNodePtr) prop;
5152 tmp->doc = doc;
5153 if (tmp->next == NULL)
5154 prop->last = tmp;
5155 tmp = tmp->next;
5156 }
5157 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005158 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005159 if (oldprop != NULL)
5160 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005161 return(prop);
5162 }
5163 prop = prop->next;
5164 }
5165 prop = xmlNewProp(node, name, value);
5166 return(prop);
5167}
5168
5169/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005170 * xmlUnsetProp:
5171 * @node: the node
5172 * @name: the attribute name
5173 *
5174 * Remove an attribute carried by a node.
5175 * Returns 0 if successful, -1 if not found
5176 */
5177int
5178xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5179 xmlAttrPtr prop = node->properties, prev = NULL;;
5180
5181 if ((node == NULL) || (name == NULL))
5182 return(-1);
5183 while (prop != NULL) {
5184 if ((xmlStrEqual(prop->name, name)) &&
5185 (prop->ns == NULL)) {
5186 if (prev == NULL)
5187 node->properties = prop->next;
5188 else
5189 prev->next = prop->next;
5190 xmlFreeProp(prop);
5191 return(0);
5192 }
5193 prev = prop;
5194 prop = prop->next;
5195 }
5196 return(-1);
5197}
5198
5199/**
Owen Taylor3473f882001-02-23 17:55:21 +00005200 * xmlSetNsProp:
5201 * @node: the node
5202 * @ns: the namespace definition
5203 * @name: the attribute name
5204 * @value: the attribute value
5205 *
5206 * Set (or reset) an attribute carried by a node.
5207 * The ns structure must be in scope, this is not checked.
5208 *
5209 * Returns the attribute pointer.
5210 */
5211xmlAttrPtr
5212xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5213 const xmlChar *value) {
5214 xmlAttrPtr prop;
5215
5216 if ((node == NULL) || (name == NULL))
5217 return(NULL);
5218
5219 if (ns == NULL)
5220 return(xmlSetProp(node, name, value));
5221 if (ns->href == NULL)
5222 return(NULL);
5223 prop = node->properties;
5224
5225 while (prop != NULL) {
5226 /*
5227 * One need to have
5228 * - same attribute names
5229 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005230 */
5231 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005232 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005233 if (prop->children != NULL)
5234 xmlFreeNodeList(prop->children);
5235 prop->children = NULL;
5236 prop->last = NULL;
5237 prop->ns = ns;
5238 if (value != NULL) {
5239 xmlChar *buffer;
5240 xmlNodePtr tmp;
5241
5242 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5243 prop->children = xmlStringGetNodeList(node->doc, buffer);
5244 prop->last = NULL;
5245 tmp = prop->children;
5246 while (tmp != NULL) {
5247 tmp->parent = (xmlNodePtr) prop;
5248 if (tmp->next == NULL)
5249 prop->last = tmp;
5250 tmp = tmp->next;
5251 }
5252 xmlFree(buffer);
5253 }
5254 return(prop);
5255 }
5256 prop = prop->next;
5257 }
5258 prop = xmlNewNsProp(node, ns, name, value);
5259 return(prop);
5260}
5261
5262/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005263 * xmlUnsetNsProp:
5264 * @node: the node
5265 * @ns: the namespace definition
5266 * @name: the attribute name
5267 *
5268 * Remove an attribute carried by a node.
5269 * Returns 0 if successful, -1 if not found
5270 */
5271int
5272xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5273 xmlAttrPtr prop = node->properties, prev = NULL;;
5274
5275 if ((node == NULL) || (name == NULL))
5276 return(-1);
5277 if (ns == NULL)
5278 return(xmlUnsetProp(node, name));
5279 if (ns->href == NULL)
5280 return(-1);
5281 while (prop != NULL) {
5282 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005283 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005284 if (prev == NULL)
5285 node->properties = prop->next;
5286 else
5287 prev->next = prop->next;
5288 xmlFreeProp(prop);
5289 return(0);
5290 }
5291 prev = prop;
5292 prop = prop->next;
5293 }
5294 return(-1);
5295}
5296
5297/**
Owen Taylor3473f882001-02-23 17:55:21 +00005298 * xmlNodeIsText:
5299 * @node: the node
5300 *
5301 * Is this node a Text node ?
5302 * Returns 1 yes, 0 no
5303 */
5304int
5305xmlNodeIsText(xmlNodePtr node) {
5306 if (node == NULL) return(0);
5307
5308 if (node->type == XML_TEXT_NODE) return(1);
5309 return(0);
5310}
5311
5312/**
5313 * xmlIsBlankNode:
5314 * @node: the node
5315 *
5316 * Checks whether this node is an empty or whitespace only
5317 * (and possibly ignorable) text-node.
5318 *
5319 * Returns 1 yes, 0 no
5320 */
5321int
5322xmlIsBlankNode(xmlNodePtr node) {
5323 const xmlChar *cur;
5324 if (node == NULL) return(0);
5325
Daniel Veillard7db37732001-07-12 01:20:08 +00005326 if ((node->type != XML_TEXT_NODE) &&
5327 (node->type != XML_CDATA_SECTION_NODE))
5328 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005329 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005330 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005331 while (*cur != 0) {
5332 if (!IS_BLANK(*cur)) return(0);
5333 cur++;
5334 }
5335
5336 return(1);
5337}
5338
5339/**
5340 * xmlTextConcat:
5341 * @node: the node
5342 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005343 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005344 *
5345 * Concat the given string at the end of the existing node content
5346 */
5347
5348void
5349xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5350 if (node == NULL) return;
5351
5352 if ((node->type != XML_TEXT_NODE) &&
5353 (node->type != XML_CDATA_SECTION_NODE)) {
5354#ifdef DEBUG_TREE
5355 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005356 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005357#endif
5358 return;
5359 }
Owen Taylor3473f882001-02-23 17:55:21 +00005360 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005361}
5362
5363/************************************************************************
5364 * *
5365 * Output : to a FILE or in memory *
5366 * *
5367 ************************************************************************/
5368
Owen Taylor3473f882001-02-23 17:55:21 +00005369/**
5370 * xmlBufferCreate:
5371 *
5372 * routine to create an XML buffer.
5373 * returns the new structure.
5374 */
5375xmlBufferPtr
5376xmlBufferCreate(void) {
5377 xmlBufferPtr ret;
5378
5379 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5380 if (ret == NULL) {
5381 xmlGenericError(xmlGenericErrorContext,
5382 "xmlBufferCreate : out of memory!\n");
5383 return(NULL);
5384 }
5385 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005386 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005387 ret->alloc = xmlBufferAllocScheme;
5388 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5389 if (ret->content == NULL) {
5390 xmlGenericError(xmlGenericErrorContext,
5391 "xmlBufferCreate : out of memory!\n");
5392 xmlFree(ret);
5393 return(NULL);
5394 }
5395 ret->content[0] = 0;
5396 return(ret);
5397}
5398
5399/**
5400 * xmlBufferCreateSize:
5401 * @size: initial size of buffer
5402 *
5403 * routine to create an XML buffer.
5404 * returns the new structure.
5405 */
5406xmlBufferPtr
5407xmlBufferCreateSize(size_t size) {
5408 xmlBufferPtr ret;
5409
5410 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5411 if (ret == NULL) {
5412 xmlGenericError(xmlGenericErrorContext,
5413 "xmlBufferCreate : out of memory!\n");
5414 return(NULL);
5415 }
5416 ret->use = 0;
5417 ret->alloc = xmlBufferAllocScheme;
5418 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5419 if (ret->size){
5420 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5421 if (ret->content == NULL) {
5422 xmlGenericError(xmlGenericErrorContext,
5423 "xmlBufferCreate : out of memory!\n");
5424 xmlFree(ret);
5425 return(NULL);
5426 }
5427 ret->content[0] = 0;
5428 } else
5429 ret->content = NULL;
5430 return(ret);
5431}
5432
5433/**
5434 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005435 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005436 * @scheme: allocation scheme to use
5437 *
5438 * Sets the allocation scheme for this buffer
5439 */
5440void
5441xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5442 xmlBufferAllocationScheme scheme) {
5443 if (buf == NULL) {
5444#ifdef DEBUG_BUFFER
5445 xmlGenericError(xmlGenericErrorContext,
5446 "xmlBufferSetAllocationScheme: buf == NULL\n");
5447#endif
5448 return;
5449 }
5450
5451 buf->alloc = scheme;
5452}
5453
5454/**
5455 * xmlBufferFree:
5456 * @buf: the buffer to free
5457 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005458 * Frees an XML buffer. It frees both the content and the structure which
5459 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005460 */
5461void
5462xmlBufferFree(xmlBufferPtr buf) {
5463 if (buf == NULL) {
5464#ifdef DEBUG_BUFFER
5465 xmlGenericError(xmlGenericErrorContext,
5466 "xmlBufferFree: buf == NULL\n");
5467#endif
5468 return;
5469 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005470 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005471 xmlFree(buf->content);
5472 }
Owen Taylor3473f882001-02-23 17:55:21 +00005473 xmlFree(buf);
5474}
5475
5476/**
5477 * xmlBufferEmpty:
5478 * @buf: the buffer
5479 *
5480 * empty a buffer.
5481 */
5482void
5483xmlBufferEmpty(xmlBufferPtr buf) {
5484 if (buf->content == NULL) return;
5485 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005486 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005487}
5488
5489/**
5490 * xmlBufferShrink:
5491 * @buf: the buffer to dump
5492 * @len: the number of xmlChar to remove
5493 *
5494 * Remove the beginning of an XML buffer.
5495 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005496 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005497 */
5498int
5499xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5500 if (len == 0) return(0);
5501 if (len > buf->use) return(-1);
5502
5503 buf->use -= len;
5504 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5505
5506 buf->content[buf->use] = 0;
5507 return(len);
5508}
5509
5510/**
5511 * xmlBufferGrow:
5512 * @buf: the buffer
5513 * @len: the minimum free size to allocate
5514 *
5515 * Grow the available space of an XML buffer.
5516 *
5517 * Returns the new available space or -1 in case of error
5518 */
5519int
5520xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5521 int size;
5522 xmlChar *newbuf;
5523
5524 if (len + buf->use < buf->size) return(0);
5525
5526 size = buf->use + len + 100;
5527
5528 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5529 if (newbuf == NULL) return(-1);
5530 buf->content = newbuf;
5531 buf->size = size;
5532 return(buf->size - buf->use);
5533}
5534
5535/**
5536 * xmlBufferDump:
5537 * @file: the file output
5538 * @buf: the buffer to dump
5539 *
5540 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005541 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005542 */
5543int
5544xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5545 int ret;
5546
5547 if (buf == NULL) {
5548#ifdef DEBUG_BUFFER
5549 xmlGenericError(xmlGenericErrorContext,
5550 "xmlBufferDump: buf == NULL\n");
5551#endif
5552 return(0);
5553 }
5554 if (buf->content == NULL) {
5555#ifdef DEBUG_BUFFER
5556 xmlGenericError(xmlGenericErrorContext,
5557 "xmlBufferDump: buf->content == NULL\n");
5558#endif
5559 return(0);
5560 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005561 if (file == NULL)
5562 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005563 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5564 return(ret);
5565}
5566
5567/**
5568 * xmlBufferContent:
5569 * @buf: the buffer
5570 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005571 * Function to extract the content of a buffer
5572 *
Owen Taylor3473f882001-02-23 17:55:21 +00005573 * Returns the internal content
5574 */
5575
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005576const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005577xmlBufferContent(const xmlBufferPtr buf)
5578{
5579 if(!buf)
5580 return NULL;
5581
5582 return buf->content;
5583}
5584
5585/**
5586 * xmlBufferLength:
5587 * @buf: the buffer
5588 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005589 * Function to get the length of a buffer
5590 *
Owen Taylor3473f882001-02-23 17:55:21 +00005591 * Returns the length of data in the internal content
5592 */
5593
5594int
5595xmlBufferLength(const xmlBufferPtr buf)
5596{
5597 if(!buf)
5598 return 0;
5599
5600 return buf->use;
5601}
5602
5603/**
5604 * xmlBufferResize:
5605 * @buf: the buffer to resize
5606 * @size: the desired size
5607 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005608 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005609 *
5610 * Returns 0 in case of problems, 1 otherwise
5611 */
5612int
5613xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5614{
5615 unsigned int newSize;
5616 xmlChar* rebuf = NULL;
5617
5618 /*take care of empty case*/
5619 newSize = (buf->size ? buf->size*2 : size);
5620
5621 /* Don't resize if we don't have to */
5622 if (size < buf->size)
5623 return 1;
5624
5625 /* figure out new size */
5626 switch (buf->alloc){
5627 case XML_BUFFER_ALLOC_DOUBLEIT:
5628 while (size > newSize) newSize *= 2;
5629 break;
5630 case XML_BUFFER_ALLOC_EXACT:
5631 newSize = size+10;
5632 break;
5633 default:
5634 newSize = size+10;
5635 break;
5636 }
5637
5638 if (buf->content == NULL)
5639 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5640 else
5641 rebuf = (xmlChar *) xmlRealloc(buf->content,
5642 newSize * sizeof(xmlChar));
5643 if (rebuf == NULL) {
5644 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005645 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005646 return 0;
5647 }
5648 buf->content = rebuf;
5649 buf->size = newSize;
5650
5651 return 1;
5652}
5653
5654/**
5655 * xmlBufferAdd:
5656 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005657 * @str: the #xmlChar string
5658 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005659 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005660 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005661 * str is recomputed.
5662 */
5663void
5664xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5665 unsigned int needSize;
5666
5667 if (str == NULL) {
5668#ifdef DEBUG_BUFFER
5669 xmlGenericError(xmlGenericErrorContext,
5670 "xmlBufferAdd: str == NULL\n");
5671#endif
5672 return;
5673 }
5674 if (len < -1) {
5675#ifdef DEBUG_BUFFER
5676 xmlGenericError(xmlGenericErrorContext,
5677 "xmlBufferAdd: len < 0\n");
5678#endif
5679 return;
5680 }
5681 if (len == 0) return;
5682
5683 if (len < 0)
5684 len = xmlStrlen(str);
5685
5686 if (len <= 0) return;
5687
5688 needSize = buf->use + len + 2;
5689 if (needSize > buf->size){
5690 if (!xmlBufferResize(buf, needSize)){
5691 xmlGenericError(xmlGenericErrorContext,
5692 "xmlBufferAdd : out of memory!\n");
5693 return;
5694 }
5695 }
5696
5697 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5698 buf->use += len;
5699 buf->content[buf->use] = 0;
5700}
5701
5702/**
5703 * xmlBufferAddHead:
5704 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005705 * @str: the #xmlChar string
5706 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005707 *
5708 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005709 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005710 */
5711void
5712xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5713 unsigned int needSize;
5714
5715 if (str == NULL) {
5716#ifdef DEBUG_BUFFER
5717 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005718 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005719#endif
5720 return;
5721 }
5722 if (len < -1) {
5723#ifdef DEBUG_BUFFER
5724 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005725 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005726#endif
5727 return;
5728 }
5729 if (len == 0) return;
5730
5731 if (len < 0)
5732 len = xmlStrlen(str);
5733
5734 if (len <= 0) return;
5735
5736 needSize = buf->use + len + 2;
5737 if (needSize > buf->size){
5738 if (!xmlBufferResize(buf, needSize)){
5739 xmlGenericError(xmlGenericErrorContext,
5740 "xmlBufferAddHead : out of memory!\n");
5741 return;
5742 }
5743 }
5744
5745 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5746 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5747 buf->use += len;
5748 buf->content[buf->use] = 0;
5749}
5750
5751/**
5752 * xmlBufferCat:
5753 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005754 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005755 *
5756 * Append a zero terminated string to an XML buffer.
5757 */
5758void
5759xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5760 if (str != NULL)
5761 xmlBufferAdd(buf, str, -1);
5762}
5763
5764/**
5765 * xmlBufferCCat:
5766 * @buf: the buffer to dump
5767 * @str: the C char string
5768 *
5769 * Append a zero terminated C string to an XML buffer.
5770 */
5771void
5772xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5773 const char *cur;
5774
5775 if (str == NULL) {
5776#ifdef DEBUG_BUFFER
5777 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005778 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005779#endif
5780 return;
5781 }
5782 for (cur = str;*cur != 0;cur++) {
5783 if (buf->use + 10 >= buf->size) {
5784 if (!xmlBufferResize(buf, buf->use+10)){
5785 xmlGenericError(xmlGenericErrorContext,
5786 "xmlBufferCCat : out of memory!\n");
5787 return;
5788 }
5789 }
5790 buf->content[buf->use++] = *cur;
5791 }
5792 buf->content[buf->use] = 0;
5793}
5794
5795/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005796 * xmlBufferWriteXmlCHAR:
5797 * @buf: the XML buffer
5798 * @string: the string to add
5799 *
5800 * For VMS only.
5801 * routine which manages and grows an output buffer. This one adds
5802 * xmlChars at the end of the buffer.
5803 */
5804/**
Owen Taylor3473f882001-02-23 17:55:21 +00005805 * xmlBufferWriteCHAR:
5806 * @buf: the XML buffer
5807 * @string: the string to add
5808 *
5809 * routine which manages and grows an output buffer. This one adds
5810 * xmlChars at the end of the buffer.
5811 */
5812void
5813#ifdef VMS
5814xmlBufferWriteXmlCHAR
5815#else
5816xmlBufferWriteCHAR
5817#endif
5818(xmlBufferPtr buf, const xmlChar *string) {
5819 xmlBufferCat(buf, string);
5820}
5821
5822/**
5823 * xmlBufferWriteChar:
5824 * @buf: the XML buffer output
5825 * @string: the string to add
5826 *
5827 * routine which manage and grows an output buffer. This one add
5828 * C chars at the end of the array.
5829 */
5830void
5831xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5832 xmlBufferCCat(buf, string);
5833}
5834
5835
5836/**
5837 * xmlBufferWriteQuotedString:
5838 * @buf: the XML buffer output
5839 * @string: the string to add
5840 *
5841 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005842 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005843 * quote or double-quotes internally
5844 */
5845void
5846xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5847 if (xmlStrchr(string, '"')) {
5848 if (xmlStrchr(string, '\'')) {
5849#ifdef DEBUG_BUFFER
5850 xmlGenericError(xmlGenericErrorContext,
5851 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5852#endif
5853 }
5854 xmlBufferCCat(buf, "'");
5855 xmlBufferCat(buf, string);
5856 xmlBufferCCat(buf, "'");
5857 } else {
5858 xmlBufferCCat(buf, "\"");
5859 xmlBufferCat(buf, string);
5860 xmlBufferCCat(buf, "\"");
5861 }
5862}
5863
5864
5865/************************************************************************
5866 * *
5867 * Dumping XML tree content to a simple buffer *
5868 * *
5869 ************************************************************************/
5870
Owen Taylor3473f882001-02-23 17:55:21 +00005871static void
5872xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5873 int format);
5874void
5875htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
5876
5877/**
5878 * xmlNsDump:
5879 * @buf: the XML buffer output
5880 * @cur: a namespace
5881 *
5882 * Dump a local Namespace definition.
5883 * Should be called in the context of attributes dumps.
5884 */
5885static void
5886xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5887 if (cur == NULL) {
5888#ifdef DEBUG_TREE
5889 xmlGenericError(xmlGenericErrorContext,
5890 "xmlNsDump : Ns == NULL\n");
5891#endif
5892 return;
5893 }
5894 if (cur->type == XML_LOCAL_NAMESPACE) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005895 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
5896 return;
5897
Owen Taylor3473f882001-02-23 17:55:21 +00005898 /* Within the context of an element attributes */
5899 if (cur->prefix != NULL) {
5900 xmlBufferWriteChar(buf, " xmlns:");
5901 xmlBufferWriteCHAR(buf, cur->prefix);
5902 } else
5903 xmlBufferWriteChar(buf, " xmlns");
5904 xmlBufferWriteChar(buf, "=");
5905 xmlBufferWriteQuotedString(buf, cur->href);
5906 }
5907}
5908
5909/**
5910 * xmlNsListDump:
5911 * @buf: the XML buffer output
5912 * @cur: the first namespace
5913 *
5914 * Dump a list of local Namespace definitions.
5915 * Should be called in the context of attributes dumps.
5916 */
5917static void
5918xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
5919 while (cur != NULL) {
5920 xmlNsDump(buf, cur);
5921 cur = cur->next;
5922 }
5923}
5924
5925/**
5926 * xmlDtdDump:
5927 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00005928 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00005929 *
5930 * Dump the XML document DTD, if any.
5931 */
5932static void
5933xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
5934 if (dtd == NULL) {
5935#ifdef DEBUG_TREE
5936 xmlGenericError(xmlGenericErrorContext,
5937 "xmlDtdDump : no internal subset\n");
5938#endif
5939 return;
5940 }
5941 xmlBufferWriteChar(buf, "<!DOCTYPE ");
5942 xmlBufferWriteCHAR(buf, dtd->name);
5943 if (dtd->ExternalID != NULL) {
5944 xmlBufferWriteChar(buf, " PUBLIC ");
5945 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
5946 xmlBufferWriteChar(buf, " ");
5947 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5948 } else if (dtd->SystemID != NULL) {
5949 xmlBufferWriteChar(buf, " SYSTEM ");
5950 xmlBufferWriteQuotedString(buf, dtd->SystemID);
5951 }
5952 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5953 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5954 xmlBufferWriteChar(buf, ">");
5955 return;
5956 }
5957 xmlBufferWriteChar(buf, " [\n");
5958 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
5959#if 0
5960 if (dtd->entities != NULL)
5961 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5962 if (dtd->notations != NULL)
5963 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5964 if (dtd->elements != NULL)
5965 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5966 if (dtd->attributes != NULL)
5967 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5968#endif
5969 xmlBufferWriteChar(buf, "]>");
5970}
5971
5972/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005973 * xmlAttrSerializeContent:
5974 * @buf: the XML buffer output
5975 * @doc: the document
5976 * @attr: the attribute pointer
5977 *
5978 * Serialize the attribute in the buffer
5979 */
5980static void
5981xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
5982 const xmlChar *cur, *base;
5983 xmlNodePtr children;
5984
5985 children = attr->children;
5986 while (children != NULL) {
5987 switch (children->type) {
5988 case XML_TEXT_NODE:
5989 base = cur = children->content;
5990 while (*cur != 0) {
5991 if (*cur == '\n') {
5992 if (base != cur)
5993 xmlBufferAdd(buf, base, cur - base);
5994 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5995 cur++;
5996 base = cur;
5997#if 0
5998 } else if (*cur == '\'') {
5999 if (base != cur)
6000 xmlBufferAdd(buf, base, cur - base);
6001 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6002 cur++;
6003 base = cur;
6004#endif
6005 } else if (*cur == '"') {
6006 if (base != cur)
6007 xmlBufferAdd(buf, base, cur - base);
6008 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6009 cur++;
6010 base = cur;
6011 } else if (*cur == '<') {
6012 if (base != cur)
6013 xmlBufferAdd(buf, base, cur - base);
6014 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6015 cur++;
6016 base = cur;
6017 } else if (*cur == '>') {
6018 if (base != cur)
6019 xmlBufferAdd(buf, base, cur - base);
6020 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6021 cur++;
6022 base = cur;
6023 } else if (*cur == '&') {
6024 if (base != cur)
6025 xmlBufferAdd(buf, base, cur - base);
6026 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6027 cur++;
6028 base = cur;
6029 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6030 (doc->encoding == NULL))) {
6031 /*
6032 * We assume we have UTF-8 content.
6033 */
6034 char tmp[10];
6035 int val = 0, l = 1;
6036
6037 if (base != cur)
6038 xmlBufferAdd(buf, base, cur - base);
6039 if (*cur < 0xC0) {
6040 xmlGenericError(xmlGenericErrorContext,
6041 "xmlAttrSerializeContent : input not UTF-8\n");
6042 if (doc != NULL)
6043 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6044 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6045 tmp[sizeof(tmp) - 1] = 0;
6046 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6047 cur++;
6048 base = cur;
6049 continue;
6050 } else if (*cur < 0xE0) {
6051 val = (cur[0]) & 0x1F;
6052 val <<= 6;
6053 val |= (cur[1]) & 0x3F;
6054 l = 2;
6055 } else if (*cur < 0xF0) {
6056 val = (cur[0]) & 0x0F;
6057 val <<= 6;
6058 val |= (cur[1]) & 0x3F;
6059 val <<= 6;
6060 val |= (cur[2]) & 0x3F;
6061 l = 3;
6062 } else if (*cur < 0xF8) {
6063 val = (cur[0]) & 0x07;
6064 val <<= 6;
6065 val |= (cur[1]) & 0x3F;
6066 val <<= 6;
6067 val |= (cur[2]) & 0x3F;
6068 val <<= 6;
6069 val |= (cur[3]) & 0x3F;
6070 l = 4;
6071 }
6072 if ((l == 1) || (!IS_CHAR(val))) {
6073 xmlGenericError(xmlGenericErrorContext,
6074 "xmlAttrSerializeContent : char out of range\n");
6075 if (doc != NULL)
6076 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6077 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6078 tmp[sizeof(tmp) - 1] = 0;
6079 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6080 cur++;
6081 base = cur;
6082 continue;
6083 }
6084 /*
6085 * We could do multiple things here. Just save
6086 * as a char ref
6087 */
6088 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6089 tmp[sizeof(tmp) - 1] = 0;
6090 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6091 cur += l;
6092 base = cur;
6093 } else {
6094 cur++;
6095 }
6096 }
6097 if (base != cur)
6098 xmlBufferAdd(buf, base, cur - base);
6099 break;
6100 case XML_ENTITY_REF_NODE:
6101 xmlBufferAdd(buf, BAD_CAST "&", 1);
6102 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6103 xmlBufferAdd(buf, BAD_CAST ";", 1);
6104 break;
6105 default:
6106 /* should not happen unless we have a badly built tree */
6107 break;
6108 }
6109 children = children->next;
6110 }
6111}
6112
6113/**
Owen Taylor3473f882001-02-23 17:55:21 +00006114 * xmlAttrDump:
6115 * @buf: the XML buffer output
6116 * @doc: the document
6117 * @cur: the attribute pointer
6118 *
6119 * Dump an XML attribute
6120 */
6121static void
6122xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006123 if (cur == NULL) {
6124#ifdef DEBUG_TREE
6125 xmlGenericError(xmlGenericErrorContext,
6126 "xmlAttrDump : property == NULL\n");
6127#endif
6128 return;
6129 }
6130 xmlBufferWriteChar(buf, " ");
6131 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6132 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6133 xmlBufferWriteChar(buf, ":");
6134 }
6135 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006136 xmlBufferWriteChar(buf, "=\"");
6137 xmlAttrSerializeContent(buf, doc, cur);
6138 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006139}
6140
6141/**
6142 * xmlAttrListDump:
6143 * @buf: the XML buffer output
6144 * @doc: the document
6145 * @cur: the first attribute pointer
6146 *
6147 * Dump a list of XML attributes
6148 */
6149static void
6150xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6151 if (cur == NULL) {
6152#ifdef DEBUG_TREE
6153 xmlGenericError(xmlGenericErrorContext,
6154 "xmlAttrListDump : property == NULL\n");
6155#endif
6156 return;
6157 }
6158 while (cur != NULL) {
6159 xmlAttrDump(buf, doc, cur);
6160 cur = cur->next;
6161 }
6162}
6163
6164
6165
6166/**
6167 * xmlNodeListDump:
6168 * @buf: the XML buffer output
6169 * @doc: the document
6170 * @cur: the first node
6171 * @level: the imbrication level for indenting
6172 * @format: is formatting allowed
6173 *
6174 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006175 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6176 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006177 */
6178static void
6179xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6180 int format) {
6181 int i;
6182
6183 if (cur == NULL) {
6184#ifdef DEBUG_TREE
6185 xmlGenericError(xmlGenericErrorContext,
6186 "xmlNodeListDump : node == NULL\n");
6187#endif
6188 return;
6189 }
6190 while (cur != NULL) {
6191 if ((format) && (xmlIndentTreeOutput) &&
6192 (cur->type == XML_ELEMENT_NODE))
6193 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006194 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006195 xmlNodeDump(buf, doc, cur, level, format);
6196 if (format) {
6197 xmlBufferWriteChar(buf, "\n");
6198 }
6199 cur = cur->next;
6200 }
6201}
6202
6203/**
6204 * xmlNodeDump:
6205 * @buf: the XML buffer output
6206 * @doc: the document
6207 * @cur: the current node
6208 * @level: the imbrication level for indenting
6209 * @format: is formatting allowed
6210 *
6211 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006212 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6213 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006214 */
6215void
6216xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6217 int format) {
6218 int i;
6219 xmlNodePtr tmp;
6220
6221 if (cur == NULL) {
6222#ifdef DEBUG_TREE
6223 xmlGenericError(xmlGenericErrorContext,
6224 "xmlNodeDump : node == NULL\n");
6225#endif
6226 return;
6227 }
6228 if (cur->type == XML_XINCLUDE_START)
6229 return;
6230 if (cur->type == XML_XINCLUDE_END)
6231 return;
6232 if (cur->type == XML_DTD_NODE) {
6233 xmlDtdDump(buf, (xmlDtdPtr) cur);
6234 return;
6235 }
6236 if (cur->type == XML_ELEMENT_DECL) {
6237 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6238 return;
6239 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006240 if (cur->type == XML_ATTRIBUTE_NODE){
6241 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6242 return;
6243 }
Owen Taylor3473f882001-02-23 17:55:21 +00006244 if (cur->type == XML_ATTRIBUTE_DECL) {
6245 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6246 return;
6247 }
6248 if (cur->type == XML_ENTITY_DECL) {
6249 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6250 return;
6251 }
6252 if (cur->type == XML_TEXT_NODE) {
6253 if (cur->content != NULL) {
6254 if ((cur->name == xmlStringText) ||
6255 (cur->name != xmlStringTextNoenc)) {
6256 xmlChar *buffer;
6257
Owen Taylor3473f882001-02-23 17:55:21 +00006258 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006259 if (buffer != NULL) {
6260 xmlBufferWriteCHAR(buf, buffer);
6261 xmlFree(buffer);
6262 }
6263 } else {
6264 /*
6265 * Disable escaping, needed for XSLT
6266 */
Owen Taylor3473f882001-02-23 17:55:21 +00006267 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006268 }
6269 }
6270 return;
6271 }
6272 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006273 xmlBufferWriteChar(buf, "<?");
6274 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006275 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006276 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006277 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006278 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006279 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006280 return;
6281 }
6282 if (cur->type == XML_COMMENT_NODE) {
6283 if (cur->content != NULL) {
6284 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006285 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006286 xmlBufferWriteChar(buf, "-->");
6287 }
6288 return;
6289 }
6290 if (cur->type == XML_ENTITY_REF_NODE) {
6291 xmlBufferWriteChar(buf, "&");
6292 xmlBufferWriteCHAR(buf, cur->name);
6293 xmlBufferWriteChar(buf, ";");
6294 return;
6295 }
6296 if (cur->type == XML_CDATA_SECTION_NODE) {
6297 xmlBufferWriteChar(buf, "<![CDATA[");
6298 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006299 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006300 xmlBufferWriteChar(buf, "]]>");
6301 return;
6302 }
6303
6304 if (format == 1) {
6305 tmp = cur->children;
6306 while (tmp != NULL) {
6307 if ((tmp->type == XML_TEXT_NODE) ||
6308 (tmp->type == XML_ENTITY_REF_NODE)) {
6309 format = 0;
6310 break;
6311 }
6312 tmp = tmp->next;
6313 }
6314 }
6315 xmlBufferWriteChar(buf, "<");
6316 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6317 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6318 xmlBufferWriteChar(buf, ":");
6319 }
6320
6321 xmlBufferWriteCHAR(buf, cur->name);
6322 if (cur->nsDef)
6323 xmlNsListDump(buf, cur->nsDef);
6324 if (cur->properties != NULL)
6325 xmlAttrListDump(buf, doc, cur->properties);
6326
Daniel Veillard7db37732001-07-12 01:20:08 +00006327 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6328 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006329 (!xmlSaveNoEmptyTags)) {
6330 xmlBufferWriteChar(buf, "/>");
6331 return;
6332 }
6333 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006334 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006335 xmlChar *buffer;
6336
Owen Taylor3473f882001-02-23 17:55:21 +00006337 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006338 if (buffer != NULL) {
6339 xmlBufferWriteCHAR(buf, buffer);
6340 xmlFree(buffer);
6341 }
6342 }
6343 if (cur->children != NULL) {
6344 if (format) xmlBufferWriteChar(buf, "\n");
6345 xmlNodeListDump(buf, doc, cur->children,
6346 (level >= 0?level+1:-1), format);
6347 if ((xmlIndentTreeOutput) && (format))
6348 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006349 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006350 }
6351 xmlBufferWriteChar(buf, "</");
6352 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6353 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6354 xmlBufferWriteChar(buf, ":");
6355 }
6356
6357 xmlBufferWriteCHAR(buf, cur->name);
6358 xmlBufferWriteChar(buf, ">");
6359}
6360
6361/**
6362 * xmlElemDump:
6363 * @f: the FILE * for the output
6364 * @doc: the document
6365 * @cur: the current node
6366 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006367 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006368 */
6369void
6370xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6371 xmlBufferPtr buf;
6372
6373 if (cur == NULL) {
6374#ifdef DEBUG_TREE
6375 xmlGenericError(xmlGenericErrorContext,
6376 "xmlElemDump : cur == NULL\n");
6377#endif
6378 return;
6379 }
Owen Taylor3473f882001-02-23 17:55:21 +00006380#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006381 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006382 xmlGenericError(xmlGenericErrorContext,
6383 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006384 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006385#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006386
Owen Taylor3473f882001-02-23 17:55:21 +00006387 buf = xmlBufferCreate();
6388 if (buf == NULL) return;
6389 if ((doc != NULL) &&
6390 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6391#ifdef LIBXML_HTML_ENABLED
6392 htmlNodeDump(buf, doc, cur);
6393#else
6394 xmlGenericError(xmlGenericErrorContext,
6395 "HTML support not compiled in\n");
6396#endif /* LIBXML_HTML_ENABLED */
6397 } else
6398 xmlNodeDump(buf, doc, cur, 0, 1);
6399 xmlBufferDump(f, buf);
6400 xmlBufferFree(buf);
6401}
6402
6403/************************************************************************
6404 * *
6405 * Dumping XML tree content to an I/O output buffer *
6406 * *
6407 ************************************************************************/
6408
Owen Taylor3473f882001-02-23 17:55:21 +00006409static void
6410xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6411 int level, int format, const char *encoding);
6412/**
6413 * xmlNsDumpOutput:
6414 * @buf: the XML buffer output
6415 * @cur: a namespace
6416 *
6417 * Dump a local Namespace definition.
6418 * Should be called in the context of attributes dumps.
6419 */
6420static void
6421xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6422 if (cur == NULL) {
6423#ifdef DEBUG_TREE
6424 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006425 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006426#endif
6427 return;
6428 }
6429 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006430 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6431 return;
6432
Owen Taylor3473f882001-02-23 17:55:21 +00006433 /* Within the context of an element attributes */
6434 if (cur->prefix != NULL) {
6435 xmlOutputBufferWriteString(buf, " xmlns:");
6436 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6437 } else
6438 xmlOutputBufferWriteString(buf, " xmlns");
6439 xmlOutputBufferWriteString(buf, "=");
6440 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6441 }
6442}
6443
6444/**
6445 * xmlNsListDumpOutput:
6446 * @buf: the XML buffer output
6447 * @cur: the first namespace
6448 *
6449 * Dump a list of local Namespace definitions.
6450 * Should be called in the context of attributes dumps.
6451 */
6452static void
6453xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6454 while (cur != NULL) {
6455 xmlNsDumpOutput(buf, cur);
6456 cur = cur->next;
6457 }
6458}
6459
6460/**
6461 * xmlDtdDumpOutput:
6462 * @buf: the XML buffer output
6463 * @doc: the document
6464 * @encoding: an optional encoding string
6465 *
6466 * Dump the XML document DTD, if any.
6467 */
6468static void
6469xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6470 if (dtd == NULL) {
6471#ifdef DEBUG_TREE
6472 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006473 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006474#endif
6475 return;
6476 }
6477 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6478 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6479 if (dtd->ExternalID != NULL) {
6480 xmlOutputBufferWriteString(buf, " PUBLIC ");
6481 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6482 xmlOutputBufferWriteString(buf, " ");
6483 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6484 } else if (dtd->SystemID != NULL) {
6485 xmlOutputBufferWriteString(buf, " SYSTEM ");
6486 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6487 }
6488 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6489 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6490 xmlOutputBufferWriteString(buf, ">");
6491 return;
6492 }
6493 xmlOutputBufferWriteString(buf, " [\n");
6494 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6495 xmlOutputBufferWriteString(buf, "]>");
6496}
6497
6498/**
6499 * xmlAttrDumpOutput:
6500 * @buf: the XML buffer output
6501 * @doc: the document
6502 * @cur: the attribute pointer
6503 * @encoding: an optional encoding string
6504 *
6505 * Dump an XML attribute
6506 */
6507static void
6508xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006509 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006510 if (cur == NULL) {
6511#ifdef DEBUG_TREE
6512 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006513 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006514#endif
6515 return;
6516 }
6517 xmlOutputBufferWriteString(buf, " ");
6518 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6519 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6520 xmlOutputBufferWriteString(buf, ":");
6521 }
6522 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006523 xmlOutputBufferWriteString(buf, "=\"");
6524 xmlAttrSerializeContent(buf->buffer, doc, cur);
6525 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006526}
6527
6528/**
6529 * xmlAttrListDumpOutput:
6530 * @buf: the XML buffer output
6531 * @doc: the document
6532 * @cur: the first attribute pointer
6533 * @encoding: an optional encoding string
6534 *
6535 * Dump a list of XML attributes
6536 */
6537static void
6538xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6539 xmlAttrPtr cur, const char *encoding) {
6540 if (cur == NULL) {
6541#ifdef DEBUG_TREE
6542 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006543 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006544#endif
6545 return;
6546 }
6547 while (cur != NULL) {
6548 xmlAttrDumpOutput(buf, doc, cur, encoding);
6549 cur = cur->next;
6550 }
6551}
6552
6553
6554
6555/**
6556 * xmlNodeListDumpOutput:
6557 * @buf: the XML buffer output
6558 * @doc: the document
6559 * @cur: the first node
6560 * @level: the imbrication level for indenting
6561 * @format: is formatting allowed
6562 * @encoding: an optional encoding string
6563 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006564 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006565 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6566 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006567 */
6568static void
6569xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6570 xmlNodePtr cur, int level, int format, const char *encoding) {
6571 int i;
6572
6573 if (cur == NULL) {
6574#ifdef DEBUG_TREE
6575 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006576 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006577#endif
6578 return;
6579 }
6580 while (cur != NULL) {
6581 if ((format) && (xmlIndentTreeOutput) &&
6582 (cur->type == XML_ELEMENT_NODE))
6583 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006584 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006585 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6586 if (format) {
6587 xmlOutputBufferWriteString(buf, "\n");
6588 }
6589 cur = cur->next;
6590 }
6591}
6592
6593/**
6594 * xmlNodeDumpOutput:
6595 * @buf: the XML buffer output
6596 * @doc: the document
6597 * @cur: the current node
6598 * @level: the imbrication level for indenting
6599 * @format: is formatting allowed
6600 * @encoding: an optional encoding string
6601 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006602 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006603 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6604 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006605 */
6606void
6607xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6608 int level, int format, const char *encoding) {
6609 int i;
6610 xmlNodePtr tmp;
6611
6612 if (cur == NULL) {
6613#ifdef DEBUG_TREE
6614 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006615 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006616#endif
6617 return;
6618 }
6619 if (cur->type == XML_XINCLUDE_START)
6620 return;
6621 if (cur->type == XML_XINCLUDE_END)
6622 return;
6623 if (cur->type == XML_DTD_NODE) {
6624 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6625 return;
6626 }
6627 if (cur->type == XML_ELEMENT_DECL) {
6628 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6629 return;
6630 }
6631 if (cur->type == XML_ATTRIBUTE_DECL) {
6632 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6633 return;
6634 }
6635 if (cur->type == XML_ENTITY_DECL) {
6636 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6637 return;
6638 }
6639 if (cur->type == XML_TEXT_NODE) {
6640 if (cur->content != NULL) {
6641 if ((cur->name == xmlStringText) ||
6642 (cur->name != xmlStringTextNoenc)) {
6643 xmlChar *buffer;
6644
Owen Taylor3473f882001-02-23 17:55:21 +00006645 if (encoding == NULL)
6646 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6647 else
6648 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006649 if (buffer != NULL) {
6650 xmlOutputBufferWriteString(buf, (const char *)buffer);
6651 xmlFree(buffer);
6652 }
6653 } else {
6654 /*
6655 * Disable escaping, needed for XSLT
6656 */
Owen Taylor3473f882001-02-23 17:55:21 +00006657 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006658 }
6659 }
6660
6661 return;
6662 }
6663 if (cur->type == XML_PI_NODE) {
6664 if (cur->content != NULL) {
6665 xmlOutputBufferWriteString(buf, "<?");
6666 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6667 if (cur->content != NULL) {
6668 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006669 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006670 }
6671 xmlOutputBufferWriteString(buf, "?>");
6672 } else {
6673 xmlOutputBufferWriteString(buf, "<?");
6674 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6675 xmlOutputBufferWriteString(buf, "?>");
6676 }
6677 return;
6678 }
6679 if (cur->type == XML_COMMENT_NODE) {
6680 if (cur->content != NULL) {
6681 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006682 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006683 xmlOutputBufferWriteString(buf, "-->");
6684 }
6685 return;
6686 }
6687 if (cur->type == XML_ENTITY_REF_NODE) {
6688 xmlOutputBufferWriteString(buf, "&");
6689 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6690 xmlOutputBufferWriteString(buf, ";");
6691 return;
6692 }
6693 if (cur->type == XML_CDATA_SECTION_NODE) {
6694 xmlOutputBufferWriteString(buf, "<![CDATA[");
6695 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006696 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006697 xmlOutputBufferWriteString(buf, "]]>");
6698 return;
6699 }
6700
6701 if (format == 1) {
6702 tmp = cur->children;
6703 while (tmp != NULL) {
6704 if ((tmp->type == XML_TEXT_NODE) ||
6705 (tmp->type == XML_ENTITY_REF_NODE)) {
6706 format = 0;
6707 break;
6708 }
6709 tmp = tmp->next;
6710 }
6711 }
6712 xmlOutputBufferWriteString(buf, "<");
6713 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6714 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6715 xmlOutputBufferWriteString(buf, ":");
6716 }
6717
6718 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6719 if (cur->nsDef)
6720 xmlNsListDumpOutput(buf, cur->nsDef);
6721 if (cur->properties != NULL)
6722 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6723
Daniel Veillard7db37732001-07-12 01:20:08 +00006724 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6725 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006726 xmlOutputBufferWriteString(buf, "/>");
6727 return;
6728 }
6729 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006730 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006731 xmlChar *buffer;
6732
Owen Taylor3473f882001-02-23 17:55:21 +00006733 if (encoding == NULL)
6734 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6735 else
6736 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006737 if (buffer != NULL) {
6738 xmlOutputBufferWriteString(buf, (const char *)buffer);
6739 xmlFree(buffer);
6740 }
6741 }
6742 if (cur->children != NULL) {
6743 if (format) xmlOutputBufferWriteString(buf, "\n");
6744 xmlNodeListDumpOutput(buf, doc, cur->children,
6745 (level >= 0?level+1:-1), format, encoding);
6746 if ((xmlIndentTreeOutput) && (format))
6747 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006748 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006749 }
6750 xmlOutputBufferWriteString(buf, "</");
6751 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6752 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6753 xmlOutputBufferWriteString(buf, ":");
6754 }
6755
6756 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6757 xmlOutputBufferWriteString(buf, ">");
6758}
6759
6760/**
6761 * xmlDocContentDumpOutput:
6762 * @buf: the XML buffer output
6763 * @cur: the document
6764 * @encoding: an optional encoding string
6765 * @format: should formatting spaces been added
6766 *
6767 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006768 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6769 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006770 */
6771static void
6772xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6773 const char *encoding, int format) {
6774 xmlOutputBufferWriteString(buf, "<?xml version=");
6775 if (cur->version != NULL)
6776 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6777 else
6778 xmlOutputBufferWriteString(buf, "\"1.0\"");
6779 if (encoding == NULL) {
6780 if (cur->encoding != NULL)
6781 encoding = (const char *) cur->encoding;
6782 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6783 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6784 }
6785 if (encoding != NULL) {
6786 xmlOutputBufferWriteString(buf, " encoding=");
6787 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6788 }
6789 switch (cur->standalone) {
6790 case 0:
6791 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6792 break;
6793 case 1:
6794 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6795 break;
6796 }
6797 xmlOutputBufferWriteString(buf, "?>\n");
6798 if (cur->children != NULL) {
6799 xmlNodePtr child = cur->children;
6800
6801 while (child != NULL) {
6802 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6803 xmlOutputBufferWriteString(buf, "\n");
6804 child = child->next;
6805 }
6806 }
6807}
6808
6809/************************************************************************
6810 * *
6811 * Saving functions front-ends *
6812 * *
6813 ************************************************************************/
6814
6815/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006816 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00006817 * @out_doc: Document to generate XML text from
6818 * @doc_txt_ptr: Memory pointer for allocated XML text
6819 * @doc_txt_len: Length of the generated XML text
6820 * @txt_encoding: Character encoding to use when generating XML text
6821 * @format: should formatting spaces been added
6822 *
6823 * Dump the current DOM tree into memory using the character encoding specified
6824 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006825 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006826 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6827 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006828 */
6829
6830void
6831xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006832 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006833 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00006834 int dummy = 0;
6835
6836 xmlCharEncoding doc_charset;
6837 xmlOutputBufferPtr out_buff = NULL;
6838 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
6839
6840 if (doc_txt_len == NULL) {
6841 doc_txt_len = &dummy; /* Continue, caller just won't get length */
6842 }
6843
6844 if (doc_txt_ptr == NULL) {
6845 *doc_txt_len = 0;
6846 xmlGenericError(xmlGenericErrorContext,
6847 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
6848 return;
6849 }
6850
6851 *doc_txt_ptr = NULL;
6852 *doc_txt_len = 0;
6853
6854 if (out_doc == NULL) {
6855 /* No document, no output */
6856 xmlGenericError(xmlGenericErrorContext,
6857 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
6858 return;
6859 }
6860
6861 /*
6862 * Validate the encoding value, if provided.
6863 * This logic is copied from xmlSaveFileEnc.
6864 */
6865
6866 if (txt_encoding == NULL)
6867 txt_encoding = (const char *) out_doc->encoding;
6868 if (txt_encoding != NULL) {
6869 doc_charset = xmlParseCharEncoding(txt_encoding);
6870
6871 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
6872 xmlGenericError(xmlGenericErrorContext,
6873 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
6874 return;
6875
6876 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
6877 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
6878 if ( conv_hdlr == NULL ) {
6879 xmlGenericError(xmlGenericErrorContext,
6880 "%s: %s %s '%s'\n",
6881 "xmlDocDumpFormatMemoryEnc",
6882 "Failed to identify encoding handler for",
6883 "character set",
6884 txt_encoding);
6885 return;
6886 }
6887 }
6888 }
6889
6890 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
6891 xmlGenericError(xmlGenericErrorContext,
6892 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
6893 return;
6894 }
6895
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006896 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00006897 xmlOutputBufferFlush(out_buff);
6898 if (out_buff->conv != NULL) {
6899 *doc_txt_len = out_buff->conv->use;
6900 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
6901 } else {
6902 *doc_txt_len = out_buff->buffer->use;
6903 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
6904 }
6905 (void)xmlOutputBufferClose(out_buff);
6906
6907 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
6908 *doc_txt_len = 0;
6909 xmlGenericError(xmlGenericErrorContext,
6910 "xmlDocDumpFormatMemoryEnc: %s\n",
6911 "Failed to allocate memory for document text representation.");
6912 }
6913
6914 return;
6915}
6916
6917/**
6918 * xmlDocDumpMemory:
6919 * @cur: the document
6920 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006921 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006922 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006923 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006924 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006925 */
6926void
6927xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
6928 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
6929}
6930
6931/**
6932 * xmlDocDumpFormatMemory:
6933 * @cur: the document
6934 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00006935 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00006936 * @format: should formatting spaces been added
6937 *
6938 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006939 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006940 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006941 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6942 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006943 */
6944void
6945xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
6946 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
6947}
6948
6949/**
6950 * xmlDocDumpMemoryEnc:
6951 * @out_doc: Document to generate XML text from
6952 * @doc_txt_ptr: Memory pointer for allocated XML text
6953 * @doc_txt_len: Length of the generated XML text
6954 * @txt_encoding: Character encoding to use when generating XML text
6955 *
6956 * Dump the current DOM tree into memory using the character encoding specified
6957 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006958 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006959 */
6960
6961void
6962xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
6963 int * doc_txt_len, const char * txt_encoding) {
6964 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00006965 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006966}
6967
6968/**
6969 * xmlGetDocCompressMode:
6970 * @doc: the document
6971 *
6972 * get the compression ratio for a document, ZLIB based
6973 * Returns 0 (uncompressed) to 9 (max compression)
6974 */
6975int
6976xmlGetDocCompressMode (xmlDocPtr doc) {
6977 if (doc == NULL) return(-1);
6978 return(doc->compression);
6979}
6980
6981/**
6982 * xmlSetDocCompressMode:
6983 * @doc: the document
6984 * @mode: the compression ratio
6985 *
6986 * set the compression ratio for a document, ZLIB based
6987 * Correct values: 0 (uncompressed) to 9 (max compression)
6988 */
6989void
6990xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
6991 if (doc == NULL) return;
6992 if (mode < 0) doc->compression = 0;
6993 else if (mode > 9) doc->compression = 9;
6994 else doc->compression = mode;
6995}
6996
6997/**
6998 * xmlGetCompressMode:
6999 *
7000 * get the default compression mode used, ZLIB based.
7001 * Returns 0 (uncompressed) to 9 (max compression)
7002 */
7003int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007004xmlGetCompressMode(void)
7005{
7006 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007007}
7008
7009/**
7010 * xmlSetCompressMode:
7011 * @mode: the compression ratio
7012 *
7013 * set the default compression mode used, ZLIB based
7014 * Correct values: 0 (uncompressed) to 9 (max compression)
7015 */
7016void
7017xmlSetCompressMode(int mode) {
7018 if (mode < 0) xmlCompressMode = 0;
7019 else if (mode > 9) xmlCompressMode = 9;
7020 else xmlCompressMode = mode;
7021}
7022
7023/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007024 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007025 * @f: the FILE*
7026 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007027 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007028 *
7029 * Dump an XML document to an open FILE.
7030 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007031 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007032 */
7033int
Daniel Veillard9e412302002-06-10 15:59:44 +00007034xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007035 xmlOutputBufferPtr buf;
7036 const char * encoding;
7037 xmlCharEncodingHandlerPtr handler = NULL;
7038 int ret;
7039
7040 if (cur == NULL) {
7041#ifdef DEBUG_TREE
7042 xmlGenericError(xmlGenericErrorContext,
7043 "xmlDocDump : document == NULL\n");
7044#endif
7045 return(-1);
7046 }
7047 encoding = (const char *) cur->encoding;
7048
7049 if (encoding != NULL) {
7050 xmlCharEncoding enc;
7051
7052 enc = xmlParseCharEncoding(encoding);
7053
7054 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7055 xmlGenericError(xmlGenericErrorContext,
7056 "xmlDocDump: document not in UTF8\n");
7057 return(-1);
7058 }
7059 if (enc != XML_CHAR_ENCODING_UTF8) {
7060 handler = xmlFindCharEncodingHandler(encoding);
7061 if (handler == NULL) {
7062 xmlFree((char *) cur->encoding);
7063 cur->encoding = NULL;
7064 }
7065 }
7066 }
7067 buf = xmlOutputBufferCreateFile(f, handler);
7068 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007069 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007070
7071 ret = xmlOutputBufferClose(buf);
7072 return(ret);
7073}
7074
7075/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007076 * xmlDocDump:
7077 * @f: the FILE*
7078 * @cur: the document
7079 *
7080 * Dump an XML document to an open FILE.
7081 *
7082 * returns: the number of bytes written or -1 in case of failure.
7083 */
7084int
7085xmlDocDump(FILE *f, xmlDocPtr cur) {
7086 return(xmlDocFormatDump (f, cur, 0));
7087}
7088
7089/**
Owen Taylor3473f882001-02-23 17:55:21 +00007090 * xmlSaveFileTo:
7091 * @buf: an output I/O buffer
7092 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007093 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007094 *
7095 * Dump an XML document to an I/O buffer.
7096 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007097 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007098 */
7099int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007100xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007101 int ret;
7102
7103 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007104 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007105 ret = xmlOutputBufferClose(buf);
7106 return(ret);
7107}
7108
7109/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007110 * xmlSaveFormatFileTo:
7111 * @buf: an output I/O buffer
7112 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007113 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007114 * @format: should formatting spaces been added
7115 *
7116 * Dump an XML document to an I/O buffer.
7117 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007118 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007119 */
7120int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007121xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007122 int ret;
7123
7124 if (buf == NULL) return(0);
7125 xmlDocContentDumpOutput(buf, cur, encoding, format);
7126 ret = xmlOutputBufferClose(buf);
7127 return(ret);
7128}
7129
7130/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007131 * xmlSaveFormatFileEnc
7132 * @filename: the filename or URL to output
7133 * @cur: the document being saved
7134 * @encoding: the name of the encoding to use or NULL.
7135 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007136 *
7137 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007138 */
7139int
Daniel Veillardf012a642001-07-23 19:10:52 +00007140xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7141 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007142 xmlOutputBufferPtr buf;
7143 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007144 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007145 int ret;
7146
Daniel Veillardfb25a512002-01-13 20:32:08 +00007147 if (encoding == NULL)
7148 encoding = (const char *) cur->encoding;
7149
Owen Taylor3473f882001-02-23 17:55:21 +00007150 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007151
7152 enc = xmlParseCharEncoding(encoding);
7153 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7154 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007155 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007156 return(-1);
7157 }
7158 if (enc != XML_CHAR_ENCODING_UTF8) {
7159 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007160 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007161 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007162 }
7163 }
7164
Daniel Veillardf012a642001-07-23 19:10:52 +00007165#ifdef HAVE_ZLIB_H
7166 if (cur->compression < 0) cur->compression = xmlCompressMode;
7167#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007168 /*
7169 * save the content to a temp buffer.
7170 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007171 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007172 if (buf == NULL) return(-1);
7173
Daniel Veillardf012a642001-07-23 19:10:52 +00007174 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007175
7176 ret = xmlOutputBufferClose(buf);
7177 return(ret);
7178}
7179
Daniel Veillardf012a642001-07-23 19:10:52 +00007180
7181/**
7182 * xmlSaveFileEnc:
7183 * @filename: the filename (or URL)
7184 * @cur: the document
7185 * @encoding: the name of an encoding (or NULL)
7186 *
7187 * Dump an XML document, converting it to the given encoding
7188 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007189 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007190 */
7191int
7192xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7193 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7194}
7195
Owen Taylor3473f882001-02-23 17:55:21 +00007196/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007197 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007198 * @filename: the filename (or URL)
7199 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007200 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007201 *
7202 * Dump an XML document to a file. Will use compression if
7203 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007204 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007205 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007206 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007207 */
7208int
Daniel Veillard67fee942001-04-26 18:59:03 +00007209xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007210 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007211}
7212
Daniel Veillard67fee942001-04-26 18:59:03 +00007213/**
7214 * xmlSaveFile:
7215 * @filename: the filename (or URL)
7216 * @cur: the document
7217 *
7218 * Dump an XML document to a file. Will use compression if
7219 * compiled in and enabled. If @filename is "-" the stdout file is
7220 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007221 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007222 */
7223int
7224xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007225 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007226}
7227